@agimon-ai/po-author 0.0.0-alpha.2 → 0.0.0-alpha.21

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.
Files changed (39) hide show
  1. package/LICENSE +149 -21
  2. package/README.md +5 -3
  3. package/dist/apiContracts.cjs +3 -3
  4. package/dist/apiContracts.cjs.map +1 -1
  5. package/dist/apiContracts.mjs +3 -3
  6. package/dist/apiContracts.mjs.map +1 -1
  7. package/dist/{authorFacade-BYvlm8Ff.cjs → authorFacade-BkIMF1lR.cjs} +2 -2
  8. package/dist/authorFacade-BkIMF1lR.cjs.map +1 -0
  9. package/dist/{authorFacade--Lc599Ft.mjs → authorFacade-CpLG3duk.mjs} +3 -3
  10. package/dist/authorFacade-CpLG3duk.mjs.map +1 -0
  11. package/dist/{authorFacade-89Eb2-sW.d.mts → authorFacade-DCTTx7EE.d.mts} +3 -3
  12. package/dist/{authorFacade-89Eb2-sW.d.mts.map → authorFacade-DCTTx7EE.d.mts.map} +1 -1
  13. package/dist/authorFacade.cjs +1 -1
  14. package/dist/authorFacade.d.mts +1 -1
  15. package/dist/authorFacade.mjs +1 -1
  16. package/dist/extensions/server.cjs +104 -40
  17. package/dist/extensions/server.cjs.map +1 -1
  18. package/dist/extensions/server.d.mts +2 -2
  19. package/dist/extensions/server.d.mts.map +1 -1
  20. package/dist/extensions/server.mjs +101 -37
  21. package/dist/extensions/server.mjs.map +1 -1
  22. package/dist/extensions/web.mjs +797 -385
  23. package/dist/extensions/web.mjs.map +1 -1
  24. package/dist/index.cjs +1 -1
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.mts +6 -6
  27. package/dist/index.d.mts.map +1 -1
  28. package/dist/index.mjs +1 -1
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/{structuredDocuments-B914GLxx.mjs → structuredDocuments-BAvFI8VH.mjs} +9 -7
  31. package/dist/structuredDocuments-BAvFI8VH.mjs.map +1 -0
  32. package/dist/{structuredDocuments-CNac1JmJ.cjs → structuredDocuments-OYXnnCrZ.cjs} +18 -10
  33. package/dist/structuredDocuments-OYXnnCrZ.cjs.map +1 -0
  34. package/package.json +18 -17
  35. package/src/prompts/po-use-author/SKILL.md +1 -1
  36. package/dist/authorFacade--Lc599Ft.mjs.map +0 -1
  37. package/dist/authorFacade-BYvlm8Ff.cjs.map +0 -1
  38. package/dist/structuredDocuments-B914GLxx.mjs.map +0 -1
  39. package/dist/structuredDocuments-CNac1JmJ.cjs.map +0 -1
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_structuredDocuments = require("../structuredDocuments-CNac1JmJ.cjs");
6
- const require_authorFacade = require("../authorFacade-BYvlm8Ff.cjs");
7
- let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
5
+ const require_structuredDocuments = require("../structuredDocuments-OYXnnCrZ.cjs");
6
+ const require_authorFacade = require("../authorFacade-BkIMF1lR.cjs");
7
+ let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
8
8
  let _agimon_ai_po_minor_mode = require("@agimon-ai/po-minor-mode");
9
9
  let node_crypto = require("node:crypto");
10
10
  let node_path = require("node:path");
@@ -13,23 +13,89 @@ let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile
13
13
  let hono = require("hono");
14
14
  let node_fs_promises = require("node:fs/promises");
15
15
  node_fs_promises = require_structuredDocuments.__toESM(node_fs_promises, 1);
16
+ let _agimon_ai_po_artifact_artifactFiles = require("@agimon-ai/po-artifact/artifactFiles");
16
17
  let _agimon_ai_po_core_web = require("@agimon-ai/po-core/web");
17
18
  //#region src/services/structuredDocuments/document.ts
18
19
  const AUTHOR_DOCUMENT_MAX_BYTES = 26214400;
19
- async function readDocument(cwd, requestedPath) {
20
- if (typeof requestedPath !== "string" || requestedPath.length === 0 || requestedPath.includes("\0") || node_path.default.isAbsolute(requestedPath)) throw new Error("A relative document path is required.");
20
+ function inside(root, candidate) {
21
+ const relative = node_path.default.relative(root, candidate);
22
+ return relative !== "" && relative !== ".." && !relative.startsWith(`..${node_path.default.sep}`) && !node_path.default.isAbsolute(relative);
23
+ }
24
+ /**
25
+ * The session artifact folder is the one place outside the working tree Author
26
+ * may read. It is named either `artifact:<relative>` or by the absolute path the
27
+ * agent's prompt gives; po-artifact's guarded open does the containment checks.
28
+ */
29
+ async function resolveArtifact(requestedPath, sessionId) {
30
+ const prefixed = requestedPath.startsWith(require_structuredDocuments.AUTHOR_ARTIFACT_PREFIX);
31
+ if (sessionId === void 0) {
32
+ if (prefixed) throw new require_structuredDocuments.DocumentRequestError("Artifacts need a session.", 400);
33
+ return;
34
+ }
35
+ const root = (0, _agimon_ai_po_artifact_artifactFiles.artifactRoot)(sessionId, process.env);
36
+ if (prefixed) return {
37
+ root,
38
+ relative: requestedPath.slice(require_structuredDocuments.AUTHOR_ARTIFACT_PREFIX.length)
39
+ };
40
+ if (!node_path.default.isAbsolute(requestedPath)) return void 0;
41
+ const base = [root, await node_fs_promises.default.realpath(root).catch(() => root)].find((candidate) => inside(candidate, requestedPath));
42
+ if (base === void 0) return void 0;
43
+ return {
44
+ root,
45
+ relative: node_path.default.relative(base, requestedPath).split(node_path.default.sep).join("/")
46
+ };
47
+ }
48
+ async function resolveDocument(cwd, requestedPath, sessionId) {
49
+ if (typeof requestedPath !== "string" || requestedPath.length === 0 || requestedPath.includes("\0")) throw new Error("A relative document path is required.");
50
+ const artifact = await resolveArtifact(requestedPath, sessionId);
51
+ if (artifact !== void 0) {
52
+ const realRoot = await node_fs_promises.default.realpath(artifact.root).catch(() => artifact.root);
53
+ return {
54
+ kind: "artifact",
55
+ path: `${require_structuredDocuments.AUTHOR_ARTIFACT_PREFIX}${artifact.relative}`,
56
+ realPath: node_path.default.join(realRoot, artifact.relative),
57
+ ...artifact
58
+ };
59
+ }
60
+ if (node_path.default.isAbsolute(requestedPath)) throw new Error("A relative document path, or a file in the session artifact folder, is required.");
21
61
  const root = await node_fs_promises.default.realpath(cwd);
22
62
  const candidate = node_path.default.resolve(root, requestedPath);
23
63
  if (candidate !== root && !candidate.startsWith(`${root}${node_path.default.sep}`)) throw new require_structuredDocuments.DocumentRequestError("Document path is outside the working directory.", 403);
24
64
  const realCandidate = await node_fs_promises.default.realpath(candidate);
25
65
  if (realCandidate !== root && !realCandidate.startsWith(`${root}${node_path.default.sep}`)) throw new require_structuredDocuments.DocumentRequestError("Document path is outside the working directory.", 403);
26
- if ((await node_fs_promises.default.stat(realCandidate)).size > 26214400) throw require_structuredDocuments.documentTooLarge(`Document exceeds the ${AUTHOR_DOCUMENT_MAX_BYTES} byte preview limit.`);
27
- return await node_fs_promises.default.readFile(realCandidate);
66
+ return {
67
+ kind: "workspace",
68
+ path: node_path.default.relative(root, realCandidate).split(node_path.default.sep).join("/"),
69
+ realPath: realCandidate
70
+ };
71
+ }
72
+ async function readArtifact(root, relative) {
73
+ let file;
74
+ try {
75
+ file = await (0, _agimon_ai_po_artifact_artifactFiles.openArtifact)(root, relative);
76
+ } catch (error) {
77
+ if (error instanceof _agimon_ai_po_artifact_artifactFiles.ArtifactAccessError) throw new require_structuredDocuments.DocumentRequestError(error.message, error.status);
78
+ throw error;
79
+ }
80
+ try {
81
+ if (file.stat.size > 26214400) throw require_structuredDocuments.documentTooLarge(`Document exceeds the ${AUTHOR_DOCUMENT_MAX_BYTES} byte preview limit.`);
82
+ return await (0, _agimon_ai_po_artifact_artifactFiles.readArtifactBytes)(file.handle, file.stat.size);
83
+ } finally {
84
+ await file.handle.close();
85
+ }
86
+ }
87
+ async function readSource(source) {
88
+ if (source.kind === "artifact") return await readArtifact(source.root, source.relative);
89
+ if ((await node_fs_promises.default.stat(source.realPath)).size > 26214400) throw require_structuredDocuments.documentTooLarge(`Document exceeds the ${AUTHOR_DOCUMENT_MAX_BYTES} byte preview limit.`);
90
+ return await node_fs_promises.default.readFile(source.realPath);
91
+ }
92
+ async function readDocument(cwd, requestedPath, sessionId) {
93
+ return await readSource(await resolveDocument(cwd, requestedPath, sessionId));
28
94
  }
29
95
  //#endregion
30
96
  //#region src/services/authorCanvasRegistry/index.ts
31
97
  const MAX_CANVASES = 32;
32
- function createAuthorCanvasRegistry(cwd, createBridge) {
98
+ function createAuthorCanvasRegistry(cwd, createBridge, sessionId) {
33
99
  const byAlias = /* @__PURE__ */ new Map();
34
100
  const byPath = /* @__PURE__ */ new Map();
35
101
  const select = (alias) => {
@@ -69,12 +135,10 @@ function createAuthorCanvasRegistry(cwd, createBridge) {
69
135
  async open(requestedPath, signal, requestedAlias) {
70
136
  signal?.throwIfAborted();
71
137
  if (requestedAlias !== void 0 && !require_structuredDocuments.AUTHOR_ALIAS_PATTERN.test(requestedAlias)) throw new require_structuredDocuments.AuthorBridgeError("Invalid Author canvas alias.", 400);
72
- const bytes = await readDocument(cwd, requestedPath);
138
+ const source = await resolveDocument(cwd, requestedPath, sessionId);
139
+ const bytes = await readSource(source);
73
140
  signal?.throwIfAborted();
74
- const root = await node_fs_promises.default.realpath(cwd);
75
- const realPath = await node_fs_promises.default.realpath(node_path.default.resolve(root, requestedPath));
76
- if (realPath !== root && !realPath.startsWith(`${root}${node_path.default.sep}`)) throw new require_structuredDocuments.AuthorBridgeError("Document path is outside the working directory.", 400);
77
- const canonicalPath = node_path.default.relative(root, realPath).split(node_path.default.sep).join("/");
141
+ const { realPath, path: canonicalPath } = source;
78
142
  const occupied = requestedAlias === void 0 ? void 0 : byAlias.get(requestedAlias);
79
143
  if (occupied !== void 0 && occupied.realPath !== realPath) throw new require_structuredDocuments.AuthorBridgeError(`Author canvas alias '${requestedAlias}' already names ${occupied.path}.`, 409);
80
144
  const existing = byPath.get(realPath);
@@ -89,8 +153,14 @@ function createAuthorCanvasRegistry(cwd, createBridge) {
89
153
  reused: true
90
154
  };
91
155
  }
92
- if (byAlias.size >= MAX_CANVASES) throw new require_structuredDocuments.AuthorBridgeError("Too many Author canvases in this conversation.", 409);
93
- const base = node_path.default.basename(canonicalPath).replace(/\.[^.]*$/u, "").toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^[^a-z]+/u, "canvas-").slice(0, 48) || "canvas";
156
+ if (byAlias.size >= MAX_CANVASES) {
157
+ const reusable = [...byAlias.values()].find((canvas) => canvas.closed);
158
+ if (reusable === void 0) throw new require_structuredDocuments.AuthorBridgeError("Too many Author canvases in this conversation.", 409);
159
+ reusable.bridge.close();
160
+ byAlias.delete(reusable.alias);
161
+ byPath.delete(reusable.realPath);
162
+ }
163
+ const base = node_path.default.basename(realPath).replace(/\.[^.]*$/u, "").toLowerCase().replace(/[^a-z0-9_-]+/gu, "-").replace(/^[^a-z]+/u, "canvas-").slice(0, 48) || "canvas";
94
164
  let alias = requestedAlias ?? base;
95
165
  for (let suffix = 2; byAlias.has(alias); suffix++) alias = `${base.slice(0, 56)}-${suffix}`;
96
166
  const canvas = {
@@ -157,14 +227,6 @@ function createAuthorCanvasRegistry(cwd, createBridge) {
157
227
  canvas.bridge.close();
158
228
  canvas.bridge = createBridge();
159
229
  },
160
- closeAll() {
161
- for (const canvas of byAlias.values()) {
162
- if (canvas.closed) continue;
163
- canvas.closed = true;
164
- canvas.bridge.close();
165
- canvas.bridge = createBridge();
166
- }
167
- },
168
230
  dispose() {
169
231
  for (const canvas of byAlias.values()) canvas.bridge.close();
170
232
  byAlias.clear();
@@ -399,7 +461,7 @@ function createAuthorDocumentApi(options = {}) {
399
461
  try {
400
462
  const body = await bodyOf(context.req.raw);
401
463
  if (body.format === void 0 && options.open !== void 0) return context.json(await options.open(body.path, context.req.raw.signal, body.alias));
402
- const bytes = await readDocument(cwd, body.path);
464
+ const bytes = await readDocument(cwd, body.path, options.sessionId);
403
465
  if (body.format === void 0) return context.json({
404
466
  path: body.path,
405
467
  byteLength: bytes.byteLength
@@ -412,7 +474,7 @@ function createAuthorDocumentApi(options = {}) {
412
474
  app.post(apiRoutes_default.documentsPreflight.path, async (context) => {
413
475
  try {
414
476
  const body = await bodyOf(context.req.raw);
415
- const bytes = await readDocument(cwd, body.path);
477
+ const bytes = await readDocument(cwd, body.path, options.sessionId);
416
478
  return context.json(await require_structuredDocuments.preflightStructuredDocument(requestFormat(body.format), bytes, requestOperations(body.operations), body.csvDialect));
417
479
  } catch (error) {
418
480
  return errorResponse(context, error);
@@ -422,7 +484,7 @@ function createAuthorDocumentApi(options = {}) {
422
484
  try {
423
485
  const body = await bodyOf(context.req.raw);
424
486
  if (typeof body.preflightDigest !== "string") throw new Error("A preflight report digest is required.");
425
- const bytes = await readDocument(cwd, body.path);
487
+ const bytes = await readDocument(cwd, body.path, options.sessionId);
426
488
  const serialized = await require_structuredDocuments.serializeStructuredDocument(requestFormat(body.format), bytes, requestOperations(body.operations), body.preflightDigest, body.csvDialect);
427
489
  return context.json({
428
490
  bytes: Buffer.from(serialized.bytes).toString("base64"),
@@ -453,7 +515,7 @@ const createBridge = () => require_structuredDocuments.createAuthorBridgeState({
453
515
  });
454
516
  function createAuthorApi(options = {}) {
455
517
  const app = new hono.Hono();
456
- const registry = options.registry ?? createAuthorCanvasRegistry(options.cwd ?? process.cwd(), createBridge);
518
+ const registry = options.registry ?? createAuthorCanvasRegistry(options.cwd ?? process.cwd(), createBridge, options.sessionId);
457
519
  app.get(apiRoutes_default.state.path, (context) => context.json({
458
520
  sessionId: options.sessionId ?? null,
459
521
  ...(options.readState ?? inactiveState)()
@@ -461,6 +523,7 @@ function createAuthorApi(options = {}) {
461
523
  app.route("/", createAuthorBridgeApi(registry));
462
524
  app.route("/", createAuthorDocumentApi({
463
525
  ...options.cwd === void 0 ? {} : { cwd: options.cwd },
526
+ ...options.sessionId === void 0 ? {} : { sessionId: options.sessionId },
464
527
  open: (path, signal, alias) => registry.open(path, signal, alias)
465
528
  }));
466
529
  return app;
@@ -469,7 +532,7 @@ const api = {
469
532
  basePath: API_BASE_PATH,
470
533
  start(context) {
471
534
  if (context.cwd === void 0) throw new Error("Author requires the session working directory.");
472
- const registry = createAuthorCanvasRegistry(context.cwd, createBridge);
535
+ const registry = createAuthorCanvasRegistry(context.cwd, createBridge, context.sessionId);
473
536
  const app = createAuthorApi({
474
537
  ...context.sessionId === void 0 ? {} : { sessionId: context.sessionId },
475
538
  cwd: context.cwd,
@@ -483,9 +546,8 @@ const api = {
483
546
  };
484
547
  /** The session API and tools share the same browser ownership and pending requests. */
485
548
  function createAuthorSessionApi(cwd, sessionId) {
486
- const registry = createAuthorCanvasRegistry(cwd, createBridge);
549
+ const registry = createAuthorCanvasRegistry(cwd, createBridge, sessionId);
487
550
  return {
488
- closeCanvases: () => registry.closeAll(),
489
551
  catalog: {
490
552
  open: (path, signal, alias) => registry.open(path, signal, alias),
491
553
  async describe(signal, alias) {
@@ -525,7 +587,6 @@ var root_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ ag
525
587
  key: "minor-mode",
526
588
  values: enabled ? [...modes, require_structuredDocuments.authorMinorMode.descriptor.id] : modes
527
589
  });
528
- if (!enabled) session?.closeCanvases();
529
590
  }
530
591
  }) : void 0;
531
592
  return {
@@ -710,7 +771,7 @@ var author_webmcp_server_default = (0, _agimon_ai_po_core_extensionFile.defineCh
710
771
  //#endregion
711
772
  //#region src/services/authorBridgeMethod/index.ts
712
773
  function createAuthorBridgeMethod(scope, host) {
713
- return (0, _agimon_ai_po_core_serverFacet.defineServerMethod)(require_authorFacade.authorBridgeMethod(scope), ({ sessionId, message }, caller) => {
774
+ return (0, _agimon_ai_po_core_serverPlugin.defineServerMethod)(require_authorFacade.authorBridgeMethod(scope), ({ sessionId, message }, caller) => {
714
775
  if (!caller.connectionId) throw new Error("Author bridge requires an authenticated browser connection.");
715
776
  if (!host.context.receiveChannel?.(sessionId, "author_webmcp", message, caller.connectionId)) throw new Error("Author bridge session is outside this mount.");
716
777
  return {};
@@ -752,7 +813,7 @@ var po_use_author_server_default = (0, _agimon_ai_po_core_extensionFile.defineRe
752
813
  },
753
814
  name: "po-use-author",
754
815
  kind: "skill",
755
- read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-author/SKILL.md")
816
+ read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-author/SKILL.md")
756
817
  });
757
818
  //#endregion
758
819
  //#region src/extensions/workspaces/sessions/(backend)/tool/describe-author-tools.server.ts
@@ -775,13 +836,16 @@ var use_author_tools_server_default = (0, _agimon_ai_po_core_extensionFile.defin
775
836
  //#endregion
776
837
  //#region generated/server.ts
777
838
  const at = (value, context) => typeof value === "function" ? value(context) : value;
839
+ /* v8 ignore next -- generated normalization branch */
840
+ const defined = (values) => values.filter((value) => value !== void 0);
778
841
  const via = (identity, value) => value === void 0 ? void 0 : {
779
842
  ...identity,
780
843
  ...value
781
844
  };
782
- const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
845
+ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
783
846
  name: "@agimon-ai/po-author",
784
- providerOverrides: (0, _agimon_ai_po_core_serverFacet.composeServerProviderOverrides)(root_server_default),
847
+ providerOverrides: (0, _agimon_ai_po_core_serverPlugin.composeServerProviderOverrides)(root_server_default),
848
+ injects: (0, _agimon_ai_po_core_extensionFile.composeRootInjects)({ session: [root_server_default] }),
785
849
  global: (context) => ({
786
850
  get channels() {
787
851
  return [() => via({ frameType: "author_webmcp" }, author_webmcp_server_default())];
@@ -792,14 +856,14 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
792
856
  }),
793
857
  workspace: (context) => ({
794
858
  get channels() {
795
- return [() => via({ frameType: "author_webmcp" }, author_webmcp_server_default())];
859
+ return defined([context.hosted("global") ? void 0 : () => via({ frameType: "author_webmcp" }, author_webmcp_server_default())]);
796
860
  },
797
861
  get methods() {
798
862
  return [at(bridge_server_default, context)];
799
863
  }
800
864
  }),
801
865
  session: async (context) => {
802
- const scopeSession = await root_server_default(context);
866
+ const scopeSession = await context.scopeRoot("session", root_server_default, context);
803
867
  const contextSession = {
804
868
  ...context,
805
869
  root: scopeSession.value
@@ -810,7 +874,7 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
810
874
  return [at(route_server_default, contextSession)];
811
875
  },
812
876
  get channels() {
813
- return [() => via({ frameType: "author_webmcp" }, author_webmcp_server_default())];
877
+ return defined([context.hosted("global") ? void 0 : () => via({ frameType: "author_webmcp" }, author_webmcp_server_default())]);
814
878
  },
815
879
  get commands() {
816
880
  return [via({ name: "author" }, at(author_server_default, contextSession))];
@@ -839,7 +903,7 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
839
903
  }
840
904
  });
841
905
  //#endregion
842
- exports.default = facet;
843
- exports.facet = facet;
906
+ exports.default = serverPlugin;
907
+ exports.serverPlugin = serverPlugin;
844
908
 
845
909
  //# sourceMappingURL=server.cjs.map