|
| 1 | +import { resolve } from "node:path"; |
| 2 | +import { parseWorkspaceMounts } from "./workspace-mounts.ts"; |
1 | 3 | /** |
2 | 4 | * CLI — run an executable markdown document. |
3 | 5 | * |
@@ -320,6 +322,10 @@ const REPL_DESCRIPTION = "Run and reconstruct one XMD entry in an interactive te |
320 | 322 | * their entries is not the same choice as who their entries talk to. |
321 | 323 | */ |
322 | 324 | const replConfig = object({ |
| 325 | + mount: { |
| 326 | + description: "external SOURCE:TARGET directory; repeat for each explicit TARGET", |
| 327 | + ...field(z.array(z.string()), field.default([]), field.array()), |
| 328 | + }, |
323 | 329 | location: { |
324 | 330 | description: |
325 | 331 | "a location this REPL printed earlier — `xmd://repl/<execution>/<surface>...` — to reopen " + |
@@ -598,6 +604,8 @@ const REPL_HELP = [ |
598 | 604 | " Each one starts from the bindings the entries before it published, so a", |
599 | 605 | " later entry can read and revise what an earlier one left behind.", |
600 | 606 | "", |
| 607 | + " --mount SOURCE:TARGET adds an external directory at a required document path.", |
| 608 | + " Repeat it: --mount /work/manuals:/reference --mount /work/fixtures:/fixtures.", |
601 | 609 | " --include <directory> and --include=<directory> select component directories.", |
602 | 610 | " Repeat them in search order; explicit values replace the default list [components, .].", |
603 | 611 | " Relative directories resolve from the invocation working directory.", |
@@ -657,14 +665,15 @@ export interface ReplHostAssembly { |
657 | 665 | * silence would let them believe they got it. |
658 | 666 | */ |
659 | 667 | /** |
660 | | - * The four REPL options that carry a value, by the spelling a caller writes. |
| 668 | + * The five REPL options that carry a value, by the spelling a caller writes. |
661 | 669 | * |
662 | 670 | * Exported because the documentation check reads this command's own examples, |
663 | 671 | * and a token after one of these is that option's value rather than a location. |
664 | 672 | * A second roster beside this one would be a reader that disagreed with the |
665 | 673 | * command about what it had been handed. |
666 | 674 | */ |
667 | 675 | export const REPL_VALUES: readonly string[] = [ |
| 676 | + "--mount", |
668 | 677 | "--include", |
669 | 678 | "--agent-provider", |
670 | 679 | "--default-agent", |
@@ -722,7 +731,7 @@ export function replGrammarError( |
722 | 731 | return ( |
723 | 732 | `unrecognized option for xmd repl: ${name} — xmd repl takes one optional location, ` + |
724 | 733 | "the agent options --agent-provider, --default-agent, --approve-all, --approve-reads " + |
725 | | - "and --deny-all, --include for component directories, and --sidekick-agent for the Sidekick's own conversations" |
| 734 | + "and --deny-all, --include for component directories, --mount SOURCE:TARGET for workspace directories, and --sidekick-agent for the Sidekick's own conversations" |
726 | 735 | ); |
727 | 736 | } |
728 | 737 | if (positional.length > 1) { |
@@ -2943,6 +2952,13 @@ function* dispatch( |
2943 | 2952 | yield* exit(1); |
2944 | 2953 | break; |
2945 | 2954 | } |
| 2955 | + const mountCwd = yield* cwd(); |
| 2956 | + const mounts = parseWorkspaceMounts(command.config.mount, mountCwd, { resolve }); |
| 2957 | + if (!mounts.ok) { |
| 2958 | + console.error(mounts.error.message); |
| 2959 | + yield* exit(1); |
| 2960 | + break; |
| 2961 | + } |
2946 | 2962 | // The Agent configuration, settled before a terminal exists: mutual |
2947 | 2963 | // exclusion, an unknown provider and `DEFAULT_AGENT_NAME` precedence are |
2948 | 2964 | // all decided here, so an invocation nobody could run refuses without |
@@ -3015,6 +3031,7 @@ function* dispatch( |
3015 | 3031 | [testAgentChildDeclaration()], |
3016 | 3032 | ); |
3017 | 3033 | }, |
| 3034 | + mounts: mounts.value, |
3018 | 3035 | includes: command.config.include, |
3019 | 3036 | ...(command.config.sidekickAgent === undefined |
3020 | 3037 | ? {} |
|
0 commit comments