@canaryai/cli 0.2.13 → 0.2.14

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 (35) hide show
  1. package/dist/{chunk-Z3F373YR.js → chunk-4A4G5KTC.js} +2 -1
  2. package/dist/chunk-4A4G5KTC.js.map +1 -0
  3. package/dist/{chunk-IFOJT3A5.js → chunk-6IAPGYZQ.js} +38 -16
  4. package/dist/{chunk-IFOJT3A5.js.map → chunk-6IAPGYZQ.js.map} +1 -1
  5. package/dist/{chunk-SVU2XTYZ.js → chunk-ZQF72UTG.js} +2 -2
  6. package/dist/{debug-workflow-K2LL6CO4.js → debug-workflow-DIQZDFMN.js} +3 -3
  7. package/dist/{docs-SR7CW24Y.js → docs-CSVSGIGW.js} +45 -2
  8. package/dist/docs-CSVSGIGW.js.map +1 -0
  9. package/dist/index.js +8 -8
  10. package/dist/{init-KXAVWHYE.js → init-BTDX5N6P.js} +2 -2
  11. package/dist/{local-34FX3M5K.js → local-ZPVM4BXX.js} +4 -4
  12. package/dist/{local-browser-VPOSJS52.js → local-browser-WV4IH2DU.js} +3 -3
  13. package/dist/{login-MSIM2VIH.js → login-W4GXV3VA.js} +2 -2
  14. package/dist/{mcp-YBR7G254.js → mcp-YER5GQG7.js} +4 -4
  15. package/dist/{record-DXXQHPGT.js → record-KRS2PHMW.js} +2 -2
  16. package/dist/{session-XQGCLWNC.js → session-CLWAVJ2K.js} +3 -3
  17. package/dist/{src-F7LQ5PY2.js → src-WLOHOI6P.js} +2 -2
  18. package/dist/{start-ZOMUD6LW.js → start-CNNQUP5I.js} +2 -2
  19. package/dist/{workflow-5UZTKX7X.js → workflow-XXL4H5R4.js} +3 -2
  20. package/dist/workflow-XXL4H5R4.js.map +1 -0
  21. package/package.json +1 -1
  22. package/dist/chunk-Z3F373YR.js.map +0 -1
  23. package/dist/docs-SR7CW24Y.js.map +0 -1
  24. package/dist/workflow-5UZTKX7X.js.map +0 -1
  25. /package/dist/{chunk-SVU2XTYZ.js.map → chunk-ZQF72UTG.js.map} +0 -0
  26. /package/dist/{debug-workflow-K2LL6CO4.js.map → debug-workflow-DIQZDFMN.js.map} +0 -0
  27. /package/dist/{init-KXAVWHYE.js.map → init-BTDX5N6P.js.map} +0 -0
  28. /package/dist/{local-34FX3M5K.js.map → local-ZPVM4BXX.js.map} +0 -0
  29. /package/dist/{local-browser-VPOSJS52.js.map → local-browser-WV4IH2DU.js.map} +0 -0
  30. /package/dist/{login-MSIM2VIH.js.map → login-W4GXV3VA.js.map} +0 -0
  31. /package/dist/{mcp-YBR7G254.js.map → mcp-YER5GQG7.js.map} +0 -0
  32. /package/dist/{record-DXXQHPGT.js.map → record-KRS2PHMW.js.map} +0 -0
  33. /package/dist/{session-XQGCLWNC.js.map → session-CLWAVJ2K.js.map} +0 -0
  34. /package/dist/{src-F7LQ5PY2.js.map → src-WLOHOI6P.js.map} +0 -0
  35. /package/dist/{start-ZOMUD6LW.js.map → start-CNNQUP5I.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  PlaywrightClient
4
- } from "./chunk-IFOJT3A5.js";
4
+ } from "./chunk-6IAPGYZQ.js";
5
5
 
6
6
  // src/local-browser/host.ts
7
7
  var HEARTBEAT_INTERVAL_MS = 3e4;
@@ -384,4 +384,4 @@ var LocalBrowserHost = class {
384
384
  export {
385
385
  LocalBrowserHost
386
386
  };
387
- //# sourceMappingURL=chunk-SVU2XTYZ.js.map
387
+ //# sourceMappingURL=chunk-ZQF72UTG.js.map
@@ -4,13 +4,13 @@ import {
4
4
  } from "./chunk-BOS2YLKH.js";
5
5
  import {
6
6
  LocalBrowserHost
7
- } from "./chunk-SVU2XTYZ.js";
7
+ } from "./chunk-ZQF72UTG.js";
8
8
  import {
9
9
  getArgValue,
10
10
  hasFlag,
11
11
  resolveConfig
12
12
  } from "./chunk-ACRIE2YR.js";
13
- import "./chunk-IFOJT3A5.js";
13
+ import "./chunk-6IAPGYZQ.js";
14
14
  import "./chunk-XAA5VQ5N.js";
15
15
  import "./chunk-P5Z2Y5VV.js";
16
16
  import "./chunk-VKVL7WBN.js";
@@ -260,4 +260,4 @@ async function runDebugWorkflow(argv) {
260
260
  export {
261
261
  runDebugWorkflow
262
262
  };
263
- //# sourceMappingURL=debug-workflow-K2LL6CO4.js.map
263
+ //# sourceMappingURL=debug-workflow-DIQZDFMN.js.map
@@ -191,6 +191,44 @@ async function handleCreate(argv, apiUrl, token) {
191
191
  }
192
192
  console.log(`Created page: ${slug}`);
193
193
  }
194
+ async function handleSearch(argv, apiUrl, token) {
195
+ const query = argv.filter((a) => !a.startsWith("--")).join(" ").trim();
196
+ if (!query) {
197
+ console.error("Error: Missing search query.");
198
+ console.error("Usage: canary docs search <query> [--limit <n>] [--json]");
199
+ process.exit(1);
200
+ }
201
+ const jsonOutput = hasFlag(argv, "--json");
202
+ const limitArg = getArgValue(argv, "--limit");
203
+ const params = new URLSearchParams({ q: query });
204
+ if (limitArg) params.set("limit", limitArg);
205
+ const res = await fetch(`${apiUrl}/public/docs/search?${params.toString()}`, {
206
+ headers: { Authorization: `Bearer ${token}` }
207
+ });
208
+ if (!res.ok) {
209
+ const body2 = await res.json().catch(() => ({ error: res.statusText }));
210
+ console.error(`Error: ${body2.error ?? res.statusText}`);
211
+ process.exit(1);
212
+ }
213
+ const body = await res.json();
214
+ const results = body.data?.results ?? [];
215
+ if (jsonOutput) {
216
+ console.log(JSON.stringify(results, null, 2));
217
+ return;
218
+ }
219
+ if (results.length === 0) {
220
+ console.log("No results found.");
221
+ return;
222
+ }
223
+ for (const r of results) {
224
+ const desc = r.description ? ` ${r.description}` : "";
225
+ const excerpt = r.excerpt ? ` ${r.excerpt.replace(/<\/?mark>/g, "").replace(/\n/g, " ").slice(0, 120)}` : "";
226
+ console.log(` ${r.path ?? r.title}`);
227
+ if (r.title) console.log(` ${r.title}${desc}`);
228
+ if (excerpt) console.log(` ${excerpt}`);
229
+ console.log();
230
+ }
231
+ }
194
232
  async function handleDelete(argv, apiUrl, token) {
195
233
  const slug = argv[0];
196
234
  if (!slug || slug.startsWith("--")) {
@@ -218,6 +256,7 @@ function printDocsHelp() {
218
256
  "Sub-commands:",
219
257
  " list List all doc pages",
220
258
  " get <slug> Print content to stdout",
259
+ " search <query> Full-text search docs",
221
260
  " pull <slug> [--output <path>] Download to local file",
222
261
  " push <slug> --file <path> [--message] Publish new version",
223
262
  " history <slug> Show version history",
@@ -229,8 +268,9 @@ function printDocsHelp() {
229
268
  " --title <text> Page title (create only)",
230
269
  " --description <text> Page description (create only)",
231
270
  " --message <text> Version commit message",
271
+ " --limit <n> Max results for search (default: 8, max: 20)",
232
272
  " --output <path> Output path for pull (default: /tmp/canary/docs/<slug>.md)",
233
- " --json Output as JSON (list, history)",
273
+ " --json Output as JSON (list, history, search)",
234
274
  " --env <env> Target environment (prod, dev)",
235
275
  " --api-url <url> API URL override",
236
276
  " --token <key> API token override"
@@ -251,6 +291,9 @@ async function runDocs(argv) {
251
291
  case "get":
252
292
  await handleGet(rest, apiUrl, token);
253
293
  break;
294
+ case "search":
295
+ await handleSearch(rest, apiUrl, token);
296
+ break;
254
297
  case "pull":
255
298
  await handlePull(rest, apiUrl, token);
256
299
  break;
@@ -275,4 +318,4 @@ async function runDocs(argv) {
275
318
  export {
276
319
  runDocs
277
320
  };
278
- //# sourceMappingURL=docs-SR7CW24Y.js.map
321
+ //# sourceMappingURL=docs-CSVSGIGW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/docs.ts"],"sourcesContent":["/**\n * CLI Documentation Management\n *\n * Allows agents and superadmins to list, pull, edit, and push documentation pages.\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getSubDir } from '@chatsdet/tmp';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest, fetchList } from './cli-helpers.js';\n\ntype DocsPageListItem = {\n slug: string;\n title: string;\n description: string | null;\n updatedAt: string;\n publishedBy: string | null;\n};\n\ntype DocsVersionItem = {\n version: number;\n title: string;\n checksum: string;\n message: string | null;\n createdBy: string;\n createdAt: string;\n};\n\ntype DocsApiResponse = {\n ok: boolean;\n error?: string;\n data?: {\n slug?: string;\n title?: string;\n pages?: DocsPageListItem[];\n content?: string;\n versions?: DocsVersionItem[];\n };\n};\n\nconst DEFAULT_PULL_DIR = getSubDir('docs');\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n const pages = await fetchList<DocsPageListItem>(apiUrl, token, '/public/docs/pages', 'pages');\n\n if (jsonOutput) {\n console.log(JSON.stringify(pages, null, 2));\n return;\n }\n\n if (pages.length === 0) {\n console.log('No documentation pages found.');\n return;\n }\n\n for (const page of pages) {\n const date = new Date(page.updatedAt).toISOString().slice(0, 10);\n const by = page.publishedBy ? ` (${page.publishedBy})` : '';\n console.log(` ${page.slug} ${page.title} [${date}${by}]`);\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs get <slug>');\n process.exit(1);\n }\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n const content = await res.text();\n console.log(content);\n}\n\nasync function handlePull(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs pull <slug> [--output <path>]');\n process.exit(1);\n }\n\n const outputPath = getArgValue(argv, '--output') ?? path.join(DEFAULT_PULL_DIR, `${slug}.md`);\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n const content = await res.text();\n await mkdir(path.dirname(outputPath), { recursive: true });\n await writeFile(outputPath, content, 'utf8');\n console.log(`Pulled ${slug} → ${outputPath}`);\n}\n\nasync function handlePush(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs push <slug> --file <path> [--message <text>]');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n\n const message = getArgValue(argv, '--message') ?? undefined;\n const createdBy = getArgValue(argv, '--created-by') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'PUT',\n `/superadmin/docs/pages?slug=${encodeURIComponent(slug)}`,\n { content, message, createdBy }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Published new version of ${slug}`);\n}\n\nasync function handleHistory(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs history <slug>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n const res = await fetch(`${apiUrl}/public/docs/pages/versions?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsApiResponse;\n const versions = body.data?.versions ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(versions, null, 2));\n return;\n }\n\n if (versions.length === 0) {\n console.log(`No versions found for ${slug}.`);\n return;\n }\n\n for (const v of versions) {\n const date = new Date(v.createdAt).toISOString().slice(0, 19).replace('T', ' ');\n const msg = v.message ? ` — ${v.message}` : '';\n console.log(` v${v.version} ${date} ${v.createdBy}${msg}`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs create <slug> --file <path> --title <text>');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n const title = getArgValue(argv, '--title');\n\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n if (!title) {\n console.error('Error: Missing --title <text>.');\n process.exit(1);\n }\n\n const description = getArgValue(argv, '--description') ?? undefined;\n const message = getArgValue(argv, '--message') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'POST',\n '/superadmin/docs/pages',\n {\n slug,\n title,\n description,\n content,\n message,\n }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created page: ${slug}`);\n}\n\ntype DocsSearchResult = {\n path: string;\n title: string;\n description: string | null;\n excerpt: string;\n};\n\ntype DocsSearchResponse = {\n ok: boolean;\n error?: string;\n data?: { results: DocsSearchResult[] };\n};\n\nasync function handleSearch(argv: string[], apiUrl: string, token: string): Promise<void> {\n const query = argv.filter((a) => !a.startsWith('--')).join(' ').trim();\n if (!query) {\n console.error('Error: Missing search query.');\n console.error('Usage: canary docs search <query> [--limit <n>] [--json]');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const limitArg = getArgValue(argv, '--limit');\n const params = new URLSearchParams({ q: query });\n if (limitArg) params.set('limit', limitArg);\n\n const res = await fetch(`${apiUrl}/public/docs/search?${params.toString()}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsSearchResponse;\n const results = body.data?.results ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n\n if (results.length === 0) {\n console.log('No results found.');\n return;\n }\n\n for (const r of results) {\n const desc = r.description ? ` ${r.description}` : '';\n const excerpt = r.excerpt\n ? ` ${r.excerpt.replace(/<\\/?mark>/g, '').replace(/\\n/g, ' ').slice(0, 120)}`\n : '';\n console.log(` ${r.path ?? r.title}`);\n if (r.title) console.log(` ${r.title}${desc}`);\n if (excerpt) console.log(` ${excerpt}`);\n console.log();\n }\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs delete <slug>');\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'DELETE',\n `/superadmin/docs/pages?slug=${encodeURIComponent(slug)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted page: ${slug}`);\n}\n\nfunction printDocsHelp(): void {\n console.log(\n [\n 'Usage: canary docs <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list List all doc pages',\n ' get <slug> Print content to stdout',\n ' search <query> Full-text search docs',\n ' pull <slug> [--output <path>] Download to local file',\n ' push <slug> --file <path> [--message] Publish new version',\n ' history <slug> Show version history',\n ' create <slug> --file <path> --title ... Create new page',\n ' delete <slug> Soft-delete a page',\n '',\n 'Options:',\n ' --file <path> Path to markdown file',\n ' --title <text> Page title (create only)',\n ' --description <text> Page description (create only)',\n ' --message <text> Version commit message',\n ' --limit <n> Max results for search (default: 8, max: 20)',\n ' --output <path> Output path for pull (default: /tmp/canary/docs/<slug>.md)',\n ' --json Output as JSON (list, history, search)',\n ' --env <env> Target environment (prod, dev)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runDocs(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printDocsHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n case 'search':\n await handleSearch(rest, apiUrl, token);\n break;\n case 'pull':\n await handlePull(rest, apiUrl, token);\n break;\n case 'push':\n await handlePush(rest, apiUrl, token);\n break;\n case 'history':\n await handleHistory(rest, apiUrl, token);\n break;\n case 'create':\n await handleCreate(rest, apiUrl, token);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printDocsHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["body"]}
package/dist/index.js CHANGED
@@ -928,12 +928,12 @@ function isSuperadminToken(token) {
928
928
  // src/index.ts
929
929
  var require2 = createRequire2(import.meta.url);
930
930
  var pkg = require2("../package.json");
931
- var loadMcp = () => import("./mcp-YBR7G254.js").then((m) => m.runMcp);
932
- var loadLocalBrowser = () => import("./local-browser-VPOSJS52.js").then((m) => m.runLocalBrowser);
933
- var loadDebugWorkflow = () => import("./debug-workflow-K2LL6CO4.js").then((m) => m.runDebugWorkflow);
934
- var loadRecord = () => import("./record-DXXQHPGT.js").then((m) => m.runRecord);
935
- var loadSession = () => import("./session-XQGCLWNC.js").then((m) => m.runSession);
936
- var loadLocal = () => import("./local-34FX3M5K.js").then((m) => m.runLocal);
931
+ var loadMcp = () => import("./mcp-YER5GQG7.js").then((m) => m.runMcp);
932
+ var loadLocalBrowser = () => import("./local-browser-WV4IH2DU.js").then((m) => m.runLocalBrowser);
933
+ var loadDebugWorkflow = () => import("./debug-workflow-DIQZDFMN.js").then((m) => m.runDebugWorkflow);
934
+ var loadRecord = () => import("./record-KRS2PHMW.js").then((m) => m.runRecord);
935
+ var loadSession = () => import("./session-CLWAVJ2K.js").then((m) => m.runSession);
936
+ var loadLocal = () => import("./local-ZPVM4BXX.js").then((m) => m.runLocal);
937
937
  var canary = { run };
938
938
  var baseDir = typeof __dirname !== "undefined" ? __dirname : path4.dirname(fileURLToPath2(import.meta.url));
939
939
  var preloadPath = path4.join(baseDir, "runner", "preload.js");
@@ -1231,7 +1231,7 @@ async function main(argv) {
1231
1231
  return;
1232
1232
  }
1233
1233
  if (command === "docs") {
1234
- const { runDocs } = await import("./docs-SR7CW24Y.js");
1234
+ const { runDocs } = await import("./docs-CSVSGIGW.js");
1235
1235
  await runDocs(rest);
1236
1236
  return;
1237
1237
  }
@@ -1251,7 +1251,7 @@ async function main(argv) {
1251
1251
  return;
1252
1252
  }
1253
1253
  if (command === "workflow") {
1254
- const { runWorkflow } = await import("./workflow-5UZTKX7X.js");
1254
+ const { runWorkflow } = await import("./workflow-XXL4H5R4.js");
1255
1255
  await runWorkflow(rest);
1256
1256
  return;
1257
1257
  }
@@ -10,7 +10,7 @@ import {
10
10
  createSession,
11
11
  deleteSession,
12
12
  getSessionStorageState
13
- } from "./chunk-Z3F373YR.js";
13
+ } from "./chunk-4A4G5KTC.js";
14
14
  import {
15
15
  resolveConfig
16
16
  } from "./chunk-ACRIE2YR.js";
@@ -143,4 +143,4 @@ async function handleManualLogin(config, propertyId, environmentId, localUrl) {
143
143
  export {
144
144
  runLocalInit
145
145
  };
146
- //# sourceMappingURL=init-KXAVWHYE.js.map
146
+ //# sourceMappingURL=init-BTDX5N6P.js.map
@@ -32,12 +32,12 @@ async function runLocal(argv) {
32
32
  }
33
33
  switch (subcommand) {
34
34
  case "init": {
35
- const { runLocalInit } = await import("./init-KXAVWHYE.js");
35
+ const { runLocalInit } = await import("./init-BTDX5N6P.js");
36
36
  await runLocalInit(rest);
37
37
  break;
38
38
  }
39
39
  case "start": {
40
- const { runLocalStart } = await import("./start-ZOMUD6LW.js");
40
+ const { runLocalStart } = await import("./start-CNNQUP5I.js");
41
41
  await runLocalStart(rest);
42
42
  break;
43
43
  }
@@ -47,7 +47,7 @@ async function runLocal(argv) {
47
47
  break;
48
48
  }
49
49
  case "login": {
50
- const { runLocalLogin } = await import("./login-MSIM2VIH.js");
50
+ const { runLocalLogin } = await import("./login-W4GXV3VA.js");
51
51
  await runLocalLogin(rest);
52
52
  break;
53
53
  }
@@ -60,4 +60,4 @@ async function runLocal(argv) {
60
60
  export {
61
61
  runLocal
62
62
  };
63
- //# sourceMappingURL=local-34FX3M5K.js.map
63
+ //# sourceMappingURL=local-ZPVM4BXX.js.map
@@ -1,11 +1,11 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  LocalBrowserHost
4
- } from "./chunk-SVU2XTYZ.js";
4
+ } from "./chunk-ZQF72UTG.js";
5
5
  import {
6
6
  readStoredToken
7
7
  } from "./chunk-ACRIE2YR.js";
8
- import "./chunk-IFOJT3A5.js";
8
+ import "./chunk-6IAPGYZQ.js";
9
9
  import "./chunk-XAA5VQ5N.js";
10
10
  import "./chunk-P5Z2Y5VV.js";
11
11
  import "./chunk-VKVL7WBN.js";
@@ -141,4 +141,4 @@ async function runLocalBrowser(args) {
141
141
  export {
142
142
  runLocalBrowser
143
143
  };
144
- //# sourceMappingURL=local-browser-VPOSJS52.js.map
144
+ //# sourceMappingURL=local-browser-WV4IH2DU.js.map
@@ -9,7 +9,7 @@ import {
9
9
  createSession,
10
10
  deleteSession,
11
11
  getSessionStorageState
12
- } from "./chunk-Z3F373YR.js";
12
+ } from "./chunk-4A4G5KTC.js";
13
13
  import {
14
14
  resolveConfig
15
15
  } from "./chunk-ACRIE2YR.js";
@@ -127,4 +127,4 @@ Opening browser at ${selectedEnv.url}...`);
127
127
  export {
128
128
  runLocalLogin
129
129
  };
130
- //# sourceMappingURL=login-MSIM2VIH.js.map
130
+ //# sourceMappingURL=login-W4GXV3VA.js.map
@@ -1,20 +1,20 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  LocalBrowserHost
4
- } from "./chunk-SVU2XTYZ.js";
4
+ } from "./chunk-ZQF72UTG.js";
5
5
  import {
6
6
  callTool,
7
7
  createSession,
8
8
  deleteAllSessions,
9
9
  deleteSession,
10
10
  resolveTargetSession
11
- } from "./chunk-Z3F373YR.js";
11
+ } from "./chunk-4A4G5KTC.js";
12
12
  import {
13
13
  readStoredToken
14
14
  } from "./chunk-ACRIE2YR.js";
15
15
  import {
16
16
  getBrowserToolDefinitionsWithLifecycle
17
- } from "./chunk-IFOJT3A5.js";
17
+ } from "./chunk-6IAPGYZQ.js";
18
18
  import "./chunk-XAA5VQ5N.js";
19
19
  import "./chunk-P5Z2Y5VV.js";
20
20
  import "./chunk-VKVL7WBN.js";
@@ -371,4 +371,4 @@ async function runMcp(_argv) {
371
371
  export {
372
372
  runMcp
373
373
  };
374
- //# sourceMappingURL=mcp-YBR7G254.js.map
374
+ //# sourceMappingURL=mcp-YER5GQG7.js.map
@@ -249,7 +249,7 @@ async function runRecord(argv) {
249
249
  );
250
250
  }
251
251
  console.log("Launching browser...");
252
- const { PlaywrightClient, consoleLogger, captureElementAtPoint } = await import("./src-F7LQ5PY2.js");
252
+ const { PlaywrightClient, consoleLogger, captureElementAtPoint } = await import("./src-WLOHOI6P.js");
253
253
  const videoDir = path.join(getCanaryTmpDir(), `canary-record-video-${Date.now()}`);
254
254
  await fs.mkdir(videoDir, { recursive: true });
255
255
  const client = new PlaywrightClient({ logger: consoleLogger });
@@ -394,4 +394,4 @@ Output directory: ${outDir}`);
394
394
  export {
395
395
  runRecord
396
396
  };
397
- //# sourceMappingURL=record-DXXQHPGT.js.map
397
+ //# sourceMappingURL=record-KRS2PHMW.js.map
@@ -12,7 +12,7 @@ import {
12
12
  listSessions,
13
13
  resolveTargetSession,
14
14
  swapSessionContext
15
- } from "./chunk-Z3F373YR.js";
15
+ } from "./chunk-4A4G5KTC.js";
16
16
  import {
17
17
  getArgValue,
18
18
  hasFlag,
@@ -22,7 +22,7 @@ import {
22
22
  BrowserToolExecutor,
23
23
  PlaywrightClient,
24
24
  dispatchBrowserTool
25
- } from "./chunk-IFOJT3A5.js";
25
+ } from "./chunk-6IAPGYZQ.js";
26
26
  import "./chunk-XAA5VQ5N.js";
27
27
  import {
28
28
  consoleLogger
@@ -837,4 +837,4 @@ async function runSession(argv) {
837
837
  export {
838
838
  runSession
839
839
  };
840
- //# sourceMappingURL=session-XQGCLWNC.js.map
840
+ //# sourceMappingURL=session-CLWAVJ2K.js.map
@@ -76,7 +76,7 @@ import {
76
76
  sortMatchesByContext,
77
77
  withRecoveryNotice,
78
78
  withRecoveryNoticeMCP
79
- } from "./chunk-IFOJT3A5.js";
79
+ } from "./chunk-6IAPGYZQ.js";
80
80
  import "./chunk-XAA5VQ5N.js";
81
81
  import {
82
82
  consoleLogger,
@@ -167,4 +167,4 @@ export {
167
167
  withRecoveryNotice,
168
168
  withRecoveryNoticeMCP
169
169
  };
170
- //# sourceMappingURL=src-F7LQ5PY2.js.map
170
+ //# sourceMappingURL=src-WLOHOI6P.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-BOS2YLKH.js";
8
8
  import {
9
9
  createSession
10
- } from "./chunk-Z3F373YR.js";
10
+ } from "./chunk-4A4G5KTC.js";
11
11
  import {
12
12
  resolveConfig
13
13
  } from "./chunk-ACRIE2YR.js";
@@ -109,4 +109,4 @@ Use \`canary session\` commands to interact with the browser.`);
109
109
  export {
110
110
  runLocalStart
111
111
  };
112
- //# sourceMappingURL=start-ZOMUD6LW.js.map
112
+ //# sourceMappingURL=start-CNNQUP5I.js.map
@@ -326,7 +326,8 @@ function getCleanConfig(node) {
326
326
  "customActionInstructions",
327
327
  "playbookSteps",
328
328
  "inputValues",
329
- "declaredOutputs"
329
+ "declaredOutputs",
330
+ "alwaysUseAgent"
330
331
  ]);
331
332
  case "assertion":
332
333
  return pick(c, ["condition", "expectedOutcome", "strict", "alwaysUseAgent"]);
@@ -621,4 +622,4 @@ async function runWorkflow(argv) {
621
622
  export {
622
623
  runWorkflow
623
624
  };
624
- //# sourceMappingURL=workflow-5UZTKX7X.js.map
625
+ //# sourceMappingURL=workflow-XXL4H5R4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/workflow.ts","../src/workflow-create.ts"],"sourcesContent":["/**\n * CLI Workflow Management\n *\n * Inspect workflow definitions and steps from the terminal.\n */\n\nimport fs from 'node:fs/promises';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\nimport { handleWorkflowCreate } from './workflow-create.js';\n\n/* ── Types ────────────────────────────────────────────────────────────── */\n\ntype WorkflowNode = {\n id: string;\n nodeType: string;\n orderIndex: number;\n configJson: Record<string, unknown>;\n};\n\ntype WorkflowSummary = {\n id: string;\n name: string;\n description: string | null;\n status: string;\n flowType: string;\n nodes: WorkflowNode[];\n edges: unknown[];\n};\n\ntype Pagination = {\n page: number;\n pageSize: number;\n totalItems: number;\n totalPages: number;\n};\n\ntype WorkflowListItem = {\n id: string;\n name: string;\n status: string;\n flowType: string;\n nodeCount?: number;\n};\n\ntype WorkflowListResponse = {\n ok: boolean;\n error?: string;\n data: WorkflowListItem[];\n pagination: Pagination;\n};\n\ntype WorkflowDetailResponse = {\n ok?: boolean;\n error?: string;\n workflow?: WorkflowSummary;\n targetOrgId?: string;\n targetOrgName?: string;\n};\n\n/* ── Node Helpers ─────────────────────────────────────────────────────── */\n\nfunction truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max - 1) + '…';\n}\n\nfunction getNodeTitle(node: WorkflowNode): string {\n const c = node.configJson;\n switch (node.nodeType) {\n case 'login':\n return (c.credentialName as string) || 'Login';\n case 'navigate':\n return (c.pageTitle as string) || truncate((c.pageUrl as string) || 'Navigate', 40);\n case 'action':\n return (\n (c.customActionTitle as string) || truncate((c.actionDescription as string) || 'Action', 50)\n );\n case 'assertion':\n return truncate((c.condition as string) || 'Assertion', 50);\n case 'setup':\n return (c.setupFlowName as string) || 'Setup';\n case 'seed':\n return (c.seedWorkflowName as string) || 'Seed';\n case 'wait':\n return 'Wait';\n case 'condition':\n return truncate((c.conditionDescription as string) || 'Condition', 50);\n case 'end':\n return 'End';\n case 'api_sequence':\n return 'API Sequence';\n default:\n return node.nodeType;\n }\n}\n\nfunction getCleanConfig(node: WorkflowNode): Record<string, unknown> {\n const c = node.configJson;\n switch (node.nodeType) {\n case 'login':\n return pick(c, ['credentialName', 'performLogin']);\n case 'navigate':\n return {\n ...pick(c, ['pageUrl', 'pageTitle']),\n ...(c.openInNewTab ? { openInNewTab: true } : {}),\n };\n case 'action':\n return pick(c, [\n 'actionDescription',\n 'customActionInstructions',\n 'playbookSteps',\n 'inputValues',\n 'declaredOutputs',\n 'alwaysUseAgent',\n ]);\n case 'assertion':\n return pick(c, ['condition', 'expectedOutcome', 'strict', 'alwaysUseAgent']);\n case 'setup':\n return pick(c, ['setupFlowId', 'setupFlowName']);\n case 'seed':\n return pick(c, ['seedWorkflowId', 'seedWorkflowName', 'snapshotVersion']);\n case 'end':\n return pick(c, ['outcome']);\n case 'wait':\n case 'condition':\n case 'api_sequence':\n return c;\n default:\n return c;\n }\n}\n\nfunction pick(obj: Record<string, unknown>, keys: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n if (obj[key] !== undefined && obj[key] !== null) {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\n/* ── Markdown Formatter ───────────────────────────────────────────────── */\n\nfunction formatWorkflowMarkdown(workflow: WorkflowSummary): string {\n const sections: string[] = [];\n\n sections.push(`# ${workflow.name}`);\n const meta = [\n `**ID:** ${workflow.id}`,\n `**Status:** ${workflow.status}`,\n `**Type:** ${workflow.flowType}`,\n ];\n sections.push(meta.join(' | '));\n\n if (workflow.description) {\n sections.push(`**Description:** ${workflow.description}`);\n }\n\n sections.push('---');\n\n const sorted = [...workflow.nodes].sort((a, b) => a.orderIndex - b.orderIndex);\n\n for (let i = 0; i < sorted.length; i++) {\n const node = sorted[i];\n const title = getNodeTitle(node);\n const stepLines: string[] = [];\n\n stepLines.push(`## Step ${i + 1}: ${title}`);\n stepLines.push(`**Type:** ${node.nodeType}`);\n\n const c = node.configJson;\n switch (node.nodeType) {\n case 'login': {\n if (c.credentialName) stepLines.push(`**Credential:** ${c.credentialName}`);\n if (c.performLogin !== undefined)\n stepLines.push(`**Perform Login:** ${c.performLogin ? 'Yes' : 'No'}`);\n break;\n }\n case 'navigate': {\n if (c.pageUrl) stepLines.push(`**URL:** ${c.pageUrl}`);\n if (c.openInNewTab) stepLines.push(`**Open in New Tab:** Yes`);\n break;\n }\n case 'action': {\n const instructions =\n (c.customActionInstructions as string) || (c.actionDescription as string);\n if (instructions) stepLines.push(`**Instructions:** ${instructions}`);\n const playbook = c.playbookSteps as\n | Array<{ order: number; action: string; target: string }>\n | undefined;\n if (playbook && playbook.length > 0) {\n stepLines.push('');\n stepLines.push('**Playbook:**');\n for (const step of playbook) {\n stepLines.push(`${step.order}. [${step.action}] ${step.target}`);\n }\n }\n break;\n }\n case 'assertion': {\n if (c.condition) stepLines.push(`**Condition:** ${c.condition}`);\n if (c.strict) stepLines.push(`**Strict:** Yes`);\n break;\n }\n case 'setup': {\n if (c.setupFlowName) stepLines.push(`**Setup Flow:** ${c.setupFlowName}`);\n break;\n }\n case 'seed': {\n if (c.seedWorkflowName) stepLines.push(`**Seed Workflow:** ${c.seedWorkflowName}`);\n break;\n }\n case 'wait': {\n if (c.waitDuration) stepLines.push(`**Duration:** ${c.waitDuration}`);\n break;\n }\n case 'condition': {\n if (c.conditionDescription) stepLines.push(`**Condition:** ${c.conditionDescription}`);\n break;\n }\n case 'end': {\n if (c.outcome) stepLines.push(`**Outcome:** ${c.outcome}`);\n break;\n }\n }\n\n sections.push(stepLines.join('\\n'));\n }\n\n return sections.join('\\n\\n');\n}\n\n/* ── JSON Formatter ───────────────────────────────────────────────────── */\n\nfunction formatWorkflowJson(workflow: WorkflowSummary): object {\n const sorted = [...workflow.nodes].sort((a, b) => a.orderIndex - b.orderIndex);\n\n return {\n workflow: {\n id: workflow.id,\n name: workflow.name,\n description: workflow.description,\n status: workflow.status,\n flowType: workflow.flowType,\n },\n steps: sorted.map((node, i) => ({\n index: i + 1,\n nodeId: node.id,\n nodeType: node.nodeType,\n title: getNodeTitle(node),\n config: getCleanConfig(node),\n })),\n };\n}\n\n/* ── Sub-command Handlers ─────────────────────────────────────────────── */\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n\n const params = new URLSearchParams();\n const search = getArgValue(argv, '--search');\n const flowType = getArgValue(argv, '--flow-type');\n const status = getArgValue(argv, '--status');\n const page = getArgValue(argv, '--page');\n const pageSize = getArgValue(argv, '--page-size');\n\n if (search) params.set('search', search);\n if (flowType) params.set('flowType', flowType);\n if (status) params.set('status', status);\n if (page) params.set('page', page);\n if (pageSize) params.set('pageSize', pageSize);\n\n const qs = params.toString();\n const path = `/workflows${qs ? `?${qs}` : ''}`;\n\n const result = await apiRequest<WorkflowListResponse>(apiUrl, token, 'GET', path);\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify({ data: result.data, pagination: result.pagination }, null, 2));\n return;\n }\n\n // Default table output\n const { data, pagination } = result;\n console.log(\n `Workflows: ${pagination.totalItems} total (page ${pagination.page}/${pagination.totalPages})\\n`\n );\n\n if (data.length === 0) {\n console.log('No workflows found.');\n return;\n }\n\n // Column widths\n const idW = 36;\n const nameW = 30;\n const statusW = 12;\n const typeW = 10;\n\n const header = [\n 'ID'.padEnd(idW),\n 'Name'.padEnd(nameW),\n 'Status'.padEnd(statusW),\n 'Type'.padEnd(typeW),\n ].join(' ');\n\n console.log(header);\n\n for (const w of data) {\n const row = [\n w.id.padEnd(idW),\n truncate(w.name, nameW).padEnd(nameW),\n w.status.padEnd(statusW),\n w.flowType.padEnd(typeW),\n ].join(' ');\n console.log(row);\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const workflowId = argv[0];\n if (!workflowId || workflowId.startsWith('--')) {\n console.error('Error: Missing workflow ID.');\n console.error('Usage: canary workflow get <workflowId>');\n process.exit(1);\n }\n\n const _jsonOutput = hasFlag(argv, '--json') || getArgValue(argv, '--format') === 'json';\n const markdownOutput =\n hasFlag(argv, '--markdown') || getArgValue(argv, '--format') === 'markdown';\n const outputFile = getArgValue(argv, '--output');\n\n const res = await fetch(`${apiUrl}/workflows/${workflowId}`, {\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n });\n if (res.status === 401) {\n console.error('Error: Unauthorized. Your session may have expired.');\n console.error('Run: canary login');\n process.exit(1);\n }\n const result = (await res.json()) as WorkflowDetailResponse;\n\n if (result.error === 'WORKFLOW_NOT_FOUND') {\n console.error('Error: Workflow not found.');\n process.exit(1);\n }\n if (result.error === 'WORKFLOW_WRONG_ORG') {\n console.error(\n `Error: Workflow belongs to another org: ${result.targetOrgName ?? result.targetOrgId}`\n );\n process.exit(1);\n }\n if (!result.workflow) {\n console.error(`Error: ${result.error ?? 'Unexpected response'}`);\n process.exit(1);\n }\n\n const workflow = result.workflow;\n let output: string;\n\n if (markdownOutput) {\n output = formatWorkflowMarkdown(workflow);\n } else {\n // Default to JSON for agent-friendly output\n output = JSON.stringify(formatWorkflowJson(workflow), null, 2);\n }\n\n if (outputFile) {\n try {\n await fs.writeFile(outputFile, output, 'utf-8');\n console.log(`Written to ${outputFile}`);\n } catch (err) {\n console.error(\n `Error writing to ${outputFile}: ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n return;\n }\n\n console.log(output);\n}\n\n/* ── Help & Entry Point ───────────────────────────────────────────────── */\n\nfunction printWorkflowHelp(): void {\n console.log(\n [\n 'Usage: canary workflow <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list [options] List workflows',\n ' get <workflowId> [options] Get workflow definition with steps',\n ' create [options] Create workflow from JSON (stdin or file)',\n '',\n 'List options:',\n ' --search <query> Search by name',\n ' --flow-type <type> Filter: standard, setup, seed, teardown',\n ' --status <status> Filter: draft, published, archived',\n ' --page <n> Page number (default: 1)',\n ' --page-size <n> Page size (default: 25)',\n ' --json Output raw JSON',\n '',\n 'Get options:',\n ' --format json|markdown Output format (default: json)',\n ' --json Shorthand for --format json',\n ' --markdown Shorthand for --format markdown',\n ' --output <file> Write output to file',\n '',\n 'Create options:',\n ' --from-stdin Read workflow JSON from stdin (default)',\n ' --from-file <path> Read workflow JSON from file',\n ' --quarantine Create with quarantined status (auto-promotes after 3 passes)',\n ' --run-and-publish Create as draft, run test, publish on success',\n ' --property <name|id> Property for run-and-publish',\n ' --environment <name|id> Environment for run-and-publish',\n '',\n 'Common options:',\n ' --env <env> Target environment (prod, dev, local)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runWorkflow(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printWorkflowHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n case 'create':\n await handleWorkflowCreate(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printWorkflowHelp();\n process.exit(1);\n }\n}\n","/**\n * CLI Workflow Creation\n *\n * Creates a workflow with nodes and edges atomically via the API.\n * Supports reading workflow JSON from stdin or file.\n *\n * @module workflow-create\n */\n\nimport fs from \"node:fs/promises\";\nimport process from \"node:process\";\nimport { createParser, type EventSourceMessage } from \"eventsource-parser\";\nimport { getArgValue, hasFlag } from \"./auth.js\";\n\n/* ── Types ────────────────────────────────────────────────────────────── */\n\ntype WorkflowNodeInput = {\n nodeType: string;\n configJson?: Record<string, unknown>;\n};\n\ntype WorkflowCreateInput = {\n name: string;\n description?: string;\n status?: \"draft\" | \"quarantined\";\n flowType?: \"standard\" | \"setup\" | \"seed\" | \"teardown\";\n createdVia?: string;\n propertyId?: string;\n credentialId?: string;\n nodes: WorkflowNodeInput[];\n};\n\ntype CreateResponse = {\n ok: boolean;\n error?: string;\n workflow?: {\n id: string;\n name: string;\n status: string;\n flowType: string;\n createdVia: string | null;\n };\n nodes?: Array<{ id: string; nodeType: string; orderIndex: number }>;\n edges?: Array<{ id: string; sourceNodeId: string; targetNodeId: string }>;\n};\n\ntype SessionStatusResponse = {\n sessions?: Array<{\n id: string;\n propertyId?: string;\n credentialId?: string;\n propertyName?: string;\n credentialName?: string;\n }>;\n};\n\ntype TriggerRunResponse = {\n ok: boolean;\n error?: string;\n jobId?: string;\n suiteId?: string;\n appUrl?: string;\n};\n\ntype WorkflowTestEvent = {\n type: \"workflow-test\";\n workflowId: string;\n testRunId: string;\n status: string;\n errorMessage?: string | null;\n message?: string;\n};\n\ntype WorkflowTestSuiteEvent = {\n type: \"workflow-test-suite\";\n status: string;\n totalWorkflows: number;\n completedWorkflows: number;\n failedWorkflows: number;\n successfulWorkflows: number;\n};\n\n/* ── Input Reading ───────────────────────────────────────────────────── */\n\nasync function readFromStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n const stdin = process.stdin;\n\n if (stdin.isTTY) {\n throw new Error(\"No input on stdin. Pipe workflow JSON or use --from-file.\");\n }\n\n return new Promise((resolve, reject) => {\n stdin.on(\"data\", (chunk) => chunks.push(chunk));\n stdin.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n stdin.on(\"error\", reject);\n });\n}\n\nasync function readWorkflowInput(argv: string[]): Promise<WorkflowCreateInput> {\n let raw: string;\n\n const fromFile = getArgValue(argv, \"--from-file\");\n if (fromFile) {\n try {\n raw = await fs.readFile(fromFile, \"utf-8\");\n } catch (err) {\n throw new Error(`Failed to read file ${fromFile}: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else {\n raw = await readFromStdin();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\"Invalid JSON input. Please provide valid workflow JSON.\");\n }\n\n const input = parsed as WorkflowCreateInput;\n\n if (!input.name || typeof input.name !== \"string\") {\n throw new Error('Workflow JSON must include a \"name\" string field.');\n }\n\n if (!Array.isArray(input.nodes) || input.nodes.length === 0) {\n throw new Error('Workflow JSON must include a non-empty \"nodes\" array.');\n }\n\n const validNodeTypes = [\"login\", \"navigate\", \"action\", \"assertion\", \"end\", \"setup\", \"seed\", \"wait\"];\n for (const node of input.nodes) {\n if (!node.nodeType || !validNodeTypes.includes(node.nodeType)) {\n throw new Error(\n `Invalid nodeType \"${node.nodeType}\". Valid types: ${validNodeTypes.join(\", \")}`\n );\n }\n }\n\n return input;\n}\n\n/* ── Session Auto-linking ────────────────────────────────────────────── */\n\nasync function detectSessionContext(\n apiUrl: string,\n token: string\n): Promise<{ propertyId?: string; credentialId?: string }> {\n try {\n const res = await fetch(`${apiUrl}/sessions/status`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return {};\n\n const data = (await res.json()) as SessionStatusResponse;\n const sessions = data.sessions;\n\n if (!sessions || sessions.length === 0) return {};\n\n // Use the first active session's property/credential\n const session = sessions[0];\n return {\n propertyId: session.propertyId,\n credentialId: session.credentialId,\n };\n } catch {\n // Session detection is best-effort\n return {};\n }\n}\n\n/* ── Run-and-Publish ─────────────────────────────────────────────────── */\n\nasync function runAndPublish(opts: {\n apiUrl: string;\n token: string;\n workflowId: string;\n workflowName: string;\n propertyId?: string;\n environmentId?: string;\n}): Promise<boolean> {\n const { apiUrl, token, workflowId, workflowName } = opts;\n\n // 1. Trigger a test run for this single workflow\n const body: Record<string, string> = {};\n if (opts.propertyId) body.propertyId = opts.propertyId;\n if (opts.environmentId) body.environmentId = opts.environmentId;\n\n const triggerUrl = `${apiUrl}/workflows/test-runs?namePattern=${encodeURIComponent(workflowName)}`;\n\n let triggerRes: Response;\n try {\n triggerRes = await fetch(triggerUrl, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n } catch (err) {\n console.error(`Failed to trigger test run: ${err}`);\n return false;\n }\n\n if (!triggerRes.ok) {\n const errorText = await triggerRes.text();\n console.error(`Failed to trigger test run: ${triggerRes.status} ${errorText}`);\n return false;\n }\n\n const triggerData = (await triggerRes.json()) as TriggerRunResponse;\n if (!triggerData.ok || !triggerData.suiteId) {\n console.error(`Failed to trigger test run: ${triggerData.error ?? \"Unknown error\"}`);\n return false;\n }\n\n const { suiteId } = triggerData;\n console.log(`Test run started (suite: ${suiteId})`);\n console.log(\"Streaming results...\\n\");\n\n // 2. Stream SSE events\n const streamUrl = `${apiUrl}/workflows/test-runs/stream?suiteId=${suiteId}`;\n\n let streamRes: Response;\n try {\n streamRes = await fetch(streamUrl, {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n });\n } catch (err) {\n console.error(`Failed to connect to event stream: ${err}`);\n return false;\n }\n\n if (!streamRes.ok || !streamRes.body) {\n console.error(`Failed to connect to event stream: ${streamRes.status}`);\n return false;\n }\n\n let success = false;\n let hasCompleted = false;\n\n const parser = createParser({\n onEvent: (event: EventSourceMessage) => {\n if (!event.data) return;\n\n try {\n const data = JSON.parse(event.data) as WorkflowTestEvent | WorkflowTestSuiteEvent;\n\n if (event.event === \"workflow-test\") {\n const testEvent = data as WorkflowTestEvent;\n if (testEvent.status === \"success\") {\n console.log(` \\u2713 ${workflowName}`);\n success = true;\n } else if (testEvent.status === \"failed\") {\n console.log(` \\u2717 ${workflowName}`);\n if (testEvent.errorMessage) {\n console.log(` Error: ${testEvent.errorMessage.slice(0, 200)}`);\n }\n success = false;\n } else if (testEvent.status === \"running\") {\n console.log(` \\u25B6 Running ${workflowName}...`);\n }\n }\n\n if (event.event === \"workflow-test-suite\") {\n const suiteEvent = data as WorkflowTestSuiteEvent;\n if (suiteEvent.status === \"completed\") {\n hasCompleted = true;\n }\n }\n } catch {\n // Ignore parse errors for keepalive\n }\n },\n });\n\n const reader = streamRes.body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (!hasCompleted) {\n const { done, value } = await reader.read();\n if (done) break;\n parser.feed(decoder.decode(value, { stream: true }));\n }\n } finally {\n reader.releaseLock();\n }\n\n // 3. If success, publish the workflow\n if (success) {\n try {\n const publishRes = await fetch(`${apiUrl}/workflows/${workflowId}/publish`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (publishRes.ok) {\n console.log(`\\n\\u2713 Workflow published successfully`);\n return true;\n } else {\n console.error(`\\nFailed to publish workflow: ${publishRes.status}`);\n return false;\n }\n } catch (err) {\n console.error(`\\nFailed to publish workflow: ${err}`);\n return false;\n }\n }\n\n console.log(`\\n\\u2717 Test failed — workflow left in draft for manual review`);\n return false;\n}\n\n/* ── Main Handler ────────────────────────────────────────────────────── */\n\nexport async function handleWorkflowCreate(\n argv: string[],\n apiUrl: string,\n token: string\n): Promise<void> {\n const quarantine = hasFlag(argv, \"--quarantine\");\n const runAndPublishFlag = hasFlag(argv, \"--run-and-publish\");\n const propertyArg = getArgValue(argv, \"--property\");\n const environmentArg = getArgValue(argv, \"--environment\");\n\n if (quarantine && runAndPublishFlag) {\n console.error(\"Error: --quarantine and --run-and-publish are mutually exclusive.\");\n process.exit(1);\n }\n\n // 1. Read and validate input\n let input: WorkflowCreateInput;\n try {\n input = await readWorkflowInput(argv);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // 2. Auto-detect session context for property/credential linking\n if (!input.propertyId && !input.credentialId) {\n const sessionCtx = await detectSessionContext(apiUrl, token);\n if (sessionCtx.propertyId) {\n input.propertyId = sessionCtx.propertyId;\n console.log(`Auto-linked property from active session`);\n }\n if (sessionCtx.credentialId) {\n input.credentialId = sessionCtx.credentialId;\n console.log(`Auto-linked credential from active session`);\n }\n }\n\n // 3. Set status based on flags\n if (quarantine) {\n input.status = \"quarantined\";\n }\n\n input.createdVia = \"cli\";\n\n // 4. Create workflow via API\n const res = await fetch(`${apiUrl}/workflows/create-with-nodes`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(input),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Your session may have expired.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n const result = (await res.json()) as CreateResponse;\n\n if (!result.ok || !result.workflow) {\n console.error(`Error: ${result.error ?? \"Failed to create workflow\"}`);\n process.exit(1);\n }\n\n const { workflow, nodes, edges } = result;\n\n console.log(`\\n\\u2713 Workflow created: ${workflow.name}`);\n console.log(` ID: ${workflow.id}`);\n console.log(` Status: ${workflow.status}`);\n console.log(` Nodes: ${nodes?.length ?? 0}`);\n console.log(` Edges: ${edges?.length ?? 0}`);\n\n // Derive web UI URL from API URL\n const webUrl = apiUrl.replace(/\\/api\\b|api\\./, \"app.\").replace(/:\\d+$/, \":5173\");\n console.log(` URL: ${webUrl}/workflows/${workflow.id}`);\n\n // 5. Run-and-publish if requested\n if (runAndPublishFlag) {\n console.log(\"\\nTriggering test run...\");\n\n const passed = await runAndPublish({\n apiUrl,\n token,\n workflowId: workflow.id,\n workflowName: workflow.name,\n propertyId: propertyArg ?? input.propertyId,\n environmentId: environmentArg,\n });\n\n if (!passed) {\n process.exit(1);\n }\n }\n}\n"],"mappings":"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","names":["fs","process","process","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canaryai/cli",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/session/daemon-client.ts"],"sourcesContent":["/**\n * Daemon client — HTTP client for the session daemon.\n *\n * Handles pidfile read/write, stale PID detection, auto-start,\n * and provides typed HTTP helpers for daemon communication.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type {\n DaemonState,\n DaemonResponse,\n SessionInfo,\n CreateSessionRequest,\n SwapContextRequest,\n ToolResponse,\n StorageStateResponse,\n} from './types.js';\n\nconst PIDFILE_DIR = path.join(os.homedir(), '.config', 'canary-cli');\nconst PIDFILE_PATH = path.join(PIDFILE_DIR, 'daemon.json');\nconst HEALTH_POLL_INTERVAL_MS = 100;\nconst HEALTH_POLL_TIMEOUT_MS = 15_000;\n\n/* ── Pidfile helpers ─────────────────────────────────────────────────── */\n\nasync function readPidfile(): Promise<DaemonState | null> {\n try {\n const content = await fs.readFile(PIDFILE_PATH, 'utf-8');\n return JSON.parse(content) as DaemonState;\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/* ── HTTP helpers ────────────────────────────────────────────────────── */\n\nasync function daemonFetch(\n port: number,\n method: string,\n path: string,\n body?: unknown\n): Promise<unknown> {\n const url = `http://127.0.0.1:${port}${path}`;\n const res = await fetch(url, {\n method,\n headers: body ? { 'Content-Type': 'application/json' } : undefined,\n body: body ? JSON.stringify(body) : undefined,\n });\n return res.json();\n}\n\nasync function healthCheck(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/* ── Auto-start ──────────────────────────────────────────────────────── */\n\nasync function spawnDaemon(): Promise<number> {\n // Resolve the canary CLI entry point\n // In source: this file is src/session/daemon-client.ts → ../index.ts\n // In dist: this file is dist/chunk-*.js → ./index.js (flat)\n const dir = path.dirname(new URL(import.meta.url).pathname);\n const candidates = [\n path.resolve(dir, '..', 'index.ts'), // source layout\n path.resolve(dir, 'index.js'), // dist layout (flat)\n path.resolve(dir, '..', 'index.js'), // fallback\n ];\n const cliEntry = candidates.find((p) => existsSync(p));\n if (!cliEntry) {\n throw new Error(`Cannot find CLI entry point. Searched: ${candidates.join(', ')}`);\n }\n\n const child = spawn(process.execPath, [cliEntry, 'session', 'daemon'], {\n detached: true,\n stdio: ['ignore', 'pipe', 'ignore'],\n env: { ...process.env },\n });\n\n child.unref();\n\n // Wait for \"DAEMON_READY:<port>\" on stdout\n return new Promise<number>((resolve, reject) => {\n let output = '';\n const timeout = setTimeout(() => {\n reject(new Error('Daemon startup timed out'));\n }, HEALTH_POLL_TIMEOUT_MS);\n\n child.stdout!.on('data', (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DAEMON_READY:(\\d+)/);\n if (match) {\n clearTimeout(timeout);\n resolve(parseInt(match[1], 10));\n }\n });\n\n child.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n\n child.on('exit', (code) => {\n clearTimeout(timeout);\n if (!output.includes('DAEMON_READY')) {\n reject(new Error(`Daemon exited with code ${code} before becoming ready`));\n }\n });\n });\n}\n\n/* ── Public API ──────────────────────────────────────────────────────── */\n\n/**\n * Ensure the daemon is running and return its port.\n * Starts the daemon if needed, cleans up stale pidfiles.\n */\nasync function ensureDaemon(): Promise<number> {\n const state = await readPidfile();\n\n if (state) {\n if (isProcessAlive(state.pid)) {\n // Verify it actually responds\n if (await healthCheck(state.port)) {\n return state.port;\n }\n }\n // Stale pidfile — clean up\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // ignore\n }\n }\n\n // Spawn new daemon\n const port = await spawnDaemon();\n\n // Poll until healthy\n const deadline = Date.now() + HEALTH_POLL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n if (await healthCheck(port)) return port;\n await new Promise((r) => setTimeout(r, HEALTH_POLL_INTERVAL_MS));\n }\n\n throw new Error('Daemon failed to become healthy after spawn');\n}\n\n/* ── Session operations ──────────────────────────────────────────────── */\n\nexport async function createSession(\n params: CreateSessionRequest\n): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'POST', '/sessions', params) as Promise<DaemonResponse<SessionInfo>>;\n}\n\nexport async function listSessions(): Promise<DaemonResponse<SessionInfo[]>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'GET', '/sessions') as Promise<DaemonResponse<SessionInfo[]>>;\n}\n\nexport async function getSession(sessionId: string): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'GET', `/sessions/${sessionId}`) as Promise<DaemonResponse<SessionInfo>>;\n}\n\nexport async function deleteSession(sessionId: string): Promise<DaemonResponse> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'DELETE', `/sessions/${sessionId}`) as Promise<DaemonResponse>;\n}\n\nexport async function deleteAllSessions(): Promise<DaemonResponse> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'DELETE', '/sessions') as Promise<DaemonResponse>;\n}\n\nexport async function swapSessionContext(\n sessionId: string,\n params: SwapContextRequest\n): Promise<DaemonResponse<SessionInfo>> {\n const port = await ensureDaemon();\n return daemonFetch(port, 'POST', `/sessions/${sessionId}/swap-context`, params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function getSessionStorageState(sessionId: string): Promise<StorageStateResponse> {\n const port = await ensureDaemon();\n return daemonFetch(\n port,\n 'GET',\n `/sessions/${sessionId}/storage-state`\n ) as Promise<StorageStateResponse>;\n}\n\nexport async function callTool(\n sessionId: string,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ToolResponse> {\n const port = await ensureDaemon();\n return daemonFetch(\n port,\n 'POST',\n `/sessions/${sessionId}/tools/${toolName}`,\n args\n ) as Promise<ToolResponse>;\n}\n\n/**\n * Resolve the target session for a command.\n * If there's exactly one session, auto-targets it.\n * If a sessionId or name is provided, looks it up.\n */\nexport async function resolveTargetSession(sessionIdOrName?: string): Promise<SessionInfo> {\n const result = await listSessions();\n if (!result.ok || !result.data) {\n throw new Error('Failed to list sessions');\n }\n const sessions = result.data;\n\n if (sessions.length === 0) {\n throw new Error('No active sessions. Start one with: canary session start');\n }\n\n if (sessionIdOrName) {\n const match = sessions.find((s) => s.id === sessionIdOrName || s.name === sessionIdOrName);\n if (!match) {\n throw new Error(\n `Session \"${sessionIdOrName}\" not found. Active sessions: ${sessions.map((s) => s.id).join(', ')}`\n );\n }\n return match;\n }\n\n if (sessions.length === 1) {\n return sessions[0];\n }\n\n throw new Error(\n `Multiple sessions active. Specify one with --session:\\n${sessions.map((s) => ` ${s.id} (${s.name})`).join('\\n')}`\n );\n}\n"],"mappings":";;;AASA,SAAS,aAAa;AACtB,OAAO,QAAQ;AACf,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,OAAO,QAAQ;AAWf,IAAM,cAAc,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY;AACnE,IAAM,eAAe,KAAK,KAAK,aAAa,aAAa;AACzD,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAI/B,eAAe,cAA2C;AACxD,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,SAAS,cAAc,OAAO;AACvD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAe,YACb,MACA,QACAA,OACA,MACkB;AAClB,QAAM,MAAM,oBAAoB,IAAI,GAAGA,KAAI;AAC3C,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B;AAAA,IACA,SAAS,OAAO,EAAE,gBAAgB,mBAAmB,IAAI;AAAA,IACzD,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EACtC,CAAC;AACD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,YAAY,MAAgC;AACzD,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,IAAI,WAAW;AAAA,MACzD,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAe,cAA+B;AAI5C,QAAM,MAAM,KAAK,QAAQ,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ;AAC1D,QAAM,aAAa;AAAA,IACjB,KAAK,QAAQ,KAAK,MAAM,UAAU;AAAA;AAAA,IAClC,KAAK,QAAQ,KAAK,UAAU;AAAA;AAAA,IAC5B,KAAK,QAAQ,KAAK,MAAM,UAAU;AAAA;AAAA,EACpC;AACA,QAAM,WAAW,WAAW,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;AACrD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,0CAA0C,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACnF;AAEA,QAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,UAAU,WAAW,QAAQ,GAAG;AAAA,IACrE,UAAU;AAAA,IACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IAClC,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,EACxB,CAAC;AAED,QAAM,MAAM;AAGZ,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI,SAAS;AACb,UAAM,UAAU,WAAW,MAAM;AAC/B,aAAO,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAC9C,GAAG,sBAAsB;AAEzB,UAAM,OAAQ,GAAG,QAAQ,CAAC,SAAiB;AACzC,gBAAU,KAAK,SAAS;AACxB,YAAM,QAAQ,OAAO,MAAM,oBAAoB;AAC/C,UAAI,OAAO;AACT,qBAAa,OAAO;AACpB,gBAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,CAAC;AAAA,MAChC;AAAA,IACF,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,mBAAa,OAAO;AACpB,aAAO,GAAG;AAAA,IACZ,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,mBAAa,OAAO;AACpB,UAAI,CAAC,OAAO,SAAS,cAAc,GAAG;AACpC,eAAO,IAAI,MAAM,2BAA2B,IAAI,wBAAwB,CAAC;AAAA,MAC3E;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAQA,eAAe,eAAgC;AAC7C,QAAM,QAAQ,MAAM,YAAY;AAEhC,MAAI,OAAO;AACT,QAAI,eAAe,MAAM,GAAG,GAAG;AAE7B,UAAI,MAAM,YAAY,MAAM,IAAI,GAAG;AACjC,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAEA,QAAI;AACF,YAAM,GAAG,OAAO,YAAY;AAAA,IAC9B,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,YAAY;AAG/B,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,QAAI,MAAM,YAAY,IAAI,EAAG,QAAO;AACpC,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAAA,EACjE;AAEA,QAAM,IAAI,MAAM,6CAA6C;AAC/D;AAIA,eAAsB,cACpB,QACsC;AACtC,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,QAAQ,aAAa,MAAM;AACtD;AAEA,eAAsB,eAAuD;AAC3E,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,OAAO,WAAW;AAC7C;AAEA,eAAsB,WAAW,WAAyD;AACxF,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,OAAO,aAAa,SAAS,EAAE;AAC1D;AAEA,eAAsB,cAAc,WAA4C;AAC9E,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,UAAU,aAAa,SAAS,EAAE;AAC7D;AAEA,eAAsB,oBAA6C;AACjE,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,UAAU,WAAW;AAChD;AAEA,eAAsB,mBACpB,WACA,QACsC;AACtC,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,YAAY,MAAM,QAAQ,aAAa,SAAS,iBAAiB,MAAM;AAGhF;AAEA,eAAsB,uBAAuB,WAAkD;AAC7F,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,SAAS;AAAA,EACxB;AACF;AAEA,eAAsB,SACpB,WACA,UACA,MACuB;AACvB,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,SAAS,UAAU,QAAQ;AAAA,IACxC;AAAA,EACF;AACF;AAOA,eAAsB,qBAAqB,iBAAgD;AACzF,QAAM,SAAS,MAAM,aAAa;AAClC,MAAI,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM;AAC9B,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACA,QAAM,WAAW,OAAO;AAExB,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,MAAI,iBAAiB;AACnB,UAAM,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,mBAAmB,EAAE,SAAS,eAAe;AACzF,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,YAAY,eAAe,iCAAiC,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,MAClG;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,SAAS,CAAC;AAAA,EACnB;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAA0D,SAAS,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EACnH;AACF;","names":["path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/docs.ts"],"sourcesContent":["/**\n * CLI Documentation Management\n *\n * Allows agents and superadmins to list, pull, edit, and push documentation pages.\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getSubDir } from '@chatsdet/tmp';\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest, fetchList } from './cli-helpers.js';\n\ntype DocsPageListItem = {\n slug: string;\n title: string;\n description: string | null;\n updatedAt: string;\n publishedBy: string | null;\n};\n\ntype DocsVersionItem = {\n version: number;\n title: string;\n checksum: string;\n message: string | null;\n createdBy: string;\n createdAt: string;\n};\n\ntype DocsApiResponse = {\n ok: boolean;\n error?: string;\n data?: {\n slug?: string;\n title?: string;\n pages?: DocsPageListItem[];\n content?: string;\n versions?: DocsVersionItem[];\n };\n};\n\nconst DEFAULT_PULL_DIR = getSubDir('docs');\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n const pages = await fetchList<DocsPageListItem>(apiUrl, token, '/public/docs/pages', 'pages');\n\n if (jsonOutput) {\n console.log(JSON.stringify(pages, null, 2));\n return;\n }\n\n if (pages.length === 0) {\n console.log('No documentation pages found.');\n return;\n }\n\n for (const page of pages) {\n const date = new Date(page.updatedAt).toISOString().slice(0, 10);\n const by = page.publishedBy ? ` (${page.publishedBy})` : '';\n console.log(` ${page.slug} ${page.title} [${date}${by}]`);\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs get <slug>');\n process.exit(1);\n }\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n const content = await res.text();\n console.log(content);\n}\n\nasync function handlePull(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs pull <slug> [--output <path>]');\n process.exit(1);\n }\n\n const outputPath = getArgValue(argv, '--output') ?? path.join(DEFAULT_PULL_DIR, `${slug}.md`);\n\n const res = await fetch(`${apiUrl}/public/docs/pages/raw?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 404) {\n console.error(`Error: Page not found: ${slug}`);\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Error: ${res.statusText}`);\n process.exit(1);\n }\n\n const content = await res.text();\n await mkdir(path.dirname(outputPath), { recursive: true });\n await writeFile(outputPath, content, 'utf8');\n console.log(`Pulled ${slug} → ${outputPath}`);\n}\n\nasync function handlePush(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs push <slug> --file <path> [--message <text>]');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n\n const message = getArgValue(argv, '--message') ?? undefined;\n const createdBy = getArgValue(argv, '--created-by') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'PUT',\n `/superadmin/docs/pages?slug=${encodeURIComponent(slug)}`,\n { content, message, createdBy }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Published new version of ${slug}`);\n}\n\nasync function handleHistory(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs history <slug>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n\n const res = await fetch(`${apiUrl}/public/docs/pages/versions?slug=${encodeURIComponent(slug)}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n console.error(`Error: ${(body as { error?: string }).error ?? res.statusText}`);\n process.exit(1);\n }\n\n const body = (await res.json()) as DocsApiResponse;\n const versions = body.data?.versions ?? [];\n\n if (jsonOutput) {\n console.log(JSON.stringify(versions, null, 2));\n return;\n }\n\n if (versions.length === 0) {\n console.log(`No versions found for ${slug}.`);\n return;\n }\n\n for (const v of versions) {\n const date = new Date(v.createdAt).toISOString().slice(0, 19).replace('T', ' ');\n const msg = v.message ? ` — ${v.message}` : '';\n console.log(` v${v.version} ${date} ${v.createdBy}${msg}`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs create <slug> --file <path> --title <text>');\n process.exit(1);\n }\n\n const filePath = getArgValue(argv, '--file');\n const title = getArgValue(argv, '--title');\n\n if (!filePath) {\n console.error('Error: Missing --file <path>.');\n process.exit(1);\n }\n if (!title) {\n console.error('Error: Missing --title <text>.');\n process.exit(1);\n }\n\n const description = getArgValue(argv, '--description') ?? undefined;\n const message = getArgValue(argv, '--message') ?? undefined;\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf8');\n } catch {\n console.error(`Error: Could not read file: ${filePath}`);\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'POST',\n '/superadmin/docs/pages',\n {\n slug,\n title,\n description,\n content,\n message,\n }\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created page: ${slug}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const slug = argv[0];\n if (!slug || slug.startsWith('--')) {\n console.error('Error: Missing slug.');\n console.error('Usage: canary docs delete <slug>');\n process.exit(1);\n }\n\n const result = await apiRequest<DocsApiResponse>(\n apiUrl,\n token,\n 'DELETE',\n `/superadmin/docs/pages?slug=${encodeURIComponent(slug)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted page: ${slug}`);\n}\n\nfunction printDocsHelp(): void {\n console.log(\n [\n 'Usage: canary docs <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list List all doc pages',\n ' get <slug> Print content to stdout',\n ' pull <slug> [--output <path>] Download to local file',\n ' push <slug> --file <path> [--message] Publish new version',\n ' history <slug> Show version history',\n ' create <slug> --file <path> --title ... Create new page',\n ' delete <slug> Soft-delete a page',\n '',\n 'Options:',\n ' --file <path> Path to markdown file',\n ' --title <text> Page title (create only)',\n ' --description <text> Page description (create only)',\n ' --message <text> Version commit message',\n ' --output <path> Output path for pull (default: /tmp/canary/docs/<slug>.md)',\n ' --json Output as JSON (list, history)',\n ' --env <env> Target environment (prod, dev)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runDocs(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printDocsHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n case 'pull':\n await handlePull(rest, apiUrl, token);\n break;\n case 'push':\n await handlePush(rest, apiUrl, token);\n break;\n case 'history':\n await handleHistory(rest, apiUrl, token);\n break;\n case 'create':\n await handleCreate(rest, apiUrl, token);\n break;\n case 'delete':\n await handleDelete(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printDocsHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["body"]}