@procedures/mark 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/repl.d.ts CHANGED
@@ -7,6 +7,8 @@
7
7
  export interface ReplOptions {
8
8
  /** Verbose output */
9
9
  verbose?: boolean | undefined;
10
+ /** The folder that confines each path of the `fs.*` procedures (`--fs-root`). */
11
+ fsRoot?: string | undefined;
10
12
  }
11
13
  /**
12
14
  * Start the interactive REPL
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBnE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B;IAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CActD;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAC1C,MAAM,GAAE,MAAM,IAAe,GAC5B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAmChD"}
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBnE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B;IAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CActD;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAC1C,MAAM,GAAE,MAAM,IAAe,GAC5B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAmChD"}
package/dist/repl.js CHANGED
@@ -14,7 +14,7 @@ export async function startRepl(options) {
14
14
  const { verbose = false } = options;
15
15
  // One-time initialization (same as CLI startup)
16
16
  const spinner = print.spin("Loading procedures...");
17
- const ctx = await initCli(verbose);
17
+ const ctx = await initCli(verbose, options.fsRoot);
18
18
  spinner.succeed(`Ready (${ctx.procedures.length} procedures)`);
19
19
  print.info("Type any command (without 'mark' prefix). Ctrl+C to exit.\n");
20
20
  const reader = lineReader(process.stdin, process.stdout);
package/dist/repl.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
@@ -3,13 +3,21 @@
3
3
  *
4
4
  * Runs the CLI as a persistent server, exposing all ecosystem procedures
5
5
  * via HTTP. The server has the registry of mark (the module of each package, roadmap 3.1) and
6
- * the host policy of the core (roadmap 2.3): the token in the lockfile.
6
+ * the host policy of the core (roadmap 2.3): the token in the lockfile, and the topics of
7
+ * `--events`. With `--fs-root`, the `fs.*` procedures confine each path to the root.
7
8
  */
8
9
  export interface ServerModeOptions {
9
10
  port: number;
10
11
  host?: string;
11
12
  transport?: "http" | "websocket" | "both";
12
13
  verbose?: boolean;
14
+ /**
15
+ * The topic patterns of the remote events (`--events`, `documentation/EVENTS.md`). Empty or no
16
+ * value: the server serves no topic, and each subscription gets `TOPIC_NOT_FOUND`.
17
+ */
18
+ events?: readonly string[] | undefined;
19
+ /** The folder that confines each path of the `fs.*` procedures (`--fs-root`). */
20
+ fsRoot?: string | undefined;
13
21
  }
14
22
  /**
15
23
  * Start CLI in server mode
@@ -1 +1 @@
1
- {"version":3,"file":"server-mode.d.ts","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA6CD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+F/E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,2CAA2C;AAC3C,eAAO,MAAM,iBAAiB,YAAI,MAAM,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAExE;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAM3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAUzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAWzD"}
1
+ {"version":3,"file":"server-mode.d.ts","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvC,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AA6CD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwG/E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,2CAA2C;AAC3C,eAAO,MAAM,iBAAiB,YAAI,MAAM,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAExE;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAM3E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAUzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAWzD"}
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Runs the CLI as a persistent server, exposing all ecosystem procedures
5
5
  * via HTTP. The server has the registry of mark (the module of each package, roadmap 3.1) and
6
- * the host policy of the core (roadmap 2.3): the token in the lockfile.
6
+ * the host policy of the core (roadmap 2.3): the token in the lockfile, and the topics of
7
+ * `--events`. With `--fs-root`, the `fs.*` procedures confine each path to the root.
7
8
  */
8
9
  import { print } from "./print.js";
9
10
  import { loadEcosystemRegistry } from "./ecosystem.js";
@@ -47,7 +48,7 @@ export async function startServerMode(options) {
47
48
  if (verbose) {
48
49
  print.info("Loading ecosystem procedures...");
49
50
  }
50
- const { registry } = await loadEcosystemRegistry(verbose);
51
+ const { registry, fsRoot } = await loadEcosystemRegistry(verbose, true, { fsRoot: options.fsRoot });
51
52
  // Build transport config
52
53
  const transports = buildTransports(options);
53
54
  // Every request must send this token. Only the lockfile (readable by this user) holds it.
@@ -60,14 +61,17 @@ export async function startServerMode(options) {
60
61
  print.warning("A WebSocket-only server takes no `mark` commands: `mark` sends its commands over HTTP.");
61
62
  }
62
63
  // The host policy of the core (roadmap 2.3): the token of each transport. The server of mark
63
- // serves every procedure of the workspace to its one user, so it has no expose list.
64
+ // serves every procedure of the workspace to its one user, so it has no expose list. It always
65
+ // serves events.subscribe (EVENTS.md): the topic rule is the --events patterns, else empty.
66
+ // The bus is the global bus, which is also the ctx.bus of the procedures.
67
+ const events = [...(options.events ?? [])];
64
68
  const { hostPolicy } = await import("@procedures/client");
65
69
  const { createPeer } = await import("@procedures/peer");
66
70
  const peer = await createPeer({
67
71
  id: `peer-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
68
72
  transports,
69
73
  registry,
70
- policy: hostPolicy({ token }),
74
+ policy: hostPolicy({ token, events: { topics: events } }),
71
75
  });
72
76
  await peer.start();
73
77
  const result = {
@@ -87,6 +91,8 @@ export async function startServerMode(options) {
87
91
  cwd: process.cwd(),
88
92
  build: currentBuild(),
89
93
  peerId: result.serverId,
94
+ // A client uses this server only with the same --fs-root (or none)
95
+ ...(fsRoot !== undefined ? { fsRoot } : {}),
90
96
  });
91
97
  print.success("\nCLI Server running!");
92
98
  print.info(` PID: ${process.pid}`);
@@ -97,6 +103,10 @@ export async function startServerMode(options) {
97
103
  for (const endpoint of result.endpoints) {
98
104
  print.info(` [${endpoint.type}] ${endpoint.address}`);
99
105
  }
106
+ print.info(events.length > 0 ? `\nEvent topics (events.subscribe): ${events.join(", ")}` : "\nEvent topics: none (--events adds them)");
107
+ if (fsRoot !== undefined) {
108
+ print.info(`File root: ${fsRoot} (fs.* refuses each path outside it)`);
109
+ }
100
110
  print.info("\nPress Ctrl+C to stop.");
101
111
  // Handle shutdown: the peer stops (its requests end and its ports close) before the process
102
112
  // exits, with a limit of 10 seconds. A second signal exits at once. Before, the process exited
@@ -1 +1 @@
1
- {"version":3,"file":"server-mode.js","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-mode.js","sourceRoot":"","sources":["../src/server-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpG,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAsB7C;;GAEG;AACH,SAAS,eAAe,CAAC,OAA0B;IACjD,MAAM,UAAU,GAMX,EAAE,CAAC;IAER,0FAA0F;IAC1F,+FAA+F;IAC/F,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,EAAE,SAAS,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IAEjE,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACjD,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,MAAM;YACZ,IAAI;YACJ,IAAI;YACJ,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,SAAS,KAAK,WAAW,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACtD,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;YAC5C,IAAI;YACJ,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA0B;IAC9D,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAEjD,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAE1C,4FAA4F;IAC5F,iDAAiD;IACjD,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,qBAAqB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpG,yBAAyB;IACzB,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAE5C,0FAA0F;IAC1F,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IACzC,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,OAAO,CAAC,yBAAyB,IAAI,gEAAgE,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,OAAO,CAAC,SAAS,KAAK,WAAW,EAAE,CAAC;QACtC,KAAK,CAAC,OAAO,CAAC,wFAAwF,CAAC,CAAC;IAC1G,CAAC;IAED,6FAA6F;IAC7F,+FAA+F;IAC/F,4FAA4F;IAC5F,0EAA0E;IAC1E,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC1D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC;QAC5B,EAAE,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QAClE,UAAU;QACV,QAAQ;QACR,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;KAC1D,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACnB,MAAM,MAAM,GAAuB;QACjC,QAAQ,EAAE,IAAI,CAAC,EAAE;QACjB,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE;QAC9B,cAAc,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,cAAc;KAChD,CAAC;IAEF,4FAA4F;IAC5F,uFAAuF;IACvF,MAAM,aAAa,CAAC;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,IAAI;QACJ,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;QACtC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,oBAAoB,IAAI,MAAM;QACxE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,KAAK,EAAE,YAAY,EAAE;QACrB,MAAM,EAAE,MAAM,CAAC,QAAQ;QACvB,mEAAmE;QACnE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5C,CAAC,CAAC;IAEH,KAAK,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACvC,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,eAAe,eAAe,EAAE,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,sCAAsC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC;IACxI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,cAAc,MAAM,sCAAsC,CAAC,CAAC;IACzE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAEtC,4FAA4F;IAC5F,+FAA+F;IAC/F,+BAA+B;IAC/B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACzB,IAAI,QAAQ;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,QAAQ,GAAG,IAAI,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACnC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACxD,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,CAAC;YACH,0DAA0D;YAC1D,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,KAAK,CAAC,oCAAoC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE/B,yBAAyB;IACzB,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE;QACrB,yCAAyC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,mCAAmC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAU,CAAC;AAExE;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IACnE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,uBAAuB,KAAK,mBAAmB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,qFAAqF;IACrF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,SAAS,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC5F,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACpC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@procedures/mark",
4
- "version": "0.4.0",
4
+ "version": "0.6.0",
5
5
  "description": "mark: one CLI for every procedure package. It finds the procedures, parses flags by their Zod types, runs local or through a fast warm server, and asks for missing arguments.",
6
6
  "keywords": [
7
7
  "cli",
@@ -52,16 +52,16 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@clack/prompts": "^0.7.0",
55
- "@procedures/cli-run": "0.4.0",
56
- "@procedures/client": "0.4.0",
57
- "@procedures/lib": "0.4.0",
58
- "@procedures/mcp-dev-tools": "0.4.0",
59
- "@procedures/peer": "0.4.0",
60
- "@procedures/pnpm": "0.4.0",
61
- "@procedures/procedure": "0.4.0",
62
- "@procedures/server": "0.4.0",
63
- "@procedures/shell": "0.4.0",
64
- "@procedures/vitest": "0.4.0",
55
+ "@procedures/cli-run": "0.6.0",
56
+ "@procedures/client": "0.6.0",
57
+ "@procedures/lib": "0.6.0",
58
+ "@procedures/mcp-dev-tools": "0.6.0",
59
+ "@procedures/peer": "0.6.0",
60
+ "@procedures/pnpm": "0.6.0",
61
+ "@procedures/procedure": "0.6.0",
62
+ "@procedures/server": "0.6.0",
63
+ "@procedures/shell": "0.6.0",
64
+ "@procedures/vitest": "0.6.0",
65
65
  "chalk": "^5.3.0",
66
66
  "cli-table3": "^0.6.5",
67
67
  "ora": "^8.0.0",
@@ -70,44 +70,44 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@mark1russell7/cue": "^1.0.0",
73
- "@procedures/archive": "0.4.0",
74
- "@procedures/bundle-assistant": "0.4.0",
75
- "@procedures/bundle-dev": "0.4.0",
76
- "@procedures/bundle-mcp": "0.4.0",
77
- "@procedures/claude-cli": "0.4.0",
78
- "@procedures/compiler": "0.4.0",
79
- "@procedures/cue": "0.4.0",
80
- "@procedures/dag": "0.4.0",
81
- "@procedures/docker": "0.4.0",
82
- "@procedures/env": "0.4.0",
83
- "@procedures/exif": "0.4.0",
84
- "@procedures/fs": "0.4.0",
85
- "@procedures/geo": "0.4.0",
86
- "@procedures/gh": "0.4.0",
87
- "@procedures/git": "0.4.0",
88
- "@procedures/http": "0.4.0",
89
- "@procedures/ics": "0.4.0",
90
- "@procedures/ios-backup": "0.4.0",
91
- "@procedures/json": "0.4.0",
92
- "@procedures/llm": "0.4.0",
93
- "@procedures/mail": "0.4.0",
94
- "@procedures/mongo": "0.4.0",
95
- "@procedures/node": "0.4.0",
96
- "@procedures/notify": "0.4.0",
97
- "@procedures/npm": "0.4.0",
98
- "@procedures/pdf": "0.4.0",
99
- "@procedures/privacy-scan": "0.4.0",
100
- "@procedures/restic": "0.4.0",
101
- "@procedures/s3": "0.4.0",
102
- "@procedures/schedule": "0.4.0",
103
- "@procedures/snapshot": "0.4.0",
104
- "@procedures/splay": "0.4.0",
105
- "@procedures/sqlite": "0.4.0",
106
- "@procedures/store": "0.4.0",
107
- "@procedures/systems": "0.4.0",
108
- "@procedures/tailscale": "0.4.0",
109
- "@procedures/vite": "0.4.0",
110
- "@procedures/weather": "0.4.0",
73
+ "@procedures/archive": "0.6.0",
74
+ "@procedures/bundle-assistant": "0.6.0",
75
+ "@procedures/bundle-dev": "0.6.0",
76
+ "@procedures/bundle-mcp": "0.6.0",
77
+ "@procedures/claude-cli": "0.6.0",
78
+ "@procedures/compiler": "0.6.0",
79
+ "@procedures/cue": "0.6.0",
80
+ "@procedures/dag": "0.6.0",
81
+ "@procedures/docker": "0.6.0",
82
+ "@procedures/env": "0.6.0",
83
+ "@procedures/exif": "0.6.0",
84
+ "@procedures/fs": "0.6.0",
85
+ "@procedures/geo": "0.6.0",
86
+ "@procedures/gh": "0.6.0",
87
+ "@procedures/git": "0.6.0",
88
+ "@procedures/http": "0.6.0",
89
+ "@procedures/ics": "0.6.0",
90
+ "@procedures/ios-backup": "0.6.0",
91
+ "@procedures/json": "0.6.0",
92
+ "@procedures/llm": "0.6.0",
93
+ "@procedures/mail": "0.6.0",
94
+ "@procedures/mongo": "0.6.0",
95
+ "@procedures/node": "0.6.0",
96
+ "@procedures/notify": "0.6.0",
97
+ "@procedures/npm": "0.6.0",
98
+ "@procedures/pdf": "0.6.0",
99
+ "@procedures/privacy-scan": "0.6.0",
100
+ "@procedures/restic": "0.6.0",
101
+ "@procedures/s3": "0.6.0",
102
+ "@procedures/schedule": "0.6.0",
103
+ "@procedures/snapshot": "0.6.0",
104
+ "@procedures/splay": "0.6.0",
105
+ "@procedures/sqlite": "0.6.0",
106
+ "@procedures/store": "0.6.0",
107
+ "@procedures/systems": "0.6.0",
108
+ "@procedures/tailscale": "0.6.0",
109
+ "@procedures/vite": "0.6.0",
110
+ "@procedures/weather": "0.6.0",
111
111
  "@types/node": "^22.0.0",
112
112
  "fast-check": "^4.10.2",
113
113
  "typescript": "^7.0.2",
package/src/args.ts CHANGED
@@ -11,6 +11,8 @@
11
11
  * - Each value is converted by the type of its field: a string field keeps its text.
12
12
  * - A repeated array flag collects its values. A repeated record flag (`--env A=1 --env B=2`) merges.
13
13
  * - A boolean flag takes `true`/`false` after it, or `--flag=false`, or `--no-flag`.
14
+ * - A repeated global flag with a value keeps the last value. A repeatable one (`--events`)
15
+ * collects its values, separated by commas.
14
16
  * - A negative number is a value, not a flag. `--` ends the flags.
15
17
  * - The positional fields take the arguments in order. A last array field takes the rest.
16
18
  * An argument that no field takes is an error.
@@ -37,11 +39,13 @@ export type GlobalName =
37
39
  | "local"
38
40
  | "json"
39
41
  | "no-input"
42
+ | "fs-root"
40
43
  | "interactive"
41
44
  | "server"
42
45
  | "port"
43
46
  | "host"
44
- | "transport";
47
+ | "transport"
48
+ | "events";
45
49
 
46
50
  /** The global flags that the command line gives: true for a flag, text for a flag with a value */
47
51
  export type Globals = Partial<Record<GlobalName, string | boolean>>;
@@ -183,7 +187,9 @@ function readGlobal(
183
187
  if (value === undefined) {
184
188
  return `${label} needs a value`;
185
189
  }
186
- globals[name] = value;
190
+ // A repeatable flag (--events) collects its values, separated by commas
191
+ const previous = globals[name];
192
+ globals[name] = flag.repeatable && typeof previous === "string" ? `${previous},${value}` : value;
187
193
  return undefined;
188
194
  }
189
195
  if (inline !== undefined && inline !== "true" && inline !== "false") {
package/src/cli.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  import { print } from "./print.js";
10
10
  import type { Method, AnyProcedure } from "@procedures/client";
11
11
  import { readFileSync, realpathSync } from "node:fs";
12
- import { dirname } from "node:path";
12
+ import { dirname, resolve } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
  import { fieldsOf, generateHelp, resultFieldsOf, type CLIMeta, type CommandLike } from "./parse.js";
15
15
  import { readFreshManifest, writeManifest, type ManifestCommand } from "./manifest.js";
@@ -139,9 +139,25 @@ function showRootHelp(procedures: readonly CommandLike[]): void {
139
139
  }
140
140
 
141
141
  print.info("Run 'mark <command> --help' for more information.");
142
- print.info("Hosts: 'mark serve [--procedures pkgs] [--port N] [--expose patterns]' (the procedure server),");
142
+ print.info("Hosts: 'mark serve [--procedures pkgs] [--port N] [--expose patterns] [--events topics]' (the procedure server),");
143
143
  print.info(" 'mark mcp' (the dev-tools MCP server over stdio).");
144
- print.info("Modes: 'mark --server [--port N] [--host H] [--transport http|websocket|both]' and 'mark -i' (the REPL).");
144
+ print.info("Modes: 'mark --server [--port N] [--host H] [--transport http|websocket|both] [--events topics]' and 'mark -i' (the REPL).");
145
+ print.info("Root: 'mark --fs-root <folder> <command>' confines each path of fs.* to the folder, also in each mode and host.");
146
+ }
147
+
148
+ /** The global flags that only `--server` takes. */
149
+ const SERVER_OPTIONS = ["port", "host", "transport", "events"] as const;
150
+
151
+ /** True when the global flags give an option of `--server`. */
152
+ function hasServerOption(globals: Readonly<Record<string, unknown>>): boolean {
153
+ return SERVER_OPTIONS.some((name) => globals[name] !== undefined);
154
+ }
155
+
156
+ /** The topic patterns of `--events`, checked as `mark serve` checks them. */
157
+ async function eventPatterns(value: string | boolean | undefined): Promise<string[]> {
158
+ if (value === undefined) return [];
159
+ const { parseTopicPatterns } = await import("@procedures/server");
160
+ return parseTopicPatterns(String(value));
145
161
  }
146
162
 
147
163
  /**
@@ -151,6 +167,8 @@ export interface CliContext {
151
167
  client: InstanceType<typeof import("@procedures/client").Client>;
152
168
  procedures: AnyProcedure[];
153
169
  verbose: boolean;
170
+ /** The absolute path of the root of the `fs.*` procedures (`--fs-root`), or undefined. */
171
+ fsRoot?: string | undefined;
154
172
  }
155
173
 
156
174
  /**
@@ -160,6 +178,8 @@ export interface CliContext {
160
178
  export interface ManifestContext {
161
179
  commands: readonly ManifestCommand[];
162
180
  verbose: boolean;
181
+ /** The absolute path of the root that `load()` gives to the `fs.*` procedures, or undefined. */
182
+ fsRoot?: string | undefined;
163
183
  load: () => Promise<CliContext>;
164
184
  }
165
185
 
@@ -186,14 +206,16 @@ function interruptSignal(): { signal: AbortSignal; release: () => void } {
186
206
 
187
207
  /**
188
208
  * Initialize the CLI context (load ecosystem, create client)
189
- * This is the expensive part (~4s). Call once, reuse many times.
209
+ * This is the expensive part (~4s). Call once, reuse many times. With `fsRoot` (`--fs-root`),
210
+ * the `fs.*` procedures confine each path to the root, also in the nested calls.
190
211
  */
191
- export async function initCli(verbose = false): Promise<CliContext> {
212
+ export async function initCli(verbose = false, fsRoot?: string): Promise<CliContext> {
192
213
  const clientModule = await import("@procedures/client");
193
214
  const { Client, LocalTransport } = clientModule;
194
215
 
195
216
  // A registry of its own, from the module of each package (roadmap 3.1): not the global one
196
- const { registry } = await loadEcosystemRegistry(verbose);
217
+ const ecosystem = await loadEcosystemRegistry(verbose, true, { fsRoot });
218
+ const { registry } = ecosystem;
197
219
 
198
220
  // The transport runs each procedure of the registry through invokeProcedure() (ARCHITECTURE-PROPOSALS P1).
199
221
  // useRegistry(): exec() of a program (--json) uses the same registry.
@@ -202,7 +224,7 @@ export async function initCli(verbose = false): Promise<CliContext> {
202
224
 
203
225
  const procedures = registry.getAll();
204
226
 
205
- return { client, procedures, verbose };
227
+ return { client, procedures, verbose, ...(ecosystem.fsRoot !== undefined ? { fsRoot: ecosystem.fsRoot } : {}) };
206
228
  }
207
229
 
208
230
  /**
@@ -254,8 +276,16 @@ export async function executeArgs(
254
276
  fail("--server and -i start a mode of mark: give them alone, before any command.");
255
277
  return;
256
278
  }
257
- if (globals.port !== undefined || globals.host !== undefined || globals.transport !== undefined) {
258
- fail("--port, --host and --transport are options of --server.");
279
+ if (hasServerOption(globals)) {
280
+ fail("--port, --host, --transport and --events are options of --server.");
281
+ return;
282
+ }
283
+ // The root applies to the whole run: the procedures load with it, and a warm server must have it
284
+ if (globals["fs-root"] !== undefined && resolve(String(globals["fs-root"])) !== ctx.fsRoot) {
285
+ fail(
286
+ `--fs-root ${String(globals["fs-root"])} does not apply here: give it before the command (mark --fs-root <folder> <command>).`,
287
+ ctx.fsRoot === undefined ? undefined : `This run has the root ${ctx.fsRoot}.`
288
+ );
259
289
  return;
260
290
  }
261
291
 
@@ -371,7 +401,7 @@ export async function executeArgs(
371
401
 
372
402
  // Try client mode: connect to running server if available (unless --local)
373
403
  if (!globals.local) {
374
- const clientResult = await tryClientMode(path, validated, printItem);
404
+ const clientResult = await tryClientMode(path, validated, printItem, ctx.fsRoot);
375
405
  if (clientResult !== null) {
376
406
  if (clientResult.success) {
377
407
  if (!clientResult.printed) {
@@ -455,18 +485,23 @@ Options:
455
485
  --http <port> Serve over Streamable HTTP on this port, not over stdio (MCP_HTTP_PORT)
456
486
  --host <host> The address of --http (default: 127.0.0.1, only this computer)
457
487
  --token <token> A secret that each HTTP request must send as a bearer token
488
+ --fs-root <folder> Confine each path of fs.* to this folder, also the nested fs calls
489
+ of the tools (default: MCP_FS_ROOT, or no root). The tools stay the same.
458
490
  --debug Write debug lines to stderr
459
491
  -h, --help Show this help
460
492
 
493
+ The MCP server serves no remote events: MCP carries only the tool calls.
461
494
  \`mark mcp <procedure>\` runs an mcp.* procedure instead (mark mcp serve, mark mcp listTools).`;
462
495
 
463
496
  /**
464
497
  * Start the dev-tools MCP server (`mark mcp`). stdout carries the protocol: this function
465
498
  * writes nothing to stdout, and the server sends console.log to stderr.
466
499
  */
467
- async function startMcp(args: string[]): Promise<void> {
500
+ async function startMcp(args: string[], fsRoot?: string): Promise<void> {
468
501
  const { loadConfig, startDevToolsServer } = await import("@procedures/mcp-dev-tools");
469
502
  const config = loadConfig();
503
+ // `mark --fs-root <folder> mcp` replaces MCP_FS_ROOT, and `mark mcp --fs-root` replaces both
504
+ if (fsRoot !== undefined) config.fsRoot = fsRoot;
470
505
  for (let i = 0; i < args.length; i++) {
471
506
  const arg = args[i]!;
472
507
  const eq = arg.indexOf("=");
@@ -496,6 +531,8 @@ async function startMcp(args: string[]): Promise<void> {
496
531
  config.http = { port: config.http?.port ?? 3003, ...config.http, host: value() };
497
532
  } else if (name === "--token") {
498
533
  config.http = { port: config.http?.port ?? 3003, ...config.http, token: value() };
534
+ } else if (name === "--fs-root") {
535
+ config.fsRoot = value();
499
536
  } else if (name === "--debug") {
500
537
  config.debug = true;
501
538
  } else {
@@ -529,6 +566,9 @@ async function run(argv: string[]): Promise<void> {
529
566
  return;
530
567
  }
531
568
 
569
+ // --fs-root (roadmap R33): the root of the fs.* procedures for each mode and host of this run
570
+ const fsRoot = globals["fs-root"] === undefined ? undefined : resolve(String(globals["fs-root"]));
571
+
532
572
  // Handle --server flag: start server mode
533
573
  if (globals.server) {
534
574
  if (leading.rest.length > 0) {
@@ -539,7 +579,13 @@ async function run(argv: string[]): Promise<void> {
539
579
  // Loopback unless --host says otherwise (deep dive CLI-1)
540
580
  const host = globals.host === undefined ? "127.0.0.1" : String(globals.host);
541
581
  const transport = globals.transport === undefined ? "http" : parseTransport(String(globals.transport));
542
- await startServerMode({ port, host, transport, verbose });
582
+ const events = await eventPatterns(globals.events);
583
+ await startServerMode({ port, host, transport, verbose, events, ...(fsRoot !== undefined ? { fsRoot } : {}) });
584
+ return;
585
+ }
586
+ // Before, `mark --port 4000 serve` ignored --port without a word
587
+ if (hasServerOption(globals)) {
588
+ fail("--port, --host, --transport and --events are options of --server.", "For mark serve, give them after serve.");
543
589
  return;
544
590
  }
545
591
 
@@ -549,7 +595,7 @@ async function run(argv: string[]): Promise<void> {
549
595
  fail(`-i takes no command: ${leading.rest.join(" ")}`);
550
596
  return;
551
597
  }
552
- await startRepl({ verbose });
598
+ await startRepl({ verbose, fsRoot });
553
599
  return;
554
600
  }
555
601
 
@@ -562,12 +608,14 @@ async function run(argv: string[]): Promise<void> {
562
608
  // A --procedures package resolves from the current folder, then from mark, which depends on
563
609
  // every procedure package of the workspace
564
610
  const markDir = dirname(dirname(fileURLToPath(import.meta.url)));
565
- await runServer(commandArgs, { resolveFrom: [process.cwd(), markDir] });
611
+ // `mark --fs-root <folder> serve`: the root goes first, so a --fs-root after serve wins
612
+ const serveArgs = fsRoot === undefined ? commandArgs : ["--fs-root", fsRoot, ...commandArgs];
613
+ await runServer(serveArgs, { resolveFrom: [process.cwd(), markDir] });
566
614
  return;
567
615
  }
568
616
  // `mark mcp` and `mark mcp --option value`: the server. `mark mcp <procedure>`: an mcp.* command.
569
617
  if (command === "mcp" && (commandArgs.length === 0 || commandArgs[0]!.startsWith("-"))) {
570
- await startMcp(commandArgs);
618
+ await startMcp(commandArgs, fsRoot);
571
619
  return;
572
620
  }
573
621
 
@@ -575,13 +623,13 @@ async function run(argv: string[]): Promise<void> {
575
623
  // server do not load them (roadmap 1.3)
576
624
  const manifest = readFreshManifest();
577
625
  if (manifest) {
578
- await executeArgs(argv, { commands: manifest.commands, verbose, load: () => initCli(verbose) });
626
+ await executeArgs(argv, { commands: manifest.commands, verbose, fsRoot, load: () => initCli(verbose, fsRoot) });
579
627
  return;
580
628
  }
581
629
 
582
630
  // No manifest, or a stale one (a package was built again): load the procedures as before, and
583
631
  // write the manifest for the next run. A failure to write costs only time.
584
- const ctx = await initCli(verbose);
632
+ const ctx = await initCli(verbose, fsRoot);
585
633
  try {
586
634
  await writeManifest(ctx.procedures);
587
635
  } catch (error) {
@@ -23,7 +23,8 @@ interface ClientModeResult {
23
23
  export async function tryClientMode(
24
24
  path: string[],
25
25
  input: unknown,
26
- onItem?: (item: unknown) => void
26
+ onItem?: (item: unknown) => void,
27
+ fsRoot?: string
27
28
  ): Promise<ClientModeResult | null> {
28
29
  // A running server of this build, started in this folder, that answers as the peer of its
29
30
  // lockfile and has a token. Otherwise the CLI runs the command itself. (Before, any server
@@ -34,7 +35,8 @@ export async function tryClientMode(
34
35
  if (path[0] === "server") {
35
36
  return null;
36
37
  }
37
- const lockfile = await findServer({ cwd: process.cwd(), build: currentBuild() });
38
+ // The server must have the same fs root (--fs-root), or none when this run has none
39
+ const lockfile = await findServer({ cwd: process.cwd(), build: currentBuild(), fsRoot });
38
40
  // mark sends its commands over HTTP: a WebSocket-only server cannot take them
39
41
  if (!lockfile?.token || lockfile.transport === "websocket") {
40
42
  return null;
package/src/ecosystem.ts CHANGED
@@ -209,6 +209,36 @@ const allCoreModule: ProcedureModule = defineModule("@procedures/client (all cor
209
209
  export interface EcosystemRegistry {
210
210
  registry: ProcedureRegistry;
211
211
  loaded: string[];
212
+ /** The absolute path of the root of the `fs.*` procedures (`--fs-root`), or undefined. */
213
+ fsRoot?: string | undefined;
214
+ }
215
+
216
+ /** The options of `loadEcosystemRegistry()`. */
217
+ export interface EcosystemOptions {
218
+ /**
219
+ * The folder that confines each path of the `fs.*` procedures (`--fs-root`, roadmap R33). The
220
+ * nested `fs.*` calls of the other procedures are confined too.
221
+ */
222
+ fsRoot?: string | undefined;
223
+ }
224
+
225
+ /** The function of `@procedures/fs` that confines the `fs.*` procedures of a registry to a root. */
226
+ type ConfineFs = (registry: ProcedureRegistry, root: string) => { root: string; procedures: string[] };
227
+
228
+ /**
229
+ * This function confines the `fs.*` procedures of the registry to a root, with
230
+ * `confineFsProcedures()` of the workspace package `@procedures/fs`. Without that package, it
231
+ * throws: a root that does not apply is an error, not a silent no-op.
232
+ */
233
+ async function confineFs(registry: ProcedureRegistry, root: string, discovered: readonly DiscoveredPackage[]): Promise<string> {
234
+ const fsPackage = discovered.find((pkg) => pkg.name === "@procedures/fs");
235
+ const file = fsPackage?.modulePath ? path.join(fsPackage.path, fsPackage.modulePath) : undefined;
236
+ if (!file || !fs.existsSync(file)) {
237
+ throw new Error("--fs-root needs the package @procedures/fs of the workspace: build packages/client-fs");
238
+ }
239
+ const { confineFsProcedures } = (await import(pathToFileURL(file).href)) as { confineFsProcedures?: ConfineFs };
240
+ if (typeof confineFsProcedures !== "function") throw new Error("--fs-root needs a build of @procedures/fs with confineFsProcedures");
241
+ return confineFsProcedures(registry, root).root;
212
242
  }
213
243
 
214
244
  /**
@@ -235,12 +265,14 @@ async function moduleOfPackage(pkg: DiscoveredPackage): Promise<ProcedureModule
235
265
  * The registry of `mark` (roadmap 3.1): a registry of its own, built from the module of each
236
266
  * workspace package that declares `client.procedures`, with all the core procedures. The global
237
267
  * registry does not change for a package with a module entry. A package that fails to load gives
238
- * one warning line on stderr, as with `loadEcosystemProcedures()`.
268
+ * one warning line on stderr, as with `loadEcosystemProcedures()`. With `options.fsRoot`, the
269
+ * `fs.*` procedures confine each path to the root.
239
270
  */
240
- export async function loadEcosystemRegistry(verbose = false, warn = true): Promise<EcosystemRegistry> {
271
+ export async function loadEcosystemRegistry(verbose = false, warn = true, options: EcosystemOptions = {}): Promise<EcosystemRegistry> {
241
272
  const registry = createRegistry(allCoreModule);
242
273
  const loaded: string[] = [];
243
- for (const pkg of discoverFromEcosystem()) {
274
+ const discovered = discoverFromEcosystem();
275
+ for (const pkg of discovered) {
244
276
  try {
245
277
  const module = await moduleOfPackage(pkg);
246
278
  if (!module) {
@@ -256,5 +288,8 @@ export async function loadEcosystemRegistry(verbose = false, warn = true): Promi
256
288
  if (verbose && error instanceof Error && error.stack) console.warn(error.stack);
257
289
  }
258
290
  }
259
- return { registry, loaded };
291
+ if (options.fsRoot === undefined) return { registry, loaded };
292
+ // After the last package: each fs.* procedure of the registry gets the handler of the root
293
+ const fsRoot = await confineFs(registry, options.fsRoot, discovered);
294
+ return { registry, loaded, fsRoot };
260
295
  }
package/src/repl.ts CHANGED
@@ -12,6 +12,8 @@ import { initCli, executeArgs, type CliContext } from "./cli.js";
12
12
  export interface ReplOptions {
13
13
  /** Verbose output */
14
14
  verbose?: boolean | undefined;
15
+ /** The folder that confines each path of the `fs.*` procedures (`--fs-root`). */
16
+ fsRoot?: string | undefined;
15
17
  }
16
18
 
17
19
  /**
@@ -22,7 +24,7 @@ export async function startRepl(options: ReplOptions): Promise<void> {
22
24
 
23
25
  // One-time initialization (same as CLI startup)
24
26
  const spinner = print.spin("Loading procedures...");
25
- const ctx: CliContext = await initCli(verbose);
27
+ const ctx: CliContext = await initCli(verbose, options.fsRoot);
26
28
  spinner.succeed(`Ready (${ctx.procedures.length} procedures)`);
27
29
 
28
30
  print.info("Type any command (without 'mark' prefix). Ctrl+C to exit.\n");