cognetivy 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +415 -1276
- package/dist/cli.js.map +1 -1
- package/dist/cloud-client.d.ts +27 -1
- package/dist/cloud-client.d.ts.map +1 -1
- package/dist/cloud-client.js +18 -3
- package/dist/cloud-client.js.map +1 -1
- package/dist/core/collection-minimal-stub.d.ts +17 -0
- package/dist/core/collection-minimal-stub.d.ts.map +1 -0
- package/dist/core/collection-minimal-stub.js +124 -0
- package/dist/core/collection-minimal-stub.js.map +1 -0
- package/dist/core/collection-validate.d.ts +5 -0
- package/dist/core/collection-validate.d.ts.map +1 -1
- package/dist/core/collection-validate.js +68 -0
- package/dist/core/collection-validate.js.map +1 -1
- package/dist/core/next-step-engine.d.ts.map +1 -1
- package/dist/core/next-step-engine.js +66 -3
- package/dist/core/next-step-engine.js.map +1 -1
- package/dist/core/types.d.ts +9 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/workflow-validate.d.ts.map +1 -1
- package/dist/core/workflow-validate.js +11 -0
- package/dist/core/workflow-validate.js.map +1 -1
- package/dist/dev-checkout.d.ts +13 -0
- package/dist/dev-checkout.d.ts.map +1 -0
- package/dist/dev-checkout.js +56 -0
- package/dist/dev-checkout.js.map +1 -0
- package/dist/edge-executor-spawn.d.ts +22 -0
- package/dist/edge-executor-spawn.d.ts.map +1 -0
- package/dist/edge-executor-spawn.js +122 -0
- package/dist/edge-executor-spawn.js.map +1 -0
- package/dist/edge-worker.d.ts +7 -0
- package/dist/edge-worker.d.ts.map +1 -0
- package/dist/edge-worker.js +210 -0
- package/dist/edge-worker.js.map +1 -0
- package/dist/executor/abort-signals.d.ts +5 -0
- package/dist/executor/abort-signals.d.ts.map +1 -0
- package/dist/executor/abort-signals.js +18 -0
- package/dist/executor/abort-signals.js.map +1 -0
- package/dist/executor/agent-node-runner.d.ts +34 -0
- package/dist/executor/agent-node-runner.d.ts.map +1 -0
- package/dist/executor/agent-node-runner.js +454 -0
- package/dist/executor/agent-node-runner.js.map +1 -0
- package/dist/executor/claude-code-stdio-protocol.d.ts +9 -0
- package/dist/executor/claude-code-stdio-protocol.d.ts.map +1 -0
- package/dist/executor/claude-code-stdio-protocol.js +114 -0
- package/dist/executor/claude-code-stdio-protocol.js.map +1 -0
- package/dist/executor/claude-stream-json-line.d.ts +23 -0
- package/dist/executor/claude-stream-json-line.d.ts.map +1 -0
- package/dist/executor/claude-stream-json-line.js +177 -0
- package/dist/executor/claude-stream-json-line.js.map +1 -0
- package/dist/executor/codex-jsonl-stream.d.ts +14 -0
- package/dist/executor/codex-jsonl-stream.d.ts.map +1 -0
- package/dist/executor/codex-jsonl-stream.js +104 -0
- package/dist/executor/codex-jsonl-stream.js.map +1 -0
- package/dist/executor/collection-output-helpers.d.ts +15 -0
- package/dist/executor/collection-output-helpers.d.ts.map +1 -0
- package/dist/executor/collection-output-helpers.js +67 -0
- package/dist/executor/collection-output-helpers.js.map +1 -0
- package/dist/executor/hitl-wait-with-cloud-poll.d.ts +17 -0
- package/dist/executor/hitl-wait-with-cloud-poll.d.ts.map +1 -0
- package/dist/executor/hitl-wait-with-cloud-poll.js +72 -0
- package/dist/executor/hitl-wait-with-cloud-poll.js.map +1 -0
- package/dist/executor/json-extract.d.ts +22 -0
- package/dist/executor/json-extract.d.ts.map +1 -0
- package/dist/executor/json-extract.js +127 -0
- package/dist/executor/json-extract.js.map +1 -0
- package/dist/executor/node-workspace-isolation.d.ts +3 -0
- package/dist/executor/node-workspace-isolation.d.ts.map +1 -0
- package/dist/executor/node-workspace-isolation.js +79 -0
- package/dist/executor/node-workspace-isolation.js.map +1 -0
- package/dist/executor/prompt-for-node.d.ts +4 -0
- package/dist/executor/prompt-for-node.d.ts.map +1 -0
- package/dist/executor/prompt-for-node.js +54 -0
- package/dist/executor/prompt-for-node.js.map +1 -0
- package/dist/executor/workflow-executor.d.ts +21 -0
- package/dist/executor/workflow-executor.d.ts.map +1 -0
- package/dist/executor/workflow-executor.js +218 -0
- package/dist/executor/workflow-executor.js.map +1 -0
- package/dist/executor/workflow-generate-prompt.d.ts +17 -0
- package/dist/executor/workflow-generate-prompt.d.ts.map +1 -0
- package/dist/executor/workflow-generate-prompt.js +60 -0
- package/dist/executor/workflow-generate-prompt.js.map +1 -0
- package/dist/executor/workflow-generate-runner.d.ts +21 -0
- package/dist/executor/workflow-generate-runner.d.ts.map +1 -0
- package/dist/executor/workflow-generate-runner.js +313 -0
- package/dist/executor/workflow-generate-runner.js.map +1 -0
- package/dist/executor/workflow-node-execution.d.ts +34 -0
- package/dist/executor/workflow-node-execution.d.ts.map +1 -0
- package/dist/executor/workflow-node-execution.js +207 -0
- package/dist/executor/workflow-node-execution.js.map +1 -0
- package/dist/install-tui.d.ts +2 -3
- package/dist/install-tui.d.ts.map +1 -1
- package/dist/install-tui.js +33 -40
- package/dist/install-tui.js.map +1 -1
- package/dist/local-db/execution-store.d.ts +12 -0
- package/dist/local-db/execution-store.d.ts.map +1 -0
- package/dist/local-db/execution-store.js +79 -0
- package/dist/local-db/execution-store.js.map +1 -0
- package/dist/local-hitl-command.d.ts +7 -0
- package/dist/local-hitl-command.d.ts.map +1 -0
- package/dist/local-hitl-command.js +83 -0
- package/dist/local-hitl-command.js.map +1 -0
- package/dist/local-server/executor-terminal-log.d.ts +20 -0
- package/dist/local-server/executor-terminal-log.d.ts.map +1 -0
- package/dist/local-server/executor-terminal-log.js +143 -0
- package/dist/local-server/executor-terminal-log.js.map +1 -0
- package/dist/local-server/hitl-coordinator.d.ts +17 -0
- package/dist/local-server/hitl-coordinator.d.ts.map +1 -0
- package/dist/local-server/hitl-coordinator.js +33 -0
- package/dist/local-server/hitl-coordinator.js.map +1 -0
- package/dist/local-server/local-executor-session.d.ts +14 -0
- package/dist/local-server/local-executor-session.d.ts.map +1 -0
- package/dist/local-server/local-executor-session.js +49 -0
- package/dist/local-server/local-executor-session.js.map +1 -0
- package/dist/local-server/local-studio-server.d.ts +14 -0
- package/dist/local-server/local-studio-server.d.ts.map +1 -0
- package/dist/local-server/local-studio-server.js +290 -0
- package/dist/local-server/local-studio-server.js.map +1 -0
- package/dist/local-server/static-root.d.ts +8 -0
- package/dist/local-server/static-root.d.ts.map +1 -0
- package/dist/local-server/static-root.js +30 -0
- package/dist/local-server/static-root.js.map +1 -0
- package/dist/local-server/ws-protocol.d.ts +89 -0
- package/dist/local-server/ws-protocol.d.ts.map +1 -0
- package/dist/local-server/ws-protocol.js +8 -0
- package/dist/local-server/ws-protocol.js.map +1 -0
- package/dist/local-studio/assets/build.umd-BMMVnbyk.js +7 -0
- package/dist/local-studio/assets/index-B4zVqOUT.js +1 -0
- package/dist/local-studio/assets/index-CjYihVZf.js +1612 -0
- package/dist/local-studio/assets/index-url63DuJ.css +1 -0
- package/dist/{studio/assets/index.es-BY7s66E3.js → local-studio/assets/index.es-CNYpHgAn.js} +3 -3
- package/dist/local-studio/assets/jspdf.es.min-ZRtIKKtw.js +79 -0
- package/dist/local-studio/assets/purify.es-C0_7NiBM.js +2 -0
- package/dist/local-studio/index.html +27 -0
- package/dist/local-studio-entry.d.ts +14 -0
- package/dist/local-studio-entry.d.ts.map +1 -0
- package/dist/local-studio-entry.js +60 -0
- package/dist/local-studio-entry.js.map +1 -0
- package/dist/local-studio-placeholder/index.html +58 -0
- package/dist/mcp.d.ts +1 -2
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +17 -956
- package/dist/mcp.js.map +1 -1
- package/dist/models.d.ts +0 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js.map +1 -1
- package/dist/nest-proxy.d.ts +12 -0
- package/dist/nest-proxy.d.ts.map +1 -0
- package/dist/nest-proxy.js +69 -0
- package/dist/nest-proxy.js.map +1 -0
- package/dist/run-engine.d.ts +1 -22
- package/dist/run-engine.d.ts.map +1 -1
- package/dist/run-engine.js +5 -75
- package/dist/run-engine.js.map +1 -1
- package/dist/skills.d.ts +1 -3
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +19 -108
- package/dist/skills.js.map +1 -1
- package/dist/studio-server.d.ts.map +1 -1
- package/dist/studio-server.js +23 -0
- package/dist/studio-server.js.map +1 -1
- package/dist/workflow-template-apply.d.ts +0 -14
- package/dist/workflow-template-apply.d.ts.map +1 -1
- package/dist/workflow-template-apply.js +1 -64
- package/dist/workflow-template-apply.js.map +1 -1
- package/dist/workspace.d.ts +6 -118
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +63 -419
- package/dist/workspace.js.map +1 -1
- package/package.json +11 -7
- package/dist/studio/assets/index-5HXAsU4p.js +0 -74
- package/dist/studio/assets/index-B1aL7jAk.js +0 -57
- package/dist/studio/assets/index-B1uz6Ewl.css +0 -1
- package/dist/studio/assets/index-B2G_F__P.css +0 -1
- package/dist/studio/assets/index-BK6xaJ13.js +0 -96
- package/dist/studio/assets/index-BMhv4sXY.js +0 -96
- package/dist/studio/assets/index-BO2PmdDj.css +0 -1
- package/dist/studio/assets/index-B_0ldjZP.js +0 -96
- package/dist/studio/assets/index-Bbhu9ZEt.css +0 -1
- package/dist/studio/assets/index-BjW5ogyU.js +0 -96
- package/dist/studio/assets/index-Bt8hzNcU.js +0 -96
- package/dist/studio/assets/index-BzAnUkaS.js +0 -74
- package/dist/studio/assets/index-C0crAUM8.css +0 -1
- package/dist/studio/assets/index-CHc9YG3r.js +0 -112
- package/dist/studio/assets/index-CKtCWKy5.js +0 -96
- package/dist/studio/assets/index-CSIfnKun.css +0 -1
- package/dist/studio/assets/index-CXZmAIuY.js +0 -91
- package/dist/studio/assets/index-Cbvah-pg.js +0 -96
- package/dist/studio/assets/index-Cd1ymjRj.js +0 -96
- package/dist/studio/assets/index-CrMnnQO-.css +0 -1
- package/dist/studio/assets/index-D1J5_8Th.js +0 -91
- package/dist/studio/assets/index-DCT2826T.css +0 -1
- package/dist/studio/assets/index-DI1FMf0r.js +0 -57
- package/dist/studio/assets/index-DONQugvM.js +0 -96
- package/dist/studio/assets/index-DTK0SCwL.css +0 -1
- package/dist/studio/assets/index-DZpzYO63.js +0 -96
- package/dist/studio/assets/index-DmV3GQK3.css +0 -1
- package/dist/studio/assets/index-DmntCnBe.js +0 -96
- package/dist/studio/assets/index-DoIh_odG.js +0 -57
- package/dist/studio/assets/index-Dq9jftDf.js +0 -91
- package/dist/studio/assets/index-DvzphmLm.css +0 -1
- package/dist/studio/assets/index-SPD_jpsc.css +0 -1
- package/dist/studio/assets/index-ZiR_njv1.js +0 -96
- package/dist/studio/assets/index-ctxo2E0F.css +0 -1
- package/dist/studio/assets/index-fTm91Iph.css +0 -1
- package/dist/studio/assets/index-jQR0RL1o.js +0 -96
- package/dist/studio/assets/index-uHQLfD-r.css +0 -1
- package/dist/studio/assets/index.es-BCWxGaDy.js +0 -5
- package/dist/studio/assets/index.es-BPR3wmCH.js +0 -5
- package/dist/studio/assets/index.es-BW1yZSTk.js +0 -5
- package/dist/studio/assets/index.es-BgB1THzs.js +0 -5
- package/dist/studio/assets/index.es-C1dpmutL.js +0 -5
- package/dist/studio/assets/index.es-C4vElYon.js +0 -5
- package/dist/studio/assets/index.es-CA5y2tVx.js +0 -5
- package/dist/studio/assets/index.es-CJoNdv-d.js +0 -5
- package/dist/studio/assets/index.es-DJXBkJhb.js +0 -5
- package/dist/studio/assets/index.es-DhJ1KIdk.js +0 -5
- package/dist/studio/assets/index.es-DoO31ZM_.js +0 -5
- package/dist/studio/assets/index.es-Y3KhW381.js +0 -5
- package/dist/studio/assets/index.es-_wiJglk0.js +0 -5
- package/dist/studio/assets/index.es-dcgfUrS8.js +0 -5
- package/dist/studio/assets/index.es-j2tEOPI7.js +0 -5
- package/dist/studio/assets/index.es-zcnPOBL8.js +0 -5
- package/dist/studio/assets/jspdf.es.min-4bkGOR48.js +0 -79
- package/dist/studio/assets/jspdf.es.min-B3_vfH3S.js +0 -79
- package/dist/studio/assets/jspdf.es.min-B7A3pncP.js +0 -79
- package/dist/studio/assets/jspdf.es.min-B8ciqKwO.js +0 -79
- package/dist/studio/assets/jspdf.es.min-BWXErOTt.js +0 -79
- package/dist/studio/assets/jspdf.es.min-Be57pgIy.js +0 -79
- package/dist/studio/assets/jspdf.es.min-C-v2XVac.js +0 -79
- package/dist/studio/assets/jspdf.es.min-CTaJgZ0U.js +0 -79
- package/dist/studio/assets/jspdf.es.min-CeBUfwhn.js +0 -79
- package/dist/studio/assets/jspdf.es.min-Ctp5RK7Z.js +0 -79
- package/dist/studio/assets/jspdf.es.min-D4KCUvlV.js +0 -79
- package/dist/studio/assets/jspdf.es.min-DCNsC1_p.js +0 -79
- package/dist/studio/assets/jspdf.es.min-DMFDYk4G.js +0 -79
- package/dist/studio/assets/jspdf.es.min-DP4SG4JX.js +0 -79
- package/dist/studio/assets/jspdf.es.min-DmeLTeJx.js +0 -79
- package/dist/studio/assets/jspdf.es.min-DtNe0aer.js +0 -79
- package/dist/studio/assets/jspdf.es.min-SPz-8IlP.js +0 -79
- package/dist/studio/assets/purify.es-Bzr520pe.js +0 -2
- package/dist/studio/index.html +0 -14
- /package/dist/{studio → local-studio}/assets/html2canvas.esm-C5Fx4D8v.js +0 -0
- /package/dist/{studio → local-studio}/assets/html2canvas.esm-DXEQVQnt.js +0 -0
- /package/dist/{studio → local-studio}/assets/marked.esm-Brtrz5BF.js +0 -0
- /package/dist/{studio → local-studio}/favicon.png +0 -0
- /package/dist/{studio → local-studio}/icon-pixelized.png +0 -0
- /package/dist/{studio → local-studio}/icon-pixelized2.png +0 -0
- /package/dist/{studio → local-studio}/icon.jpg +0 -0
- /package/dist/{studio → local-studio}/vite.svg +0 -0
package/dist/cli.js
CHANGED
|
@@ -2,17 +2,14 @@
|
|
|
2
2
|
import { program } from "commander";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
|
-
import { ensureMinimalWorkspace,
|
|
5
|
+
import { ensureMinimalWorkspace, readWorkflowIndex, readWorkflowIndexOptional, writeWorkflowIndex, } from "./workspace.js";
|
|
6
6
|
import { getMergedConfig } from "./config.js";
|
|
7
|
-
import {
|
|
8
|
-
import { getNextStep, formatNextStepLine } from "./run-engine.js";
|
|
7
|
+
import { formatNextStepLine } from "./run-engine.js";
|
|
9
8
|
import { mergeKindTemplate } from "./kind-templates.js";
|
|
10
9
|
import { listWorkflowTemplates, listWorkflowTemplatesForPicker, materializeWorkflowTemplate } from "./workflow-templates.js";
|
|
11
|
-
import {
|
|
12
|
-
import { NodeResultStatus } from "./models.js";
|
|
10
|
+
import { applyWorkflowTemplateToCloud } from "./workflow-template-apply.js";
|
|
13
11
|
import { runMcpServer } from "./mcp.js";
|
|
14
|
-
import {
|
|
15
|
-
import { cloudCreateRun, cloudGetRun, cloudGetNext, cloudStartNode, cloudCompleteNode, cloudAppendEvents, mapCloudActionToLocal, isCloudMode, isCloudAuthenticated, getCloudApiUrl, cloudGetCurrentUser, resolveCloudOrganizationId, cloudListWorkflows, cloudCreateWorkflow, cloudCreateWorkflowFull, cloudCreateWorkflowVersion, cloudGetWorkflow, cloudGetWorkflowVersions, cloudGetWorkflowVersion, cloudListCollectionKinds, cloudGetCollectionItems, cloudSetCollectionSchema, } from "./cloud-client.js";
|
|
12
|
+
import { cloudCreateRun, cloudGetRun, cloudGetNext, cloudStartNode, cloudCompleteNode, cloudAppendEvents, mapCloudActionToCliAction, isCloudMode, isCloudAuthenticated, getCloudApiUrl, cloudGetCurrentUser, resolveCloudOrganizationId, cloudListWorkflows, cloudCreateWorkflow, cloudCreateWorkflowFull, cloudCreateWorkflowVersion, cloudGetWorkflow, cloudGetWorkflowVersions, cloudGetWorkflowVersion, cloudListCollectionKinds, cloudGetCollectionItems, cloudSetCollectionSchema, cloudGetCollectionSchema, } from "./cloud-client.js";
|
|
16
13
|
import { writeStoredApiKey, removeStoredApiKey, getApiKeyPath } from "./credentials.js";
|
|
17
14
|
import { runLoginFlow } from "./auth-login-server.js";
|
|
18
15
|
import open from "open";
|
|
@@ -66,13 +63,11 @@ import updateNotifier from "update-notifier";
|
|
|
66
63
|
import * as p from "@clack/prompts";
|
|
67
64
|
import { openCliDocsInBrowser } from "./cli-docs.js";
|
|
68
65
|
import { getCloudAppUrl, buildCloudOnboardingUrl } from "./onboarding-url.js";
|
|
66
|
+
import { runLocalStudioForeground, resolveLocalStudioBrowserBase } from "./local-studio-entry.js";
|
|
67
|
+
import { createLocalStudioServer } from "./local-server/local-studio-server.js";
|
|
68
|
+
import { resolveLocalStudioStaticRoot, localStudioBundleHasCliAuth } from "./local-server/static-root.js";
|
|
69
69
|
import { parsePayload, formatFromFilePath, stringifyPayload } from "./payload-parse.js";
|
|
70
70
|
const DEFAULT_BY = "cli";
|
|
71
|
-
function generateId(prefix) {
|
|
72
|
-
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
73
|
-
const rand = Math.random().toString(36).slice(2, 8);
|
|
74
|
-
return `${prefix}_${ts}_${rand}`;
|
|
75
|
-
}
|
|
76
71
|
async function resolveBy(cwd) {
|
|
77
72
|
const config = await getMergedConfig(cwd);
|
|
78
73
|
return config.default_by ?? DEFAULT_BY;
|
|
@@ -86,16 +81,11 @@ async function resolveCloudWorkflowId(cwd, optsWorkflow) {
|
|
|
86
81
|
const index = await readWorkflowIndexOptional(cwd);
|
|
87
82
|
return index?.cloud_current_workflow_id ?? null;
|
|
88
83
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return opts.cloud;
|
|
95
|
-
const index = await readWorkflowIndexOptional(cwd);
|
|
96
|
-
if (index?.preferred_mode === "local")
|
|
97
|
-
return false;
|
|
98
|
-
return isCloudMode();
|
|
84
|
+
async function requireCloudApiKey() {
|
|
85
|
+
if (!isCloudMode()) {
|
|
86
|
+
console.error("Error: Cloud API key required. Run `cognetivy auth login` or set COGNETIVY_API_KEY.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
99
89
|
}
|
|
100
90
|
/** Extract all unique collection names from nodes (input_collections + output_collections). */
|
|
101
91
|
function getCollectionNamesFromNodes(nodes) {
|
|
@@ -135,42 +125,59 @@ async function readPayloadFromFileOrStdin(filePath, cwd) {
|
|
|
135
125
|
}
|
|
136
126
|
return raw;
|
|
137
127
|
}
|
|
138
|
-
/** Launch local Studio server and open in browser (for local .cognetivy workspace). Optionally deep-link to a workflow. */
|
|
139
|
-
async function launchLocalStudio(workspacePath, port = STUDIO_DEFAULT_PORT, workflowId) {
|
|
140
|
-
await requireWorkspace(workspacePath);
|
|
141
|
-
const { port: actualPort } = await startStudioServer(workspacePath, port, { apiOnly: false });
|
|
142
|
-
const base = `http://127.0.0.1:${actualPort}`;
|
|
143
|
-
const url = workflowId ? `${base}/workflows/${encodeURIComponent(workflowId)}` : base;
|
|
144
|
-
await openUrl(url);
|
|
145
|
-
console.log(`Local Studio at ${base} (workspace: ${workspacePath}). Press Ctrl+C to stop.`);
|
|
146
|
-
}
|
|
147
128
|
const DEV_API_URL = "http://localhost:3000";
|
|
148
129
|
/** Local cloud-studio dev server; used for auth/login when --dev. */
|
|
149
130
|
const DEV_APP_URL = "http://localhost:5174";
|
|
150
131
|
program
|
|
151
132
|
.name("cognetivy")
|
|
152
|
-
.description("Cognetivy – workflows, runs, and collections. Default:
|
|
133
|
+
.description("Cognetivy – workflows, runs, and collections. Default: start the local studio backend (browser + executor). Use `cognetivy auth status` to check API key; `cognetivy auth login` to sign in and get an API key.")
|
|
153
134
|
.version(getCurrentVersionSync())
|
|
154
135
|
.option("--interface", "Open CLI reference in browser (same as `cognetivy docs`)")
|
|
155
|
-
.option("--dev", "
|
|
136
|
+
.option("--dev", "Point at local backend: API http://localhost:3000 and app http://localhost:5174. Opens the Vite dev studio (same port) with ?session=…; run `npm run dev` in cloud-studio first. Proxy /ws and /api/local to the CLI (see cloud-studio vite.config). Set COGNETIVY_USE_BUNDLED_STUDIO=1 to open the bundled UI on port 3848 instead.")
|
|
137
|
+
.option("--api-url <url>", "Backend API base for this run only (overrides COGNETIVY_API_URL). Local studio CLI auth uses this URL. Example: --api-url http://localhost:3000")
|
|
156
138
|
.addHelpText("after", `
|
|
157
139
|
Environment (cloud):
|
|
158
140
|
COGNETIVY_API_KEY API key for cloud run/event (create at app → Settings). When set, run/event use cloud by default.
|
|
159
141
|
COGNETIVY_APP_URL URL opened by default command (default: https://alpha.cognetivy.com).
|
|
160
|
-
COGNETIVY_API_URL
|
|
142
|
+
COGNETIVY_API_URL Backend API base (default: https://bm.cognetivy.com, or http://localhost:3000 when NODE_ENV=development / COGNETIVY_DEV=1). Local studio injects this into the page so /auth/cli/authorize matches the CLI token exchange.
|
|
143
|
+
|
|
144
|
+
Local studio (default command):
|
|
145
|
+
COGNETIVY_LOCAL_PORT Bind port for local HTTP + WebSocket (default: 3848).
|
|
146
|
+
COGNETIVY_LOCAL_STUDIO_URL Open this origin with ?session=… (e.g. http://localhost:5174 for Vite HMR). Vite proxies /ws and /api/local to the CLI. With cognetivy --dev, defaults to http://localhost:5174 unless set; COGNETIVY_USE_BUNDLED_STUDIO=1 opens the bundled UI on COGNETIVY_LOCAL_PORT instead.
|
|
147
|
+
COGNETIVY_OPEN_APP Set to 0 or false to skip opening the browser.
|
|
148
|
+
COGNETIVY_EXECUTOR_LOG Set to 0 or false to hide executor status lines on stderr (run phases, nodes, HITL; not agent tool output).
|
|
149
|
+
COGNETIVY_WORKFLOW_GENERATE_DEBUG Set to 1 — stderr diagnostics for “Generate workflow” (marker counts, combinedLog, parse/validation, cloud create timing).
|
|
150
|
+
COGNETIVY_WORKFLOW_GENERATE_HEARTBEAT_SEC Interval (seconds) for “agent still running …” lines while Generate workflow waits on the child (default 20; min 5).
|
|
151
|
+
COGNETIVY_CLAUDE_STREAM_JSON_IDLE_END_MS Claude stream-json: ms of stdout silence after a COGNETIVY_* payload marker before closing stdin (default 6000) if the CLI never sends a terminal result line.
|
|
152
|
+
COGNETIVY_AGENT_COMBINED_LOG_MAX_CHARS Max characters of merged agent stdout kept for marker parsing (default 1500000); when trimming, prefers retaining text from the last COGNETIVY_COLLECTION_JSON= / COGNETIVY_WORKFLOW_FILE_JSON=.
|
|
153
|
+
COGNETIVY_PARALLEL_ISOLATION copy (default) or none — per parallel PROMPT node, copy workspace into .cognetivy/exec-islands/<run>/<node>/ (skips node_modules, .git, dist, …) or share the parent cwd.
|
|
161
154
|
|
|
162
|
-
|
|
155
|
+
Examples: \`cognetivy --dev\` (local API), \`cognetivy --api-url http://127.0.0.1:3000\`. Use \`cognetivy auth status\` to see resolved URLs.
|
|
163
156
|
`);
|
|
164
157
|
program.hook("preAction", () => {
|
|
165
158
|
const opts = program.opts();
|
|
166
|
-
|
|
159
|
+
const trimmedApi = typeof opts.apiUrl === "string" ? opts.apiUrl.trim() : "";
|
|
160
|
+
if (trimmedApi) {
|
|
161
|
+
process.env.COGNETIVY_API_URL = trimmedApi.replace(/\/$/, "");
|
|
162
|
+
}
|
|
163
|
+
else if (opts.dev) {
|
|
167
164
|
process.env.COGNETIVY_API_URL = DEV_API_URL;
|
|
168
165
|
process.env.COGNETIVY_APP_URL = DEV_APP_URL;
|
|
166
|
+
const useBundledStudio = process.env.COGNETIVY_USE_BUNDLED_STUDIO === "1" ||
|
|
167
|
+
process.env.COGNETIVY_USE_BUNDLED_STUDIO === "true";
|
|
168
|
+
const existingStudioUrl = (process.env.COGNETIVY_LOCAL_STUDIO_URL ?? "").trim();
|
|
169
|
+
if (!useBundledStudio && !existingStudioUrl) {
|
|
170
|
+
process.env.COGNETIVY_LOCAL_STUDIO_URL = DEV_APP_URL;
|
|
171
|
+
}
|
|
169
172
|
}
|
|
170
173
|
});
|
|
171
174
|
const authCmd = program
|
|
172
175
|
.command("auth")
|
|
173
|
-
.description("Authentication and API key. Run with no subcommand to see: status, login, logout, whoami.")
|
|
176
|
+
.description("Authentication and API key. Run with no subcommand to see: status, login, logout, whoami.")
|
|
177
|
+
.addHelpText("after", `
|
|
178
|
+
For a local Nest API, put global options first: cognetivy --dev auth login
|
|
179
|
+
or: cognetivy --api-url http://localhost:3000 auth login
|
|
180
|
+
`);
|
|
174
181
|
authCmd
|
|
175
182
|
.command("status")
|
|
176
183
|
.description("Show whether cloud API key is set and which app/API URLs are used. Run with no options for human-readable output; use --json for machine-readable.")
|
|
@@ -203,7 +210,7 @@ authCmd
|
|
|
203
210
|
});
|
|
204
211
|
authCmd
|
|
205
212
|
.command("login")
|
|
206
|
-
.description("Open the app
|
|
213
|
+
.description("Open the app (or local studio) to sign in and authorize the CLI. Saves API key locally. Use cognetivy --dev auth login to use http://localhost:3000.")
|
|
207
214
|
.action(async () => {
|
|
208
215
|
const appUrl = getCloudAppUrl();
|
|
209
216
|
console.log("Opening browser to sign in and authorize the CLI…");
|
|
@@ -322,131 +329,21 @@ program
|
|
|
322
329
|
.command("init")
|
|
323
330
|
.description("Initialize .cognetivy workspace and run interactive skill installer (same as cognetivy install). Use --workspace-only to only create the workspace.")
|
|
324
331
|
.option("--no-gitignore", "Do not add .gitignore snippet for runs/events/collections")
|
|
325
|
-
.option("--force", "
|
|
332
|
+
.option("--force", "Passed to skill install when using the interactive installer (overwrite existing skills)")
|
|
326
333
|
.option("--workspace-only", "Only create .cognetivy workspace; do not prompt for skill installation")
|
|
327
334
|
.action(async (opts) => {
|
|
328
335
|
const cwd = process.cwd();
|
|
329
336
|
const noGitignore = opts.gitignore === false;
|
|
330
337
|
if (opts.workspaceOnly) {
|
|
331
|
-
await
|
|
338
|
+
await ensureMinimalWorkspace(cwd, { noGitignore });
|
|
332
339
|
console.log("Initialized cognetivy workspace at .cognetivy/");
|
|
333
340
|
return;
|
|
334
341
|
}
|
|
335
342
|
const { runInstallTUI } = await import("./install-tui.js");
|
|
336
343
|
await runInstallTUI({ cwd, force: opts.force, init: true, noGitignore });
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
.command("mode")
|
|
341
|
-
.description("Set or show default mode: Cloud (app + API) or Local (this machine only). Use with no options to switch interactively; --show for current state; --select for non-interactive.")
|
|
342
|
-
.option("--show", "Show current mode and workspace type (no prompt)")
|
|
343
|
-
.option("--json", "Output machine-readable JSON")
|
|
344
|
-
.option("--select <mode>", "Set mode without prompt (cloud | local). For scripts and tests.")
|
|
345
|
-
.action(async (opts) => {
|
|
346
|
-
const cwd = process.cwd();
|
|
347
|
-
const showOnly = opts.show === true || opts.json === true;
|
|
348
|
-
const selectMode = opts.select === "cloud" || opts.select === "local" ? opts.select : null;
|
|
349
|
-
const hadWorkspace = await workspaceExists(cwd);
|
|
350
|
-
if (!hadWorkspace) {
|
|
351
|
-
if (showOnly) {
|
|
352
|
-
if (opts.json) {
|
|
353
|
-
console.log(JSON.stringify({ preferred_mode: null, workspace: "none", cloud_authenticated: await isCloudAuthenticated() }));
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
console.log("No workspace. Run `cognetivy init` or `cognetivy mode` to create one and set mode.");
|
|
357
|
-
}
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
if (selectMode) {
|
|
361
|
-
if (selectMode === "cloud") {
|
|
362
|
-
await ensureMinimalWorkspace(cwd);
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
await ensureWorkspace(cwd, { force: false });
|
|
366
|
-
}
|
|
367
|
-
const indexAfter = await readWorkflowIndexOptional(cwd);
|
|
368
|
-
await writeWorkflowIndex({ ...(indexAfter ?? { current_workflow_id: "", workflows: [] }), preferred_mode: selectMode }, cwd);
|
|
369
|
-
console.log(`Default mode set to ${selectMode === "cloud" ? "Cloud" : "Local"}.`);
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
// Interactive with no workspace: do not create yet; create only after user chooses below
|
|
373
|
-
}
|
|
374
|
-
const index = await readWorkflowIndexOptional(cwd);
|
|
375
|
-
const preferredMode = index?.preferred_mode ?? null;
|
|
376
|
-
const cloudAuthenticated = await isCloudAuthenticated();
|
|
377
|
-
const minimal = await isWorkspaceMinimal(cwd);
|
|
378
|
-
if (showOnly) {
|
|
379
|
-
if (opts.json) {
|
|
380
|
-
console.log(JSON.stringify({
|
|
381
|
-
preferred_mode: preferredMode,
|
|
382
|
-
workspace: minimal ? "minimal" : "full",
|
|
383
|
-
cloud_authenticated: cloudAuthenticated,
|
|
384
|
-
}));
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
const modeLabel = preferredMode === "local" ? "Local" : preferredMode === "cloud" ? "Cloud" : isCloudMode() ? "Cloud (API key set)" : "Local (no API key)";
|
|
388
|
-
console.log(`Preferred mode: ${preferredMode ?? "not set"}`);
|
|
389
|
-
console.log(`Workspace: ${minimal ? "minimal (cloud-only)" : "full"}`);
|
|
390
|
-
console.log(`Cloud authenticated: ${cloudAuthenticated ? "yes" : "no"}`);
|
|
391
|
-
console.log(`Effective default: ${modeLabel}`);
|
|
392
|
-
}
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
if (selectMode) {
|
|
396
|
-
const base = index ?? { current_workflow_id: "wf_default", workflows: [] };
|
|
397
|
-
await writeWorkflowIndex({ ...base, preferred_mode: selectMode }, cwd);
|
|
398
|
-
if (selectMode === "local" && minimal) {
|
|
399
|
-
await ensureWorkspace(cwd, { force: false });
|
|
400
|
-
}
|
|
401
|
-
console.log(`Default mode set to ${selectMode === "cloud" ? "Cloud" : "Local"}.`);
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
if (!process.stdin.isTTY) {
|
|
405
|
-
console.error("Interactive terminal required. Use `cognetivy mode --show`, `cognetivy mode --json`, or `cognetivy mode --select <local|cloud>`.");
|
|
406
|
-
process.exit(1);
|
|
407
|
-
}
|
|
408
|
-
const currentLabel = preferredMode === "local"
|
|
409
|
-
? "Local"
|
|
410
|
-
: preferredMode === "cloud"
|
|
411
|
-
? cloudAuthenticated
|
|
412
|
-
? "Cloud (signed in)"
|
|
413
|
-
: "Cloud (preferred, not signed in)"
|
|
414
|
-
: isCloudMode()
|
|
415
|
-
? "Cloud (API key set)"
|
|
416
|
-
: "Local";
|
|
417
|
-
p.intro("cognetivy mode");
|
|
418
|
-
p.note(hadWorkspace ? `Current: ${currentLabel}. Workspace: ${minimal ? "minimal" : "full"}.` : "No workspace yet. Choose mode to create one.", "Current state");
|
|
419
|
-
p.note("Local: data stays in .cognetivy/ on this machine—you own it, view in Studio here.\nCloud: sign in once; view run status from anywhere (web or mobile browser) and work from anywhere.", "Local vs Cloud");
|
|
420
|
-
const choice = await p.select({
|
|
421
|
-
message: "Local or Cloud?",
|
|
422
|
-
options: [
|
|
423
|
-
{ value: "cloud", label: "Cloud", hint: "View run status from anywhere (web or mobile browser)" },
|
|
424
|
-
{ value: "local", label: "Local", hint: "Data in .cognetivy/ here; view in Studio on this machine" },
|
|
425
|
-
],
|
|
426
|
-
});
|
|
427
|
-
if (p.isCancel(choice)) {
|
|
428
|
-
p.cancel("Cancelled.");
|
|
429
|
-
process.exit(0);
|
|
430
|
-
}
|
|
431
|
-
const selected = choice;
|
|
432
|
-
if (!hadWorkspace) {
|
|
433
|
-
if (selected === "cloud") {
|
|
434
|
-
await ensureMinimalWorkspace(cwd);
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
await ensureWorkspace(cwd, { force: false });
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
const indexToWrite = await readWorkflowIndexOptional(cwd);
|
|
441
|
-
await writeWorkflowIndex({ ...(indexToWrite ?? { current_workflow_id: "", workflows: [] }), preferred_mode: selected }, cwd);
|
|
442
|
-
if (selected === "local" && (await isWorkspaceMinimal(cwd))) {
|
|
443
|
-
await ensureWorkspace(cwd, { force: false });
|
|
444
|
-
p.note("Full local workspace created (default workflow added).", "Local mode");
|
|
445
|
-
}
|
|
446
|
-
if (selected === "cloud" && !cloudAuthenticated) {
|
|
447
|
-
p.note("Run `cognetivy auth login` to sign in to the cloud.", "Tip");
|
|
448
|
-
}
|
|
449
|
-
p.outro(`Default mode set to ${selected === "cloud" ? "Cloud" : "Local"}.`);
|
|
344
|
+
const appUrl = getCloudAppUrl();
|
|
345
|
+
await openUrl(appUrl);
|
|
346
|
+
printOpenedUrlMessage(appUrl, { workflow: false });
|
|
450
347
|
});
|
|
451
348
|
const workflowCmd = program
|
|
452
349
|
.command("workflow")
|
|
@@ -463,61 +360,34 @@ function filterWorkflowsByQuery(items, q) {
|
|
|
463
360
|
}
|
|
464
361
|
workflowCmd
|
|
465
362
|
.command("list")
|
|
466
|
-
.description("List workflows (id, name, description only)
|
|
363
|
+
.description("List workflows (id, name, description only) from cloud. Add --q to filter by name/description.")
|
|
467
364
|
.option("--q <query>", "Filter by name or description (search)")
|
|
468
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
469
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
470
365
|
.action(async (opts) => {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const out = list.map((w) => ({ id: w.id, name: w.name, description: w.description ?? undefined }));
|
|
476
|
-
console.log(JSON.stringify(out, null, 2));
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
const cwd = process.cwd();
|
|
480
|
-
await requireWorkspace(cwd);
|
|
481
|
-
const workflows = await listWorkflows(cwd);
|
|
482
|
-
let out = workflows.map((w) => ({ id: w.workflow_id, name: w.name, description: w.description }));
|
|
483
|
-
if (opts.q)
|
|
484
|
-
out = filterWorkflowsByQuery(out, opts.q);
|
|
366
|
+
await requireCloudApiKey();
|
|
367
|
+
const orgId = await resolveCloudOrganizationId();
|
|
368
|
+
const list = await cloudListWorkflows(orgId, opts.q);
|
|
369
|
+
const out = list.map((w) => ({ id: w.id, name: w.name, description: w.description ?? undefined }));
|
|
485
370
|
console.log(JSON.stringify(out, null, 2));
|
|
486
371
|
});
|
|
487
372
|
workflowCmd
|
|
488
373
|
.command("search")
|
|
489
374
|
.description("Search workflows by name or description (id, name, description only). Use only when the user asks to list or search workflows.")
|
|
490
375
|
.option("--q <query>", "Search term (optional; omit to list all)")
|
|
491
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
492
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
493
376
|
.action(async (opts) => {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const out = list.map((w) => ({ id: w.id, name: w.name, description: w.description ?? undefined }));
|
|
499
|
-
console.log(JSON.stringify(out, null, 2));
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
const cwd = process.cwd();
|
|
503
|
-
await requireWorkspace(cwd);
|
|
504
|
-
const workflows = await listWorkflows(cwd);
|
|
505
|
-
let out = workflows.map((w) => ({ id: w.workflow_id, name: w.name, description: w.description }));
|
|
506
|
-
if (opts.q)
|
|
507
|
-
out = filterWorkflowsByQuery(out, opts.q);
|
|
377
|
+
await requireCloudApiKey();
|
|
378
|
+
const orgId = await resolveCloudOrganizationId();
|
|
379
|
+
const list = await cloudListWorkflows(orgId, opts.q);
|
|
380
|
+
const out = list.map((w) => ({ id: w.id, name: w.name, description: w.description ?? undefined }));
|
|
508
381
|
console.log(JSON.stringify(out, null, 2));
|
|
509
382
|
});
|
|
510
383
|
workflowCmd
|
|
511
384
|
.command("create")
|
|
512
|
-
.description("Create a new workflow. Use --name for an empty workflow; --file <path> or stdin
|
|
385
|
+
.description("Create a new workflow in cloud. Use --name for an empty workflow; --file <path> or stdin for one-call create with name/description/nodes/kinds.")
|
|
513
386
|
.option("--name <string>", "Workflow name (required if no --file and not reading from stdin; overrides file/stdin name if both)")
|
|
514
387
|
.option("--file <path>", "Path to JSON with name, description?, nodes?, kinds?; omit to read from stdin when --name not set)")
|
|
515
|
-
.option("--id <string>", "Workflow id (local only; default: generated)")
|
|
516
388
|
.option("--description <string>", "Workflow description (overrides file/stdin if both)")
|
|
517
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
518
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
519
389
|
.action(async (opts) => {
|
|
520
|
-
|
|
390
|
+
await requireCloudApiKey();
|
|
521
391
|
const cwd = process.cwd();
|
|
522
392
|
let raw;
|
|
523
393
|
if (opts.file) {
|
|
@@ -545,60 +415,21 @@ workflowCmd
|
|
|
545
415
|
process.exit(1);
|
|
546
416
|
}
|
|
547
417
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
organizationId: orgId,
|
|
552
|
-
name,
|
|
553
|
-
description,
|
|
554
|
-
nodes: nodes.length > 0 ? nodes : undefined,
|
|
555
|
-
kinds,
|
|
556
|
-
});
|
|
557
|
-
console.log(result.id);
|
|
558
|
-
if (result.versionId) {
|
|
559
|
-
console.error(`Version: ${result.versionId}`);
|
|
560
|
-
}
|
|
561
|
-
await ensureWorkspace(cwd);
|
|
562
|
-
const index = await readWorkflowIndex(cwd);
|
|
563
|
-
await writeWorkflowIndex({ ...index, cloud_current_workflow_id: result.id }, cwd);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
await requireWorkspace(cwd);
|
|
567
|
-
const id = opts.id ?? generateId("wf");
|
|
568
|
-
const now = new Date().toISOString();
|
|
569
|
-
const wf = {
|
|
570
|
-
workflow_id: id,
|
|
418
|
+
const orgId = await resolveCloudOrganizationId();
|
|
419
|
+
const result = await cloudCreateWorkflowFull({
|
|
420
|
+
organizationId: orgId,
|
|
571
421
|
name,
|
|
572
422
|
description,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
version_id: "v1",
|
|
580
|
-
name: "v1",
|
|
581
|
-
created_at: now,
|
|
582
|
-
nodes: nodes,
|
|
583
|
-
}, cwd);
|
|
584
|
-
if (kinds && Object.keys(kinds).length > 0) {
|
|
585
|
-
const merged = { workflow_id: id, kinds: {} };
|
|
586
|
-
for (const [k, v] of Object.entries(kinds)) {
|
|
587
|
-
merged.kinds[k] = mergeKindTemplate(k, v);
|
|
588
|
-
}
|
|
589
|
-
await writeCollectionSchema(id, merged, cwd);
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
const { createDefaultCollectionSchema } = await import("./default-collection-schema.js");
|
|
593
|
-
await writeCollectionSchema(id, createDefaultCollectionSchema(id), cwd);
|
|
423
|
+
nodes: nodes.length > 0 ? nodes : undefined,
|
|
424
|
+
kinds,
|
|
425
|
+
});
|
|
426
|
+
console.log(result.id);
|
|
427
|
+
if (result.versionId) {
|
|
428
|
+
console.error(`Version: ${result.versionId}`);
|
|
594
429
|
}
|
|
430
|
+
await ensureMinimalWorkspace(cwd);
|
|
595
431
|
const index = await readWorkflowIndex(cwd);
|
|
596
|
-
|
|
597
|
-
...index,
|
|
598
|
-
workflows: [...(index.workflows ?? []), { workflow_id: id, name: wf.name, description: wf.description, current_version_id: wf.current_version_id }],
|
|
599
|
-
};
|
|
600
|
-
await writeWorkflowIndex(next, cwd);
|
|
601
|
-
console.log(id);
|
|
432
|
+
await writeWorkflowIndex({ ...index, cloud_current_workflow_id: result.id }, cwd);
|
|
602
433
|
return;
|
|
603
434
|
}
|
|
604
435
|
const name = opts.name;
|
|
@@ -606,153 +437,88 @@ workflowCmd
|
|
|
606
437
|
console.error("Error: --name <string> is required when not using --file or stdin.");
|
|
607
438
|
process.exit(1);
|
|
608
439
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
organizationId: orgId,
|
|
613
|
-
name,
|
|
614
|
-
description: opts.description,
|
|
615
|
-
});
|
|
616
|
-
await cloudCreateWorkflowVersion(workflow.id, []);
|
|
617
|
-
console.log(workflow.id);
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
await requireWorkspace(cwd);
|
|
621
|
-
const id = opts.id ?? generateId("wf");
|
|
622
|
-
const now = new Date().toISOString();
|
|
623
|
-
const wf = {
|
|
624
|
-
workflow_id: id,
|
|
440
|
+
const orgId = await resolveCloudOrganizationId();
|
|
441
|
+
const workflow = await cloudCreateWorkflow({
|
|
442
|
+
organizationId: orgId,
|
|
625
443
|
name,
|
|
626
444
|
description: opts.description,
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
await writeWorkflowRecord(wf, cwd);
|
|
631
|
-
await writeWorkflowVersionRecord({
|
|
632
|
-
workflow_id: id,
|
|
633
|
-
version_id: "v1",
|
|
634
|
-
name: "v1",
|
|
635
|
-
created_at: now,
|
|
636
|
-
nodes: [],
|
|
637
|
-
}, cwd);
|
|
638
|
-
const { createDefaultCollectionSchema } = await import("./default-collection-schema.js");
|
|
639
|
-
await writeCollectionSchema(id, createDefaultCollectionSchema(id), cwd);
|
|
640
|
-
const index = await readWorkflowIndex(cwd);
|
|
641
|
-
const next = {
|
|
642
|
-
...index,
|
|
643
|
-
workflows: [...(index.workflows ?? []), { workflow_id: id, name: wf.name, description: wf.description, current_version_id: wf.current_version_id }],
|
|
644
|
-
};
|
|
645
|
-
await writeWorkflowIndex(next, cwd);
|
|
646
|
-
console.log(id);
|
|
445
|
+
});
|
|
446
|
+
await cloudCreateWorkflowVersion(workflow.id, []);
|
|
447
|
+
console.log(workflow.id);
|
|
647
448
|
});
|
|
648
449
|
workflowCmd
|
|
649
450
|
.command("select")
|
|
650
|
-
.description("
|
|
451
|
+
.description("Set default cloud workflow id in .cognetivy/workflows/index.json. Workflow must exist on the server.")
|
|
651
452
|
.requiredOption("--workflow <workflow_id>", "Workflow ID")
|
|
652
|
-
.option("--cloud", "Set as default workflow for cloud (persisted in index; workflow must exist on server)")
|
|
653
|
-
.option("--local", "Select from local workspace only (default if neither --cloud nor --local)")
|
|
654
453
|
.action(async (opts) => {
|
|
454
|
+
await requireCloudApiKey();
|
|
655
455
|
const cwd = process.cwd();
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
try {
|
|
659
|
-
await cloudGetWorkflow(opts.workflow);
|
|
660
|
-
}
|
|
661
|
-
catch {
|
|
662
|
-
console.error(`Error: workflow "${opts.workflow}" not found on server.`);
|
|
663
|
-
process.exit(1);
|
|
664
|
-
}
|
|
665
|
-
await ensureWorkspace(cwd);
|
|
666
|
-
const index = await readWorkflowIndex(cwd);
|
|
667
|
-
await writeWorkflowIndex({ ...index, cloud_current_workflow_id: opts.workflow }, cwd);
|
|
668
|
-
console.log(opts.workflow);
|
|
669
|
-
return;
|
|
456
|
+
try {
|
|
457
|
+
await cloudGetWorkflow(opts.workflow);
|
|
670
458
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if (!(index.workflows ?? []).some((w) => w.workflow_id === opts.workflow)) {
|
|
674
|
-
console.error(`Error: workflow "${opts.workflow}" not found.`);
|
|
459
|
+
catch {
|
|
460
|
+
console.error(`Error: workflow "${opts.workflow}" not found on server.`);
|
|
675
461
|
process.exit(1);
|
|
676
462
|
}
|
|
677
|
-
await
|
|
463
|
+
await ensureMinimalWorkspace(cwd);
|
|
464
|
+
const index = await readWorkflowIndex(cwd);
|
|
465
|
+
await writeWorkflowIndex({ ...index, cloud_current_workflow_id: opts.workflow }, cwd);
|
|
678
466
|
console.log(opts.workflow);
|
|
679
467
|
});
|
|
680
468
|
workflowCmd
|
|
681
469
|
.command("get")
|
|
682
470
|
.description("Print a workflow version (nodes, etc.). Default: --workflow/--version omitted uses current workflow and latest version. Use --output-format yaml for fewer tokens.")
|
|
683
|
-
.option("--workflow <workflow_id>", "Workflow ID (default:
|
|
684
|
-
.option("--version <version_id>", "Version ID (default: latest
|
|
471
|
+
.option("--workflow <workflow_id>", "Workflow ID (default: cloud_current_workflow_id or COGNETIVY_WORKFLOW_ID)")
|
|
472
|
+
.option("--version <version_id>", "Version ID (default: latest)")
|
|
685
473
|
.option("--output-format <format>", "Output format: json or yaml", "json")
|
|
686
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
687
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
688
474
|
.action(async (opts) => {
|
|
475
|
+
await requireCloudApiKey();
|
|
689
476
|
const cwd = process.cwd();
|
|
690
|
-
const
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
477
|
+
const workflowId = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
478
|
+
if (!workflowId) {
|
|
479
|
+
console.error("Error: --workflow <id>, COGNETIVY_WORKFLOW_ID, or `cognetivy workflow select --workflow <id>` is required.");
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
let versionId = opts.version;
|
|
483
|
+
if (!versionId) {
|
|
484
|
+
const versions = await cloudGetWorkflowVersions(workflowId);
|
|
485
|
+
versionId = versions[0]?.id;
|
|
698
486
|
if (!versionId) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (!versionId) {
|
|
702
|
-
console.error("No versions found for workflow.");
|
|
703
|
-
process.exit(1);
|
|
704
|
-
}
|
|
487
|
+
console.error("No versions found for workflow.");
|
|
488
|
+
process.exit(1);
|
|
705
489
|
}
|
|
706
|
-
const version = await cloudGetWorkflowVersion(workflowId, versionId);
|
|
707
|
-
const outFormat = opts.outputFormat === "yaml" ? "yaml" : "json";
|
|
708
|
-
console.log(stringifyPayload(version, outFormat));
|
|
709
|
-
return;
|
|
710
490
|
}
|
|
711
|
-
await
|
|
712
|
-
const index = await readWorkflowIndex(cwd);
|
|
713
|
-
const workflowId = opts.workflow ?? index.current_workflow_id;
|
|
714
|
-
const wf = await readWorkflowRecord(workflowId, cwd);
|
|
715
|
-
const versionId = opts.version ?? wf.current_version_id;
|
|
716
|
-
const version = await readWorkflowVersionRecord(workflowId, versionId, cwd);
|
|
491
|
+
const version = await cloudGetWorkflowVersion(workflowId, versionId);
|
|
717
492
|
const outFormat = opts.outputFormat === "yaml" ? "yaml" : "json";
|
|
718
493
|
console.log(stringifyPayload(version, outFormat));
|
|
719
494
|
});
|
|
720
495
|
workflowCmd
|
|
721
496
|
.command("versions")
|
|
722
|
-
.description("List versions for a workflow. Default: --workflow omitted uses current workflow (index or COGNETIVY_WORKFLOW_ID).
|
|
497
|
+
.description("List versions for a workflow. Default: --workflow omitted uses current workflow (index or COGNETIVY_WORKFLOW_ID).")
|
|
723
498
|
.option("--workflow <workflow_id>", "Workflow ID (default: current or COGNETIVY_WORKFLOW_ID)")
|
|
724
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
725
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
726
499
|
.action(async (opts) => {
|
|
500
|
+
await requireCloudApiKey();
|
|
727
501
|
const cwd = process.cwd();
|
|
728
|
-
const
|
|
729
|
-
if (
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
console.error("Error: In cloud mode --workflow <id>, COGNETIVY_WORKFLOW_ID, or run `cognetivy workflow select --workflow <id> --cloud` is required.");
|
|
733
|
-
process.exit(1);
|
|
734
|
-
}
|
|
735
|
-
const versions = await cloudGetWorkflowVersions(workflowId);
|
|
736
|
-
console.log(JSON.stringify(versions, null, 2));
|
|
737
|
-
return;
|
|
502
|
+
const workflowId = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
503
|
+
if (!workflowId) {
|
|
504
|
+
console.error("Error: --workflow <id>, COGNETIVY_WORKFLOW_ID, or `cognetivy workflow select --workflow <id>` is required.");
|
|
505
|
+
process.exit(1);
|
|
738
506
|
}
|
|
739
|
-
await
|
|
740
|
-
|
|
741
|
-
const workflowId = opts.workflow ?? index.current_workflow_id;
|
|
742
|
-
const ids = await listWorkflowVersionIds(workflowId, cwd);
|
|
743
|
-
console.log(JSON.stringify(ids, null, 2));
|
|
507
|
+
const versions = await cloudGetWorkflowVersions(workflowId);
|
|
508
|
+
console.log(JSON.stringify(versions, null, 2));
|
|
744
509
|
});
|
|
745
510
|
workflowCmd
|
|
746
511
|
.command("templates")
|
|
747
|
-
.description("List or pick workflow templates. With TTY: interactive picker then
|
|
512
|
+
.description("List or pick workflow templates. With TTY: interactive picker then create workflow in cloud. Use --list to print templates as JSON (no picker).")
|
|
748
513
|
.option("--list", "Print templates JSON instead of interactive picker")
|
|
749
514
|
.action(async (opts) => {
|
|
750
515
|
const cwd = process.cwd();
|
|
751
|
-
await
|
|
516
|
+
await ensureMinimalWorkspace(cwd);
|
|
752
517
|
if (opts.list || !process.stdin.isTTY) {
|
|
753
518
|
console.log(JSON.stringify(listWorkflowTemplates(), null, 2));
|
|
754
519
|
return;
|
|
755
520
|
}
|
|
521
|
+
await requireCloudApiKey();
|
|
756
522
|
const templates = listWorkflowTemplatesForPicker();
|
|
757
523
|
const picked = await p.select({
|
|
758
524
|
message: "Pick a workflow template",
|
|
@@ -767,16 +533,18 @@ workflowCmd
|
|
|
767
533
|
process.exit(0);
|
|
768
534
|
}
|
|
769
535
|
const templateId = picked;
|
|
770
|
-
const
|
|
771
|
-
|
|
536
|
+
const orgId = await resolveCloudOrganizationId();
|
|
537
|
+
const result = await applyWorkflowTemplateToCloud({ organizationId: orgId, templateId, cwd });
|
|
538
|
+
p.note(`Created workflow "${result.template.name}" (${result.workflowId}) in cloud.`, "Template applied");
|
|
772
539
|
console.log(JSON.stringify({
|
|
773
540
|
template_id: result.template.id,
|
|
774
|
-
workflow_id: result.
|
|
775
|
-
|
|
776
|
-
version_id: result.
|
|
541
|
+
workflow_id: result.workflowId,
|
|
542
|
+
cloud_current_workflow_id: result.workflowId,
|
|
543
|
+
version_id: result.versionId,
|
|
777
544
|
}, null, 2));
|
|
778
|
-
const
|
|
779
|
-
openUrl(
|
|
545
|
+
const appUrl = getCloudAppUrl();
|
|
546
|
+
await openUrl(appUrl);
|
|
547
|
+
printOpenedUrlMessage(appUrl, { workflow: true });
|
|
780
548
|
});
|
|
781
549
|
workflowCmd
|
|
782
550
|
.command("template")
|
|
@@ -792,14 +560,14 @@ workflowCmd
|
|
|
792
560
|
});
|
|
793
561
|
workflowCmd
|
|
794
562
|
.command("apply-template")
|
|
795
|
-
.description("
|
|
563
|
+
.description("Create a workflow in cloud from a built-in template. Use --id to skip picker; omit for interactive template choice.")
|
|
796
564
|
.option("--id <template_id>", "Template ID (omit for interactive picker)")
|
|
797
|
-
.option("--workflow <workflow_id>", "Workflow ID to create (default: wf_<template_id>)")
|
|
798
565
|
.option("--name <string>", "Optional workflow name override")
|
|
799
566
|
.option("--description <string>", "Optional workflow description override")
|
|
800
567
|
.action(async (opts) => {
|
|
568
|
+
await requireCloudApiKey();
|
|
801
569
|
const cwd = process.cwd();
|
|
802
|
-
await
|
|
570
|
+
await ensureMinimalWorkspace(cwd);
|
|
803
571
|
let templateId = opts.id;
|
|
804
572
|
if (!templateId) {
|
|
805
573
|
if (!process.stdin.isTTY) {
|
|
@@ -822,18 +590,19 @@ workflowCmd
|
|
|
822
590
|
templateId = picked;
|
|
823
591
|
}
|
|
824
592
|
try {
|
|
825
|
-
const
|
|
826
|
-
|
|
593
|
+
const orgId = await resolveCloudOrganizationId();
|
|
594
|
+
const result = await applyWorkflowTemplateToCloud({
|
|
595
|
+
organizationId: orgId,
|
|
827
596
|
templateId,
|
|
828
|
-
|
|
597
|
+
cwd,
|
|
829
598
|
workflowName: opts.name,
|
|
830
599
|
workflowDescription: opts.description,
|
|
831
600
|
});
|
|
832
601
|
console.log(JSON.stringify({
|
|
833
602
|
template_id: result.template.id,
|
|
834
|
-
workflow_id: result.
|
|
835
|
-
|
|
836
|
-
version_id: result.
|
|
603
|
+
workflow_id: result.workflowId,
|
|
604
|
+
cloud_current_workflow_id: result.workflowId,
|
|
605
|
+
version_id: result.versionId,
|
|
837
606
|
}, null, 2));
|
|
838
607
|
}
|
|
839
608
|
catch (err) {
|
|
@@ -843,80 +612,40 @@ workflowCmd
|
|
|
843
612
|
});
|
|
844
613
|
workflowCmd
|
|
845
614
|
.command("set")
|
|
846
|
-
.description("Set workflow version from file or stdin (creates new version). Use --file <path> or omit to read from stdin.
|
|
615
|
+
.description("Set workflow version from file or stdin (creates new version in cloud). Use --file <path> or omit to read from stdin.")
|
|
847
616
|
.option("--file <path>", "Path to workflow JSON file (must contain 'nodes' array); omit to read from stdin")
|
|
848
617
|
.option("--workflow <workflow_id>", "Workflow ID (default: current or COGNETIVY_WORKFLOW_ID)")
|
|
849
|
-
.option("--name <string>", "Optional version name (local only)")
|
|
850
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
851
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
852
618
|
.action(async (opts) => {
|
|
619
|
+
await requireCloudApiKey();
|
|
853
620
|
const cwd = process.cwd();
|
|
854
621
|
const raw = opts.file
|
|
855
622
|
? await fs.readFile(path.resolve(cwd, opts.file), "utf-8")
|
|
856
623
|
: await readPayloadFromFileOrStdin(undefined, cwd);
|
|
857
624
|
const format = opts.file ? formatFromFilePath(opts.file) : "auto";
|
|
858
625
|
const data = parsePayload(raw, format);
|
|
859
|
-
const
|
|
860
|
-
if (
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
console.error("Error: In cloud mode --workflow <id>, COGNETIVY_WORKFLOW_ID, or run `cognetivy workflow select --workflow <id> --cloud` is required.");
|
|
864
|
-
process.exit(1);
|
|
865
|
-
}
|
|
866
|
-
const nodes = Array.isArray(data?.nodes) ? data.nodes : [];
|
|
867
|
-
const version = await cloudCreateWorkflowVersion(workflowId, nodes);
|
|
868
|
-
console.log(version.id);
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
await requireWorkspace(cwd);
|
|
872
|
-
const index = await readWorkflowIndex(cwd);
|
|
873
|
-
const workflowId = opts.workflow ?? index.current_workflow_id;
|
|
874
|
-
const wf = await readWorkflowRecord(workflowId, cwd);
|
|
875
|
-
const existing = await listWorkflowVersionIds(workflowId, cwd);
|
|
876
|
-
const nums = existing.map((v) => parseInt(v.replace(/^v/, ""), 10)).filter((n) => !Number.isNaN(n));
|
|
877
|
-
const nextNum = Math.max(0, ...nums) + 1;
|
|
878
|
-
const newVersionId = `v${nextNum}`;
|
|
879
|
-
const dataRecord = data;
|
|
880
|
-
const version = {
|
|
881
|
-
...dataRecord,
|
|
882
|
-
workflow_id: workflowId,
|
|
883
|
-
version_id: newVersionId,
|
|
884
|
-
name: opts.name,
|
|
885
|
-
created_at: new Date().toISOString(),
|
|
886
|
-
nodes: Array.isArray(dataRecord.nodes) ? dataRecord.nodes : [],
|
|
887
|
-
};
|
|
888
|
-
validateWorkflowVersion(version);
|
|
889
|
-
// Measure change remaining-1: require collection schema presence when setting a version with nodes.
|
|
890
|
-
const referencedKinds = getCollectionNamesFromNodes(version.nodes ?? []);
|
|
891
|
-
if (referencedKinds.length > 0) {
|
|
892
|
-
const schema = await readCollectionSchema(workflowId, cwd);
|
|
893
|
-
const missing = referencedKinds.filter((k) => k !== "run_input" && (schema.kinds?.[k]?.item_schema == null));
|
|
894
|
-
if (missing.length > 0) {
|
|
895
|
-
console.error(`Error: Collection schema (kinds) is required for all collections referenced in nodes. Missing kinds for: ${missing.join(", ")}. Add a "kinds" entry for each kind before setting this workflow version.`);
|
|
896
|
-
process.exit(1);
|
|
897
|
-
}
|
|
626
|
+
const workflowId = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
627
|
+
if (!workflowId) {
|
|
628
|
+
console.error("Error: --workflow <id>, COGNETIVY_WORKFLOW_ID, or `cognetivy workflow select --workflow <id>` is required.");
|
|
629
|
+
process.exit(1);
|
|
898
630
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
await writeWorkflowIndex({ ...index, workflows }, cwd);
|
|
903
|
-
console.log(newVersionId);
|
|
631
|
+
const nodes = Array.isArray(data?.nodes) ? data.nodes : [];
|
|
632
|
+
const version = await cloudCreateWorkflowVersion(workflowId, nodes);
|
|
633
|
+
console.log(version.id);
|
|
904
634
|
});
|
|
905
635
|
const runCmd = program
|
|
906
636
|
.command("run")
|
|
907
637
|
.description("Run lifecycle: start, status, step, complete. Run with no subcommand to see all. Every response includes COGNETIVY_NEXT_STEP when a node is in progress.");
|
|
908
638
|
runCmd
|
|
909
639
|
.command("start")
|
|
910
|
-
.description("Start a new run. Requires --input <path>, --input -, or --input-inline <json>; and --name. Prints run_id and COGNETIVY_NEXT_STEP.
|
|
640
|
+
.description("Start a new run (cloud). Requires --input <path>, --input -, or --input-inline <json>; and --name. Prints run_id and COGNETIVY_NEXT_STEP.")
|
|
911
641
|
.option("--input <path>", "Path to JSON file with run input, or '-' to read from stdin")
|
|
912
642
|
.option("--input-inline <json>", "Run input as JSON string (alternative to --input; no file or stdin needed)")
|
|
913
643
|
.option("--name <string>", "Human-readable name for the run (e.g. 'Q1 ideas exploration')")
|
|
914
644
|
.option("--by <string>", "Actor (e.g. agent:cursor); defaults to config or 'cli'")
|
|
915
|
-
.option("--workflow <workflow_id>", "Workflow ID (default:
|
|
916
|
-
.option("--version <version_id>", "Workflow version ID (default:
|
|
917
|
-
.option("--cloud", "Use Cognetivy cloud API (default when COGNETIVY_API_KEY is set; see `cognetivy auth status`)")
|
|
918
|
-
.option("--local", "Use local .cognetivy workspace (overrides API key)")
|
|
645
|
+
.option("--workflow <workflow_id>", "Workflow ID (default: cloud_current_workflow_id or COGNETIVY_WORKFLOW_ID)")
|
|
646
|
+
.option("--version <version_id>", "Workflow version ID (default: latest on server)")
|
|
919
647
|
.action(async (opts) => {
|
|
648
|
+
await requireCloudApiKey();
|
|
920
649
|
const cwd = process.cwd();
|
|
921
650
|
if (!opts.input && !opts.inputInline) {
|
|
922
651
|
console.error("Error: Provide --input <path>, --input -, or --input-inline <json> for run input.");
|
|
@@ -943,488 +672,145 @@ runCmd
|
|
|
943
672
|
}
|
|
944
673
|
}
|
|
945
674
|
const input = parsePayload(inputRaw, "auto");
|
|
946
|
-
const
|
|
947
|
-
if (
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
968
|
-
process.exit(1);
|
|
969
|
-
}
|
|
970
|
-
return;
|
|
675
|
+
const workflowId = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
676
|
+
if (!workflowId) {
|
|
677
|
+
console.error("Error: --workflow <id>, COGNETIVY_WORKFLOW_ID, or `cognetivy workflow select --workflow <id>` is required.");
|
|
678
|
+
process.exit(1);
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
const result = await cloudCreateRun({
|
|
682
|
+
workflowId,
|
|
683
|
+
workflowVersionId: opts.version,
|
|
684
|
+
name: opts.name,
|
|
685
|
+
input,
|
|
686
|
+
});
|
|
687
|
+
console.log(result.run_id);
|
|
688
|
+
console.log(`COGNETIVY_RUN_ID=${result.run_id}`);
|
|
689
|
+
const next = result.next_step;
|
|
690
|
+
const action = mapCloudActionToCliAction(next.action);
|
|
691
|
+
console.log(formatNextStepLine(result.run_id, "RUNNING", { ...next, action }, result.current_node_id, result.current_node_ids));
|
|
692
|
+
}
|
|
693
|
+
catch (err) {
|
|
694
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
695
|
+
process.exit(1);
|
|
971
696
|
}
|
|
972
|
-
await requireWorkspace(cwd);
|
|
973
|
-
const index = await readWorkflowIndex(cwd);
|
|
974
|
-
const workflowId = opts.workflow ?? index.current_workflow_id;
|
|
975
|
-
const wf = await readWorkflowRecord(workflowId, cwd);
|
|
976
|
-
const versionId = opts.version ?? wf.current_version_id;
|
|
977
|
-
const runId = generateId("run");
|
|
978
|
-
const by = opts.by ?? (await resolveBy(cwd));
|
|
979
|
-
const now = new Date().toISOString();
|
|
980
|
-
const runRecord = {
|
|
981
|
-
run_id: runId,
|
|
982
|
-
...(opts.name && { name: opts.name }),
|
|
983
|
-
workflow_id: workflowId,
|
|
984
|
-
workflow_version_id: versionId,
|
|
985
|
-
status: "running",
|
|
986
|
-
input,
|
|
987
|
-
created_at: now,
|
|
988
|
-
};
|
|
989
|
-
await writeRunFile(runRecord, cwd);
|
|
990
|
-
const event = {
|
|
991
|
-
ts: now,
|
|
992
|
-
type: "run_started",
|
|
993
|
-
by,
|
|
994
|
-
data: { workflow_id: workflowId, workflow_version_id: versionId, input },
|
|
995
|
-
};
|
|
996
|
-
await appendEventLine(runId, event, cwd);
|
|
997
|
-
// Seed run_input collection item for collection→node flow.
|
|
998
|
-
const systemNodeId = "__system__";
|
|
999
|
-
const systemNodeResultId = generateId("node_result");
|
|
1000
|
-
const nodeResult = {
|
|
1001
|
-
node_result_id: systemNodeResultId,
|
|
1002
|
-
run_id: runId,
|
|
1003
|
-
workflow_id: workflowId,
|
|
1004
|
-
workflow_version_id: versionId,
|
|
1005
|
-
node_id: systemNodeId,
|
|
1006
|
-
status: NodeResultStatus.Completed,
|
|
1007
|
-
started_at: now,
|
|
1008
|
-
completed_at: now,
|
|
1009
|
-
output: JSON.stringify(input, null, 2),
|
|
1010
|
-
writes: [{ kind: "run_input", item_ids: ["run_input"] }],
|
|
1011
|
-
};
|
|
1012
|
-
await writeNodeResult(runId, systemNodeId, nodeResult, cwd);
|
|
1013
|
-
const runInputPayload = typeof input.name === "string" && input.name !== ""
|
|
1014
|
-
? input
|
|
1015
|
-
: { name: "Run input", ...input };
|
|
1016
|
-
await appendCollection(runId, "run_input", runInputPayload, { id: "run_input", created_by_node_id: systemNodeId, created_by_node_result_id: systemNodeResultId }, cwd);
|
|
1017
|
-
console.log(runId);
|
|
1018
|
-
console.log(`COGNETIVY_RUN_ID=${runId}`);
|
|
1019
|
-
let { next_step, current_node_id, current_node_ids } = await getNextStep(runId, cwd);
|
|
1020
|
-
if (next_step.action === "run_node" && next_step.node_id) {
|
|
1021
|
-
await appendEventLine(runId, { ts: now, type: "step_started", by, data: { step: next_step.node_id, step_id: next_step.node_id } }, cwd);
|
|
1022
|
-
await writeNodeResult(runId, next_step.node_id, {
|
|
1023
|
-
node_result_id: generateId("node_result"),
|
|
1024
|
-
run_id: runId,
|
|
1025
|
-
workflow_id: workflowId,
|
|
1026
|
-
workflow_version_id: versionId,
|
|
1027
|
-
node_id: next_step.node_id,
|
|
1028
|
-
status: NodeResultStatus.Started,
|
|
1029
|
-
started_at: now,
|
|
1030
|
-
}, cwd);
|
|
1031
|
-
const after = await getNextStep(runId, cwd);
|
|
1032
|
-
next_step = after.next_step;
|
|
1033
|
-
current_node_id = after.current_node_id;
|
|
1034
|
-
current_node_ids = after.current_node_ids;
|
|
1035
|
-
}
|
|
1036
|
-
console.log(formatNextStepLine(runId, "running", next_step, current_node_id, current_node_ids));
|
|
1037
697
|
});
|
|
1038
698
|
runCmd
|
|
1039
699
|
.command("complete")
|
|
1040
700
|
.description("Mark a run as completed (appends run_completed and persists status). Requires --run <id>. Run this after all nodes are done.")
|
|
1041
701
|
.requiredOption("--run <run_id>", "Run ID to mark complete")
|
|
1042
702
|
.action(async (opts) => {
|
|
703
|
+
await requireCloudApiKey();
|
|
1043
704
|
const cwd = process.cwd();
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
console.log(`Run "${opts.run}" marked as completed.`);
|
|
1052
|
-
console.log(formatNextStepLine(opts.run, run.status, { action: "done", hint: "Run finished." }));
|
|
1053
|
-
}
|
|
1054
|
-
catch (err) {
|
|
1055
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1056
|
-
process.exit(1);
|
|
1057
|
-
}
|
|
1058
|
-
return;
|
|
705
|
+
try {
|
|
706
|
+
await cloudAppendEvents(opts.run, {
|
|
707
|
+
events: [{ type: "run_completed", by: await resolveBy(cwd), data: {} }],
|
|
708
|
+
});
|
|
709
|
+
const run = await cloudGetRun(opts.run);
|
|
710
|
+
console.log(`Run "${opts.run}" marked as completed.`);
|
|
711
|
+
console.log(formatNextStepLine(opts.run, run.status, { action: "done", hint: "Run finished." }));
|
|
1059
712
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
713
|
+
catch (err) {
|
|
714
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1063
715
|
process.exit(1);
|
|
1064
716
|
}
|
|
1065
|
-
const by = await resolveBy(cwd);
|
|
1066
|
-
const now = new Date().toISOString();
|
|
1067
|
-
await appendEventLine(opts.run, { ts: now, type: "run_completed", by, data: {} }, cwd);
|
|
1068
|
-
await updateRunFile(opts.run, { status: "completed" }, cwd);
|
|
1069
|
-
console.log(`Run "${opts.run}" marked as completed.`);
|
|
1070
|
-
console.log(formatNextStepLine(opts.run, "completed", { action: "done", hint: "Run finished." }));
|
|
1071
717
|
});
|
|
1072
718
|
runCmd
|
|
1073
719
|
.command("status")
|
|
1074
|
-
.description("Show run metadata
|
|
720
|
+
.description("Show run metadata and next_step from cloud. Requires --run <id>. Use --json for machine-readable output.")
|
|
1075
721
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1076
722
|
.option("--json", "Output as JSON")
|
|
1077
|
-
.option("--cloud", "Use Cognetivy cloud API (default when COGNETIVY_API_KEY is set; see `cognetivy auth status`)")
|
|
1078
|
-
.option("--local", "Use local .cognetivy workspace (overrides API key)")
|
|
1079
723
|
.action(async (opts) => {
|
|
1080
|
-
|
|
1081
|
-
if (useCloud) {
|
|
1082
|
-
try {
|
|
1083
|
-
const [run, nextData] = await Promise.all([cloudGetRun(opts.run), cloudGetNext(opts.run)]);
|
|
1084
|
-
const next = nextData.next_step;
|
|
1085
|
-
const action = mapCloudActionToLocal(next.action);
|
|
1086
|
-
const next_step = { ...next, action };
|
|
1087
|
-
if (opts.json) {
|
|
1088
|
-
console.log(JSON.stringify({ run: { id: run.id, status: run.status, workflowId: run.workflowId }, next_step, current_node_id: nextData.current_node_id, current_node_ids: nextData.current_node_ids }, null, 2));
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
console.log("Run:", run.id, run.status, `(${run.workflowId})`);
|
|
1092
|
-
if (nextData.current_node_ids?.length)
|
|
1093
|
-
console.log("Current nodes (in progress):", nextData.current_node_ids.join(", "));
|
|
1094
|
-
else if (nextData.current_node_id)
|
|
1095
|
-
console.log("Current node (in progress):", nextData.current_node_id);
|
|
1096
|
-
console.log(formatNextStepLine(run.id, run.status, next_step, nextData.current_node_id, nextData.current_node_ids));
|
|
1097
|
-
}
|
|
1098
|
-
catch (err) {
|
|
1099
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1100
|
-
process.exit(1);
|
|
1101
|
-
}
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
const cwd = process.cwd();
|
|
1105
|
-
const exists = await runExists(opts.run, cwd);
|
|
1106
|
-
if (!exists) {
|
|
1107
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
1108
|
-
process.exit(1);
|
|
1109
|
-
}
|
|
1110
|
-
const run = await readRunFile(opts.run, cwd);
|
|
1111
|
-
let version = null;
|
|
724
|
+
await requireCloudApiKey();
|
|
1112
725
|
try {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
}
|
|
1126
|
-
const nodesList = [];
|
|
1127
|
-
if (version?.nodes) {
|
|
1128
|
-
for (const node of version.nodes) {
|
|
1129
|
-
const nr = nodeResultByNodeId.get(node.id);
|
|
1130
|
-
nodesList.push({
|
|
1131
|
-
node_id: node.id,
|
|
1132
|
-
status: nr?.status ?? "-",
|
|
1133
|
-
completed_at: nr?.completed_at,
|
|
1134
|
-
});
|
|
726
|
+
const [run, nextData] = await Promise.all([cloudGetRun(opts.run), cloudGetNext(opts.run)]);
|
|
727
|
+
const next = nextData.next_step;
|
|
728
|
+
const action = mapCloudActionToCliAction(next.action);
|
|
729
|
+
const next_step = { ...next, action };
|
|
730
|
+
if (opts.json) {
|
|
731
|
+
console.log(JSON.stringify({
|
|
732
|
+
run: { id: run.id, status: run.status, workflowId: run.workflowId },
|
|
733
|
+
next_step,
|
|
734
|
+
current_node_id: nextData.current_node_id,
|
|
735
|
+
current_node_ids: nextData.current_node_ids,
|
|
736
|
+
}, null, 2));
|
|
737
|
+
return;
|
|
1135
738
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
const nr = nodeResultByNodeId.get("__system__");
|
|
1140
|
-
nodesList.unshift({ node_id: "__system__", status: nr.status, completed_at: nr.completed_at });
|
|
1141
|
-
}
|
|
1142
|
-
const { next_step, current_node_id, current_node_ids } = await getNextStep(opts.run, cwd);
|
|
1143
|
-
const runSummary = {
|
|
1144
|
-
run_id: run.run_id,
|
|
1145
|
-
status: run.status,
|
|
1146
|
-
name: run.name,
|
|
1147
|
-
workflow_id: run.workflow_id,
|
|
1148
|
-
workflow_version_id: run.workflow_version_id,
|
|
1149
|
-
...(current_node_id !== undefined && { current_node_id, current_node_status: "in_progress" }),
|
|
1150
|
-
...(current_node_ids !== undefined && current_node_ids.length > 0 && { current_node_ids }),
|
|
1151
|
-
};
|
|
1152
|
-
if (opts.json) {
|
|
1153
|
-
console.log(JSON.stringify({ run: runSummary, nodes: nodesList, collections, next_step, ...(current_node_id !== undefined && { current_node_id }), ...(current_node_ids !== undefined && current_node_ids.length > 0 && { current_node_ids }) }, null, 2));
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
|
-
console.log("Run:", run.run_id, run.status, run.name ? `"${run.name}"` : "", `(${run.workflow_id} @ ${run.workflow_version_id})`);
|
|
1157
|
-
if (current_node_ids !== undefined && current_node_ids.length > 0) {
|
|
1158
|
-
console.log("Current nodes (in progress):", current_node_ids.join(", "));
|
|
1159
|
-
}
|
|
1160
|
-
else if (current_node_id !== undefined) {
|
|
1161
|
-
console.log("Current node (in progress):", current_node_id);
|
|
1162
|
-
}
|
|
1163
|
-
if (nodesList.length > 0) {
|
|
1164
|
-
console.log("Nodes:");
|
|
1165
|
-
for (const n of nodesList) {
|
|
1166
|
-
const at = n.completed_at ? ` @ ${n.completed_at}` : "";
|
|
1167
|
-
console.log(` ${n.node_id}: ${n.status}${at}`);
|
|
739
|
+
console.log("Run:", run.id, run.status, `(${run.workflowId})`);
|
|
740
|
+
if (nextData.current_node_ids?.length) {
|
|
741
|
+
console.log("Current nodes (in progress):", nextData.current_node_ids.join(", "));
|
|
1168
742
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
console.log("Nodes: (workflow version unavailable)");
|
|
1172
|
-
}
|
|
1173
|
-
if (collections.length > 0) {
|
|
1174
|
-
console.log("Collections:");
|
|
1175
|
-
for (const c of collections) {
|
|
1176
|
-
console.log(` ${c.kind}: ${c.item_count} item(s)`);
|
|
743
|
+
else if (nextData.current_node_id) {
|
|
744
|
+
console.log("Current node (in progress):", nextData.current_node_id);
|
|
1177
745
|
}
|
|
746
|
+
console.log(formatNextStepLine(run.id, run.status, next_step, nextData.current_node_id, nextData.current_node_ids));
|
|
747
|
+
}
|
|
748
|
+
catch (err) {
|
|
749
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
750
|
+
process.exit(1);
|
|
1178
751
|
}
|
|
1179
|
-
console.log(formatNextStepLine(run.run_id, run.status, next_step, current_node_id, current_node_ids));
|
|
1180
752
|
});
|
|
1181
753
|
runCmd
|
|
1182
754
|
.command("step")
|
|
1183
|
-
.description("Advance run: run with only --run <id> to start the next node; add --node <id> and --collection-kind with --collection-file <path> (or stdin) to complete a node.
|
|
755
|
+
.description("Advance run (cloud): run with only --run <id> to start the next node; add --node <id> and --collection-kind with --collection-file <path> (or stdin) to complete a node.")
|
|
1184
756
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1185
757
|
.option("--node <node_id>", "Node ID (required when completing a node with payload)")
|
|
1186
758
|
.option("--collection-kind <kind>", "Collection kind when completing node (payload from --collection-file or stdin)")
|
|
1187
|
-
.option("--collection-file <path>", "Path to JSON/YAML payload file (omit to read from stdin
|
|
1188
|
-
.option("--collection-mode <mode>", "set (array) or append (single object); default: infer", "infer")
|
|
1189
|
-
.option("--by <string>", "Actor; defaults to config or 'cli'")
|
|
1190
|
-
.option("--cloud", "Use Cognetivy cloud API (default when COGNETIVY_API_KEY is set; see `cognetivy auth status`)")
|
|
1191
|
-
.option("--local", "Use local .cognetivy workspace (overrides API key)")
|
|
759
|
+
.option("--collection-file <path>", "Path to JSON/YAML payload file (omit to read from stdin)")
|
|
1192
760
|
.action(async (opts) => {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
body.collectionPayload = parsePayload(raw, "auto");
|
|
1202
|
-
}
|
|
1203
|
-
const result = await cloudCompleteNode(opts.run, opts.node, body);
|
|
1204
|
-
const next = result.next_step;
|
|
1205
|
-
const action = mapCloudActionToLocal(next.action);
|
|
1206
|
-
console.log(formatNextStepLine(opts.run, "running", { ...next, action }, result.current_node_id, result.current_node_ids));
|
|
1207
|
-
}
|
|
1208
|
-
else {
|
|
1209
|
-
const nextData = await cloudGetNext(opts.run);
|
|
1210
|
-
const next = nextData.next_step;
|
|
1211
|
-
const action = mapCloudActionToLocal(next.action);
|
|
1212
|
-
if (action === "run_node" && next.node_id) {
|
|
1213
|
-
const result = await cloudStartNode(opts.run, next.node_id);
|
|
1214
|
-
const rNext = result.next_step;
|
|
1215
|
-
const rAction = mapCloudActionToLocal(rNext.action);
|
|
1216
|
-
console.log(formatNextStepLine(opts.run, "running", { ...rNext, action: rAction }, result.current_node_id, result.current_node_ids));
|
|
1217
|
-
}
|
|
1218
|
-
else if (action === "run_nodes_parallel" && next.runnable_node_ids?.length) {
|
|
1219
|
-
for (const nodeId of next.runnable_node_ids) {
|
|
1220
|
-
await cloudStartNode(opts.run, nodeId);
|
|
1221
|
-
}
|
|
1222
|
-
const after = await cloudGetNext(opts.run);
|
|
1223
|
-
const afterAction = mapCloudActionToLocal(after.next_step.action);
|
|
1224
|
-
console.log(formatNextStepLine(opts.run, "running", { ...after.next_step, action: afterAction }, after.current_node_id, after.current_node_ids));
|
|
1225
|
-
}
|
|
1226
|
-
else {
|
|
1227
|
-
console.log(formatNextStepLine(opts.run, "running", { ...next, action }, nextData.current_node_id, nextData.current_node_ids));
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
catch (err) {
|
|
1232
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1233
|
-
process.exit(1);
|
|
1234
|
-
}
|
|
1235
|
-
return;
|
|
1236
|
-
}
|
|
1237
|
-
const cwd = process.cwd();
|
|
1238
|
-
const exists = await runExists(opts.run, cwd);
|
|
1239
|
-
if (!exists) {
|
|
1240
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
1241
|
-
process.exit(1);
|
|
1242
|
-
}
|
|
1243
|
-
const run = await readRunFile(opts.run, cwd);
|
|
1244
|
-
if (run.status !== "running") {
|
|
1245
|
-
console.error(`Error: Run is not running (status: ${run.status}).`);
|
|
1246
|
-
process.exit(1);
|
|
1247
|
-
}
|
|
1248
|
-
const by = opts.by ?? (await resolveBy(cwd));
|
|
1249
|
-
const now = new Date().toISOString();
|
|
1250
|
-
if (opts.node !== undefined) {
|
|
1251
|
-
const nodeId = opts.node;
|
|
1252
|
-
const existingResult = await readNodeResult(opts.run, nodeId, cwd);
|
|
1253
|
-
// Replace semantics (B2): if this node was completed before and we are completing it again
|
|
1254
|
-
// with new collection output, delete the previous output items created by that node result.
|
|
1255
|
-
let priorItemIds = [];
|
|
1256
|
-
if (existingResult?.writes != null && Array.isArray(existingResult.writes)) {
|
|
1257
|
-
for (const w of existingResult.writes) {
|
|
1258
|
-
const itemIdsMaybe = w && typeof w === "object" ? w.item_ids : undefined;
|
|
1259
|
-
if (Array.isArray(itemIdsMaybe)) {
|
|
1260
|
-
for (const id of itemIdsMaybe) {
|
|
1261
|
-
if (typeof id === "string" && id.trim() !== "")
|
|
1262
|
-
priorItemIds.push(id);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
761
|
+
await requireCloudApiKey();
|
|
762
|
+
try {
|
|
763
|
+
if (opts.node !== undefined) {
|
|
764
|
+
const body = {};
|
|
765
|
+
if (opts.collectionKind) {
|
|
766
|
+
const raw = await readPayloadFromFileOrStdin(opts.collectionFile, process.cwd());
|
|
767
|
+
body.collectionKind = opts.collectionKind;
|
|
768
|
+
body.collectionPayload = parsePayload(raw, "auto");
|
|
1265
769
|
}
|
|
770
|
+
const result = await cloudCompleteNode(opts.run, opts.node, body);
|
|
771
|
+
const next = result.next_step;
|
|
772
|
+
const action = mapCloudActionToCliAction(next.action);
|
|
773
|
+
console.log(formatNextStepLine(opts.run, "running", { ...next, action }, result.current_node_id, result.current_node_ids));
|
|
1266
774
|
}
|
|
1267
|
-
|
|
1268
|
-
await
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
started_at: now,
|
|
1277
|
-
}, cwd);
|
|
1278
|
-
const { next_step: afterStep, current_node_id: afterCurrent, current_node_ids: afterIds } = await getNextStep(opts.run, cwd);
|
|
1279
|
-
const runAfter = await readRunFile(opts.run, cwd);
|
|
1280
|
-
console.log(formatNextStepLine(runAfter.run_id, runAfter.status, afterStep, afterCurrent, afterIds));
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
if (!existingResult || existingResult.status !== "started") {
|
|
1284
|
-
const startedAt = new Date().toISOString();
|
|
1285
|
-
await appendEventLine(opts.run, { ts: startedAt, type: "step_started", by, data: { step: nodeId, step_id: nodeId } }, cwd);
|
|
1286
|
-
await writeNodeResult(opts.run, nodeId, {
|
|
1287
|
-
node_result_id: generateId("node_result"),
|
|
1288
|
-
run_id: opts.run,
|
|
1289
|
-
workflow_id: run.workflow_id,
|
|
1290
|
-
workflow_version_id: run.workflow_version_id,
|
|
1291
|
-
node_id: nodeId,
|
|
1292
|
-
status: NodeResultStatus.Started,
|
|
1293
|
-
started_at: startedAt,
|
|
1294
|
-
}, cwd);
|
|
1295
|
-
}
|
|
1296
|
-
const nodeResultId = generateId("node_result");
|
|
1297
|
-
if (opts.collectionKind) {
|
|
1298
|
-
if (priorItemIds.length > 0) {
|
|
1299
|
-
await deleteCollectionItemsByIds(opts.run, priorItemIds, cwd);
|
|
775
|
+
else {
|
|
776
|
+
const nextData = await cloudGetNext(opts.run);
|
|
777
|
+
const next = nextData.next_step;
|
|
778
|
+
const action = mapCloudActionToCliAction(next.action);
|
|
779
|
+
if (action === "run_node" && next.node_id) {
|
|
780
|
+
const result = await cloudStartNode(opts.run, next.node_id);
|
|
781
|
+
const rNext = result.next_step;
|
|
782
|
+
const rAction = mapCloudActionToCliAction(rNext.action);
|
|
783
|
+
console.log(formatNextStepLine(opts.run, "running", { ...rNext, action: rAction }, result.current_node_id, result.current_node_ids));
|
|
1300
784
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1308
|
-
id: p.id ?? `${opts.collectionKind}_${i}`,
|
|
1309
|
-
}));
|
|
1310
|
-
await writeCollections(opts.run, opts.collectionKind, payloads, { created_by_node_id: nodeId, created_by_node_result_id: nodeResultId }, cwd);
|
|
1311
|
-
writes.push({ kind: opts.collectionKind, item_ids: payloads.map((p) => p.id) });
|
|
785
|
+
else if (action === "run_nodes_parallel" && next.runnable_node_ids?.length) {
|
|
786
|
+
for (const nodeId of next.runnable_node_ids) {
|
|
787
|
+
await cloudStartNode(opts.run, nodeId);
|
|
788
|
+
}
|
|
789
|
+
const after = await cloudGetNext(opts.run);
|
|
790
|
+
const afterAction = mapCloudActionToCliAction(after.next_step.action);
|
|
791
|
+
console.log(formatNextStepLine(opts.run, "running", { ...after.next_step, action: afterAction }, after.current_node_id, after.current_node_ids));
|
|
1312
792
|
}
|
|
1313
793
|
else {
|
|
1314
|
-
|
|
1315
|
-
writes.push({ kind: opts.collectionKind, item_ids: [item.id] });
|
|
794
|
+
console.log(formatNextStepLine(opts.run, "running", { ...next, action }, nextData.current_node_id, nextData.current_node_ids));
|
|
1316
795
|
}
|
|
1317
|
-
const result = {
|
|
1318
|
-
node_result_id: nodeResultId,
|
|
1319
|
-
run_id: opts.run,
|
|
1320
|
-
workflow_id: run.workflow_id,
|
|
1321
|
-
workflow_version_id: run.workflow_version_id,
|
|
1322
|
-
node_id: nodeId,
|
|
1323
|
-
status: NodeResultStatus.Completed,
|
|
1324
|
-
started_at: now,
|
|
1325
|
-
completed_at: now,
|
|
1326
|
-
writes,
|
|
1327
|
-
};
|
|
1328
|
-
await writeNodeResult(opts.run, nodeId, result, cwd);
|
|
1329
|
-
await appendEventLine(opts.run, { ts: now, type: "step_completed", by, data: { step: nodeId, step_id: nodeId } }, cwd);
|
|
1330
|
-
}
|
|
1331
|
-
else {
|
|
1332
|
-
await writeNodeResult(opts.run, nodeId, {
|
|
1333
|
-
node_result_id: nodeResultId,
|
|
1334
|
-
run_id: opts.run,
|
|
1335
|
-
workflow_id: run.workflow_id,
|
|
1336
|
-
workflow_version_id: run.workflow_version_id,
|
|
1337
|
-
node_id: nodeId,
|
|
1338
|
-
status: NodeResultStatus.Completed,
|
|
1339
|
-
started_at: now,
|
|
1340
|
-
completed_at: now,
|
|
1341
|
-
}, cwd);
|
|
1342
|
-
await appendEventLine(opts.run, { ts: now, type: "step_completed", by, data: { step: nodeId, step_id: nodeId } }, cwd);
|
|
1343
796
|
}
|
|
1344
797
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
if (ns.action === "run_nodes_parallel" && ns.runnable_node_ids?.length) {
|
|
1348
|
-
for (const nodeId of ns.runnable_node_ids) {
|
|
1349
|
-
const existing = await readNodeResult(opts.run, nodeId, cwd);
|
|
1350
|
-
if (!existing || existing.status !== NodeResultStatus.Started) {
|
|
1351
|
-
await appendEventLine(opts.run, { ts: now, type: "step_started", by, data: { step: nodeId, step_id: nodeId } }, cwd);
|
|
1352
|
-
await writeNodeResult(opts.run, nodeId, {
|
|
1353
|
-
node_result_id: generateId("node_result"),
|
|
1354
|
-
run_id: opts.run,
|
|
1355
|
-
workflow_id: run.workflow_id,
|
|
1356
|
-
workflow_version_id: run.workflow_version_id,
|
|
1357
|
-
node_id: nodeId,
|
|
1358
|
-
status: NodeResultStatus.Started,
|
|
1359
|
-
started_at: now,
|
|
1360
|
-
}, cwd);
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
const runAfter = await readRunFile(opts.run, cwd);
|
|
1364
|
-
console.log(formatNextStepLine(runAfter.run_id, runAfter.status, ns, undefined, ns.runnable_node_ids));
|
|
1365
|
-
return;
|
|
1366
|
-
}
|
|
1367
|
-
if (ns.action === "run_node" && ns.node_id) {
|
|
1368
|
-
const nodeResultId = generateId("node_result");
|
|
1369
|
-
await appendEventLine(opts.run, { ts: now, type: "step_started", by, data: { step: ns.node_id, step_id: ns.node_id } }, cwd);
|
|
1370
|
-
await writeNodeResult(opts.run, ns.node_id, {
|
|
1371
|
-
node_result_id: nodeResultId,
|
|
1372
|
-
run_id: opts.run,
|
|
1373
|
-
workflow_id: run.workflow_id,
|
|
1374
|
-
workflow_version_id: run.workflow_version_id,
|
|
1375
|
-
node_id: ns.node_id,
|
|
1376
|
-
status: NodeResultStatus.Started,
|
|
1377
|
-
started_at: now,
|
|
1378
|
-
}, cwd);
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
let { next_step, current_node_id, current_node_ids } = await getNextStep(opts.run, cwd);
|
|
1382
|
-
if (next_step.action === "run_node" && next_step.node_id) {
|
|
1383
|
-
await appendEventLine(opts.run, { ts: now, type: "step_started", by, data: { step: next_step.node_id, step_id: next_step.node_id } }, cwd);
|
|
1384
|
-
await writeNodeResult(opts.run, next_step.node_id, {
|
|
1385
|
-
node_result_id: generateId("node_result"),
|
|
1386
|
-
run_id: opts.run,
|
|
1387
|
-
workflow_id: run.workflow_id,
|
|
1388
|
-
workflow_version_id: run.workflow_version_id,
|
|
1389
|
-
node_id: next_step.node_id,
|
|
1390
|
-
status: NodeResultStatus.Started,
|
|
1391
|
-
started_at: now,
|
|
1392
|
-
}, cwd);
|
|
1393
|
-
const after = await getNextStep(opts.run, cwd);
|
|
1394
|
-
next_step = after.next_step;
|
|
1395
|
-
current_node_id = after.current_node_id;
|
|
1396
|
-
current_node_ids = after.current_node_ids;
|
|
1397
|
-
}
|
|
1398
|
-
const runAfter = await readRunFile(opts.run, cwd);
|
|
1399
|
-
console.log(formatNextStepLine(runAfter.run_id, runAfter.status, next_step, current_node_id, current_node_ids));
|
|
1400
|
-
});
|
|
1401
|
-
runCmd
|
|
1402
|
-
.command("set-name")
|
|
1403
|
-
.description("Set or update the human-readable name for an existing run. Requires --run <id> and --name <string>.")
|
|
1404
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1405
|
-
.requiredOption("--name <string>", "Name for the run")
|
|
1406
|
-
.action(async (opts) => {
|
|
1407
|
-
const cwd = process.cwd();
|
|
1408
|
-
const exists = await runExists(opts.run, cwd);
|
|
1409
|
-
if (!exists) {
|
|
1410
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
798
|
+
catch (err) {
|
|
799
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1411
800
|
process.exit(1);
|
|
1412
801
|
}
|
|
1413
|
-
await updateRunFile(opts.run, { name: opts.name }, cwd);
|
|
1414
|
-
console.log(`Run "${opts.run}" named "${opts.name}".`);
|
|
1415
802
|
});
|
|
1416
803
|
const eventCmd = program
|
|
1417
804
|
.command("event")
|
|
1418
805
|
.description("Event log operations (low-level). Run with no subcommand to see: append. Prefer run complete for ending runs.");
|
|
1419
806
|
eventCmd
|
|
1420
807
|
.command("append")
|
|
1421
|
-
.description("Append one event to run's log. Omit --file to read JSON from stdin. For run_completed, prefer 'cognetivy run complete --run <id>'
|
|
808
|
+
.description("Append one event to run's log (cloud). Omit --file to read JSON from stdin. For run_completed, prefer 'cognetivy run complete --run <id>'.")
|
|
1422
809
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1423
810
|
.option("--file <path>", "Path to JSON file (omit to read event from stdin)")
|
|
1424
811
|
.option("--by <string>", "Actor; defaults to config or 'cli'")
|
|
1425
|
-
.option("--cloud", "Use Cognetivy cloud API (default when COGNETIVY_API_KEY is set; see `cognetivy auth status`)")
|
|
1426
|
-
.option("--local", "Use local .cognetivy workspace (overrides API key)")
|
|
1427
812
|
.action(async (opts) => {
|
|
813
|
+
await requireCloudApiKey();
|
|
1428
814
|
const cwd = process.cwd();
|
|
1429
815
|
const raw = await readPayloadFromFileOrStdin(opts.file, cwd);
|
|
1430
816
|
const format = opts.file ? formatFromFilePath(opts.file) : "auto";
|
|
@@ -1437,57 +823,43 @@ eventCmd
|
|
|
1437
823
|
by: data.by ?? by,
|
|
1438
824
|
data: data.data ?? data,
|
|
1439
825
|
};
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
});
|
|
1446
|
-
console.log(`Appended ${result.appended} event(s).`);
|
|
1447
|
-
}
|
|
1448
|
-
catch (err) {
|
|
1449
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1450
|
-
process.exit(1);
|
|
1451
|
-
}
|
|
1452
|
-
return;
|
|
826
|
+
try {
|
|
827
|
+
const result = await cloudAppendEvents(opts.run, {
|
|
828
|
+
events: [{ type: event.type, by: event.by, data: event.data }],
|
|
829
|
+
});
|
|
830
|
+
console.log(`Appended ${result.appended} event(s).`);
|
|
1453
831
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
console.error(`Error: Run "${opts.run}" not found. Run \`cognetivy run start\` first.`);
|
|
832
|
+
catch (err) {
|
|
833
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1457
834
|
process.exit(1);
|
|
1458
835
|
}
|
|
1459
|
-
await appendEventLine(opts.run, event, cwd);
|
|
1460
|
-
if (event.type === "run_completed") {
|
|
1461
|
-
await updateRunFile(opts.run, { status: "completed" }, cwd);
|
|
1462
|
-
}
|
|
1463
|
-
console.log("Appended event.");
|
|
1464
836
|
});
|
|
1465
837
|
const collectionSchemaCmd = program
|
|
1466
838
|
.command("collection-schema")
|
|
1467
839
|
.description("Collection schema (workflow-scoped; kinds and item_schema). Used when creating/editing workflows; run get/set with --workflow.");
|
|
1468
840
|
collectionSchemaCmd
|
|
1469
841
|
.command("get")
|
|
1470
|
-
.description("Print collection schema JSON for a workflow. Use --run to resolve workflow from a run; --kind to print only one kind.")
|
|
1471
|
-
.option("--workflow <workflow_id>", "Workflow ID (default:
|
|
842
|
+
.description("Print collection schema JSON for a workflow (cloud). Use --run to resolve workflow from a run; --kind to print only one kind.")
|
|
843
|
+
.option("--workflow <workflow_id>", "Workflow ID (default: cloud_current_workflow_id or COGNETIVY_WORKFLOW_ID)")
|
|
1472
844
|
.option("--run <run_id>", "Run ID (resolve workflow from this run; overrides --workflow)")
|
|
1473
845
|
.option("--kind <kind>", "Print only this collection kind's schema")
|
|
1474
846
|
.action(async (opts) => {
|
|
847
|
+
await requireCloudApiKey();
|
|
1475
848
|
const cwd = process.cwd();
|
|
1476
|
-
await requireWorkspace(cwd);
|
|
1477
849
|
let workflowId;
|
|
1478
850
|
if (opts.run) {
|
|
1479
|
-
const run = await
|
|
1480
|
-
workflowId = run.
|
|
851
|
+
const run = await cloudGetRun(opts.run);
|
|
852
|
+
workflowId = run.workflowId;
|
|
1481
853
|
}
|
|
1482
854
|
else {
|
|
1483
|
-
const
|
|
1484
|
-
workflowId =
|
|
855
|
+
const resolved = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
856
|
+
workflowId = resolved ?? "";
|
|
1485
857
|
}
|
|
1486
858
|
if (!workflowId) {
|
|
1487
|
-
console.error("Error: specify --workflow <id>, --run <run_id>, or set
|
|
859
|
+
console.error("Error: specify --workflow <id>, --run <run_id>, or set default with workflow select.");
|
|
1488
860
|
process.exit(1);
|
|
1489
861
|
}
|
|
1490
|
-
const schema = await
|
|
862
|
+
const schema = await cloudGetCollectionSchema(workflowId);
|
|
1491
863
|
if (opts.kind) {
|
|
1492
864
|
const kindSchema = schema.kinds?.[opts.kind];
|
|
1493
865
|
if (kindSchema == null) {
|
|
@@ -1502,12 +874,11 @@ collectionSchemaCmd
|
|
|
1502
874
|
});
|
|
1503
875
|
collectionSchemaCmd
|
|
1504
876
|
.command("set")
|
|
1505
|
-
.description("Set collection schema from JSON file. Requires --file <path>.
|
|
877
|
+
.description("Set collection schema from JSON file (cloud). Requires --file <path>.")
|
|
1506
878
|
.requiredOption("--file <path>", "Path to collection-schema JSON file")
|
|
1507
|
-
.option("--workflow <workflow_id>", "Workflow ID (default: current
|
|
1508
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
1509
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
879
|
+
.option("--workflow <workflow_id>", "Workflow ID (default: current cloud workflow)")
|
|
1510
880
|
.action(async (opts) => {
|
|
881
|
+
await requireCloudApiKey();
|
|
1511
882
|
const cwd = process.cwd();
|
|
1512
883
|
const raw = await fs.readFile(path.resolve(cwd, opts.file), "utf-8");
|
|
1513
884
|
const schema = parsePayload(raw, formatFromFilePath(opts.file));
|
|
@@ -1515,340 +886,160 @@ collectionSchemaCmd
|
|
|
1515
886
|
console.error("Error: schema must have a 'kinds' object.");
|
|
1516
887
|
process.exit(1);
|
|
1517
888
|
}
|
|
1518
|
-
const
|
|
1519
|
-
if (
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
console.error("Error: In cloud mode --workflow <id>, COGNETIVY_WORKFLOW_ID, or run `cognetivy workflow select --workflow <id> --cloud` is required.");
|
|
1523
|
-
process.exit(1);
|
|
1524
|
-
}
|
|
1525
|
-
const kinds = {};
|
|
1526
|
-
for (const [k, v] of Object.entries(schema.kinds)) {
|
|
1527
|
-
const merged = mergeKindTemplate(k, v);
|
|
1528
|
-
kinds[k] = { name: merged.name, description: merged.description, item_schema: merged.item_schema };
|
|
1529
|
-
}
|
|
1530
|
-
await cloudSetCollectionSchema(workflowId, kinds);
|
|
1531
|
-
console.log("Collection schema updated.");
|
|
1532
|
-
return;
|
|
889
|
+
const workflowId = await resolveCloudWorkflowId(cwd, opts.workflow);
|
|
890
|
+
if (!workflowId) {
|
|
891
|
+
console.error("Error: --workflow <id>, COGNETIVY_WORKFLOW_ID, or `cognetivy workflow select --workflow <id>` is required.");
|
|
892
|
+
process.exit(1);
|
|
1533
893
|
}
|
|
1534
|
-
|
|
1535
|
-
const index = await readWorkflowIndex(cwd);
|
|
1536
|
-
const workflowId = opts.workflow ?? index.current_workflow_id;
|
|
1537
|
-
const merged = { workflow_id: workflowId, kinds: {} };
|
|
894
|
+
const kinds = {};
|
|
1538
895
|
for (const [k, v] of Object.entries(schema.kinds)) {
|
|
1539
|
-
merged
|
|
896
|
+
const merged = mergeKindTemplate(k, v);
|
|
897
|
+
kinds[k] = { name: merged.name, description: merged.description, item_schema: merged.item_schema };
|
|
1540
898
|
}
|
|
1541
|
-
await
|
|
899
|
+
await cloudSetCollectionSchema(workflowId, kinds);
|
|
1542
900
|
console.log("Collection schema updated.");
|
|
1543
901
|
});
|
|
1544
902
|
const collectionCmd = program
|
|
1545
903
|
.command("collection")
|
|
1546
|
-
.description("Structured collections per run (
|
|
904
|
+
.description("Structured collections per run (cloud). Subcommands: list, get.");
|
|
1547
905
|
collectionCmd
|
|
1548
906
|
.command("list")
|
|
1549
|
-
.description("List collection kinds that have data for a run. Requires --run <id>.
|
|
907
|
+
.description("List collection kinds that have data for a run. Requires --run <id>.")
|
|
1550
908
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1551
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
1552
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
1553
909
|
.action(async (opts) => {
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1563
|
-
process.exit(1);
|
|
1564
|
-
}
|
|
1565
|
-
return;
|
|
910
|
+
await requireCloudApiKey();
|
|
911
|
+
try {
|
|
912
|
+
const result = await cloudListCollectionKinds(opts.run);
|
|
913
|
+
console.log(JSON.stringify(result.kinds, null, 2));
|
|
914
|
+
}
|
|
915
|
+
catch (err) {
|
|
916
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
917
|
+
process.exit(1);
|
|
1566
918
|
}
|
|
1567
|
-
const kinds = await listCollectionKindsForRun(opts.run, cwd);
|
|
1568
|
-
console.log(JSON.stringify(kinds, null, 2));
|
|
1569
919
|
});
|
|
1570
920
|
collectionCmd
|
|
1571
921
|
.command("get")
|
|
1572
|
-
.description("Get all items of a collection kind for a run. Requires --run <id> and --kind or --collection
|
|
922
|
+
.description("Get all items of a collection kind for a run. Requires --run <id> and --kind or --collection.")
|
|
1573
923
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1574
|
-
.option("--kind <kind>", "Collection kind (e.g. sources,
|
|
924
|
+
.option("--kind <kind>", "Collection kind (e.g. sources, run_input)")
|
|
1575
925
|
.option("--collection <kind>", "Collection kind (alias for --kind)")
|
|
1576
|
-
.option("--cloud", "Use Cognetivy cloud API (default when API key is set)")
|
|
1577
|
-
.option("--local", "Use local .cognetivy workspace only")
|
|
1578
926
|
.action(async (opts) => {
|
|
927
|
+
await requireCloudApiKey();
|
|
1579
928
|
const kind = opts.kind ?? opts.collection;
|
|
1580
929
|
if (!kind) {
|
|
1581
930
|
console.error("Error: required option --kind <kind> or --collection <kind> not specified.");
|
|
1582
931
|
process.exit(1);
|
|
1583
932
|
}
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
try {
|
|
1588
|
-
const result = await cloudGetCollectionItems(opts.run, kind);
|
|
1589
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1590
|
-
}
|
|
1591
|
-
catch (err) {
|
|
1592
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1593
|
-
process.exit(1);
|
|
1594
|
-
}
|
|
1595
|
-
return;
|
|
1596
|
-
}
|
|
1597
|
-
const store = await readCollections(opts.run, kind, cwd);
|
|
1598
|
-
console.log(JSON.stringify(store, null, 2));
|
|
1599
|
-
});
|
|
1600
|
-
collectionCmd
|
|
1601
|
-
.command("set")
|
|
1602
|
-
.description("Replace all items of a kind for a run. Requires --run, --kind, --node, --node-result. Omit --file to read from stdin.")
|
|
1603
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1604
|
-
.requiredOption("--kind <kind>", "Collection kind")
|
|
1605
|
-
.option("--file <path>", "Path to JSON file (omit to read array from stdin)")
|
|
1606
|
-
.requiredOption("--node <node_id>", "Node id that created these items")
|
|
1607
|
-
.requiredOption("--node-result <node_result_id>", "Node result id that created these items")
|
|
1608
|
-
.action(async (opts) => {
|
|
1609
|
-
const cwd = process.cwd();
|
|
1610
|
-
const raw = await readPayloadFromFileOrStdin(opts.file, cwd);
|
|
1611
|
-
const format = opts.file ? formatFromFilePath(opts.file) : "auto";
|
|
1612
|
-
const payloads = parsePayload(raw, format);
|
|
1613
|
-
if (!Array.isArray(payloads)) {
|
|
1614
|
-
console.error("Error: file must contain a JSON or YAML array of collection items.");
|
|
1615
|
-
process.exit(1);
|
|
1616
|
-
}
|
|
1617
|
-
await writeCollections(opts.run, opts.kind, payloads, { created_by_node_id: opts.node, created_by_node_result_id: opts.nodeResult }, cwd);
|
|
1618
|
-
console.log(`Set ${payloads.length} collection(s) for kind "${opts.kind}".`);
|
|
1619
|
-
});
|
|
1620
|
-
collectionCmd
|
|
1621
|
-
.command("append")
|
|
1622
|
-
.description("Append one collection item to a run's kind. Requires --run, --kind, --node, --node-result. Omit --file to read from stdin.")
|
|
1623
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1624
|
-
.requiredOption("--kind <kind>", "Collection kind")
|
|
1625
|
-
.option("--file <path>", "Path to JSON file (omit to read payload from stdin)")
|
|
1626
|
-
.requiredOption("--node <node_id>", "Node id that created this item")
|
|
1627
|
-
.requiredOption("--node-result <node_result_id>", "Node result id that created this item")
|
|
1628
|
-
.option("--id <string>", "Optional collection id")
|
|
1629
|
-
.action(async (opts) => {
|
|
1630
|
-
const cwd = process.cwd();
|
|
1631
|
-
const raw = await readPayloadFromFileOrStdin(opts.file, cwd);
|
|
1632
|
-
const format = opts.file ? formatFromFilePath(opts.file) : "auto";
|
|
1633
|
-
const payload = parsePayload(raw, format);
|
|
1634
|
-
const item = await appendCollection(opts.run, opts.kind, payload, { id: opts.id, created_by_node_id: opts.node, created_by_node_result_id: opts.nodeResult }, cwd);
|
|
1635
|
-
console.log(JSON.stringify(item, null, 2));
|
|
1636
|
-
});
|
|
1637
|
-
const nodeResultCmd = program
|
|
1638
|
-
.command("node-result")
|
|
1639
|
-
.description("Node results per run (stored snapshots of node outputs). Low-level; prefer run step / node complete for agent flow.");
|
|
1640
|
-
nodeResultCmd
|
|
1641
|
-
.command("list")
|
|
1642
|
-
.description("List node results for a run. Requires --run <id>.")
|
|
1643
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1644
|
-
.action(async (opts) => {
|
|
1645
|
-
const cwd = process.cwd();
|
|
1646
|
-
const results = await listNodeResults(opts.run, cwd);
|
|
1647
|
-
console.log(JSON.stringify(results, null, 2));
|
|
1648
|
-
});
|
|
1649
|
-
nodeResultCmd
|
|
1650
|
-
.command("get")
|
|
1651
|
-
.description("Get node result for a node in a run. Requires --run <id> and --node <node_id>.")
|
|
1652
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1653
|
-
.requiredOption("--node <node_id>", "Node ID")
|
|
1654
|
-
.action(async (opts) => {
|
|
1655
|
-
const cwd = process.cwd();
|
|
1656
|
-
const result = await readNodeResult(opts.run, opts.node, cwd);
|
|
1657
|
-
if (!result) {
|
|
1658
|
-
console.error("Not found.");
|
|
1659
|
-
process.exit(1);
|
|
933
|
+
try {
|
|
934
|
+
const result = await cloudGetCollectionItems(opts.run, kind);
|
|
935
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1660
936
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
nodeResultCmd
|
|
1664
|
-
.command("set")
|
|
1665
|
-
.description("Create or replace a node result for a node in a run. Requires --run, --node, --status; optional --output/--output-file.")
|
|
1666
|
-
.requiredOption("--run <run_id>", "Run ID")
|
|
1667
|
-
.requiredOption("--node <node_id>", "Node ID")
|
|
1668
|
-
.requiredOption("--status <status>", "Status: started|completed|failed|needs_human")
|
|
1669
|
-
.option("--id <node_result_id>", "Node result id (default: generated)")
|
|
1670
|
-
.option("--output-file <path>", "Path to a text/markdown file for output")
|
|
1671
|
-
.option("--output <string>", "Inline output text")
|
|
1672
|
-
.action(async (opts) => {
|
|
1673
|
-
const cwd = process.cwd();
|
|
1674
|
-
const run = await readRunFile(opts.run, cwd);
|
|
1675
|
-
const now = new Date().toISOString();
|
|
1676
|
-
const status = opts.status;
|
|
1677
|
-
const validStatuses = Object.values(NodeResultStatus);
|
|
1678
|
-
if (!validStatuses.includes(status)) {
|
|
1679
|
-
console.error(`Error: status must be one of: ${validStatuses.join(", ")}`);
|
|
937
|
+
catch (err) {
|
|
938
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1680
939
|
process.exit(1);
|
|
1681
940
|
}
|
|
1682
|
-
let output = opts.output;
|
|
1683
|
-
if (opts.outputFile) {
|
|
1684
|
-
output = await fs.readFile(path.resolve(cwd, opts.outputFile), "utf-8");
|
|
1685
|
-
}
|
|
1686
|
-
const id = opts.id ?? generateId("node_result");
|
|
1687
|
-
const completed_at = status === NodeResultStatus.Completed || status === NodeResultStatus.Failed || status === NodeResultStatus.NeedsHuman
|
|
1688
|
-
? now
|
|
1689
|
-
: undefined;
|
|
1690
|
-
const result = {
|
|
1691
|
-
node_result_id: id,
|
|
1692
|
-
run_id: opts.run,
|
|
1693
|
-
workflow_id: run.workflow_id,
|
|
1694
|
-
workflow_version_id: run.workflow_version_id,
|
|
1695
|
-
node_id: opts.node,
|
|
1696
|
-
status,
|
|
1697
|
-
started_at: now,
|
|
1698
|
-
completed_at,
|
|
1699
|
-
...(output ? { output } : {}),
|
|
1700
|
-
};
|
|
1701
|
-
await writeNodeResult(opts.run, opts.node, result, cwd);
|
|
1702
|
-
console.log(`COGNETIVY_NODE_RESULT_ID=${id}`);
|
|
1703
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1704
941
|
});
|
|
1705
942
|
const nodeCmd = program
|
|
1706
943
|
.command("node")
|
|
1707
|
-
.description("Node lifecycle: start
|
|
944
|
+
.description("Node lifecycle (cloud): start a node or complete it with optional collection payload. Prefer `cognetivy run step` when available.");
|
|
1708
945
|
nodeCmd
|
|
1709
946
|
.command("start")
|
|
1710
|
-
.description("Mark a node as started
|
|
947
|
+
.description("Mark a node as started on the server. Requires COGNETIVY_API_KEY, --run, and --node.")
|
|
1711
948
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1712
949
|
.requiredOption("--node <node_id>", "Workflow node ID")
|
|
1713
|
-
.
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
if (useCloud) {
|
|
1719
|
-
try {
|
|
1720
|
-
await cloudStartNode(opts.run, opts.node);
|
|
1721
|
-
console.log(`Node "${opts.node}" started.`);
|
|
1722
|
-
}
|
|
1723
|
-
catch (err) {
|
|
1724
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1725
|
-
process.exit(1);
|
|
1726
|
-
}
|
|
1727
|
-
return;
|
|
950
|
+
.action(async function nodeStartAction(opts) {
|
|
951
|
+
await requireCloudApiKey();
|
|
952
|
+
try {
|
|
953
|
+
await cloudStartNode(opts.run, opts.node);
|
|
954
|
+
console.log(`Node "${opts.node}" started.`);
|
|
1728
955
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
if (!exists) {
|
|
1732
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
956
|
+
catch (err) {
|
|
957
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1733
958
|
process.exit(1);
|
|
1734
959
|
}
|
|
1735
|
-
const run = await readRunFile(opts.run, cwd);
|
|
1736
|
-
const by = opts.by ?? (await resolveBy(cwd));
|
|
1737
|
-
const now = new Date().toISOString();
|
|
1738
|
-
const nodeResultId = generateId("node_result");
|
|
1739
|
-
const event = {
|
|
1740
|
-
ts: now,
|
|
1741
|
-
type: "step_started",
|
|
1742
|
-
by,
|
|
1743
|
-
data: { step: opts.node, step_id: opts.node },
|
|
1744
|
-
};
|
|
1745
|
-
await appendEventLine(opts.run, event, cwd);
|
|
1746
|
-
const result = {
|
|
1747
|
-
node_result_id: nodeResultId,
|
|
1748
|
-
run_id: opts.run,
|
|
1749
|
-
workflow_id: run.workflow_id,
|
|
1750
|
-
workflow_version_id: run.workflow_version_id,
|
|
1751
|
-
node_id: opts.node,
|
|
1752
|
-
status: NodeResultStatus.Started,
|
|
1753
|
-
started_at: now,
|
|
1754
|
-
};
|
|
1755
|
-
await writeNodeResult(opts.run, opts.node, result, cwd);
|
|
1756
|
-
console.log(`COGNETIVY_NODE_RESULT_ID=${nodeResultId}`);
|
|
1757
960
|
});
|
|
1758
961
|
nodeCmd
|
|
1759
962
|
.command("complete")
|
|
1760
|
-
.description("Complete a node
|
|
963
|
+
.description("Complete a node via the cloud API (--status completed only). Optional --output/--output-file, --collection-kind + payload (file or stdin), or --writes-file for multi-output nodes.")
|
|
1761
964
|
.requiredOption("--run <run_id>", "Run ID")
|
|
1762
965
|
.requiredOption("--node <node_id>", "Workflow node ID")
|
|
1763
|
-
.requiredOption("--status <status>", "
|
|
966
|
+
.requiredOption("--status <status>", "Must be: completed (cloud API completes successfully)")
|
|
1764
967
|
.option("--output <string>", "Inline output text for the node result")
|
|
1765
968
|
.option("--output-file <path>", "Path to file for node result output")
|
|
1766
|
-
.option("--collection-kind <kind>", "Collection kind
|
|
969
|
+
.option("--collection-kind <kind>", "Collection kind (payload from --collection-file or stdin)")
|
|
1767
970
|
.option("--collection-file <path>", "Path to JSON payload (omit to read from stdin when --collection-kind is set)")
|
|
1768
971
|
.option("--collection-mode <mode>", "set (array) or append (single object); default: infer from payload", "infer")
|
|
1769
|
-
.option("--
|
|
1770
|
-
.action(async (opts)
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
console.error(`Error: Run "${opts.run}" not found.`);
|
|
972
|
+
.option("--writes-file <path>", "JSON file: writes [{ kind, item_ids }] for nodes with multiple output kinds")
|
|
973
|
+
.action(async function nodeCompleteAction(opts) {
|
|
974
|
+
await requireCloudApiKey();
|
|
975
|
+
if (opts.status !== "completed") {
|
|
976
|
+
console.error('Error: cloud `node complete` only supports --status completed. For failed or needs_human, use the Cognetivy app or API.');
|
|
1775
977
|
process.exit(1);
|
|
1776
978
|
}
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
console.error(`Error: status must be one of: ${validStatuses.join(", ")}`);
|
|
979
|
+
const cwd = process.cwd();
|
|
980
|
+
if (opts.writesFile && opts.collectionKind) {
|
|
981
|
+
console.error("Error: use either --writes-file or --collection-kind, not both.");
|
|
1781
982
|
process.exit(1);
|
|
1782
983
|
}
|
|
1783
|
-
const status = opts.status;
|
|
1784
|
-
const by = opts.by ?? (await resolveBy(cwd));
|
|
1785
|
-
const now = new Date().toISOString();
|
|
1786
984
|
let output = opts.output;
|
|
1787
985
|
if (opts.outputFile) {
|
|
1788
986
|
output = await fs.readFile(path.resolve(cwd, opts.outputFile), "utf-8");
|
|
1789
987
|
}
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
988
|
+
const body = {};
|
|
989
|
+
if (output !== undefined) {
|
|
990
|
+
body.output = output;
|
|
991
|
+
}
|
|
992
|
+
if (opts.writesFile) {
|
|
993
|
+
const raw = await fs.readFile(path.resolve(cwd, opts.writesFile), "utf-8");
|
|
994
|
+
body.writes = parsePayload(raw, formatFromFilePath(opts.writesFile));
|
|
995
|
+
}
|
|
996
|
+
else if (opts.collectionKind) {
|
|
1793
997
|
const raw = await readPayloadFromFileOrStdin(opts.collectionFile, cwd);
|
|
1794
998
|
const payload = parsePayload(raw, opts.collectionFile ? formatFromFilePath(opts.collectionFile) : "auto");
|
|
1795
|
-
const mode = opts.collectionMode === "set" || opts.collectionMode === "append"
|
|
999
|
+
const mode = opts.collectionMode === "set" || opts.collectionMode === "append"
|
|
1000
|
+
? opts.collectionMode
|
|
1001
|
+
: Array.isArray(payload)
|
|
1002
|
+
? "set"
|
|
1003
|
+
: "append";
|
|
1004
|
+
body.collectionKind = opts.collectionKind;
|
|
1796
1005
|
if (mode === "set") {
|
|
1797
|
-
|
|
1798
|
-
if (!Array.isArray(payloads)) {
|
|
1006
|
+
if (!Array.isArray(payload)) {
|
|
1799
1007
|
console.error("Error: collection payload must be a JSON array when using set.");
|
|
1800
1008
|
process.exit(1);
|
|
1801
1009
|
}
|
|
1802
|
-
|
|
1803
|
-
...p,
|
|
1804
|
-
id: p.id ?? `${opts.collectionKind}_${i}`,
|
|
1805
|
-
}));
|
|
1806
|
-
const itemIds = payloadsWithIds.map((p) => p.id);
|
|
1807
|
-
await writeCollections(opts.run, opts.collectionKind, payloadsWithIds, { created_by_node_id: opts.node, created_by_node_result_id: nodeResultId }, cwd);
|
|
1808
|
-
writes.push({ kind: opts.collectionKind, item_ids: itemIds });
|
|
1010
|
+
body.collectionPayload = payload;
|
|
1809
1011
|
}
|
|
1810
1012
|
else {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1013
|
+
if (Array.isArray(payload)) {
|
|
1014
|
+
console.error("Error: collection payload must be a single JSON object when using append.");
|
|
1015
|
+
process.exit(1);
|
|
1016
|
+
}
|
|
1017
|
+
body.collectionPayload = payload;
|
|
1814
1018
|
}
|
|
1815
1019
|
}
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
completed_at: now,
|
|
1825
|
-
...(output ? { output } : {}),
|
|
1826
|
-
...(writes.length > 0 ? { writes } : {}),
|
|
1827
|
-
};
|
|
1828
|
-
await writeNodeResult(opts.run, opts.node, result, cwd);
|
|
1829
|
-
const stepCompletedEvent = {
|
|
1830
|
-
ts: now,
|
|
1831
|
-
type: "step_completed",
|
|
1832
|
-
by,
|
|
1833
|
-
data: { step: opts.node, step_id: opts.node },
|
|
1834
|
-
};
|
|
1835
|
-
await appendEventLine(opts.run, stepCompletedEvent, cwd);
|
|
1836
|
-
console.log(`COGNETIVY_NODE_RESULT_ID=${nodeResultId}`);
|
|
1020
|
+
try {
|
|
1021
|
+
await cloudCompleteNode(opts.run, opts.node, body);
|
|
1022
|
+
console.log(`Node "${opts.node}" completed.`);
|
|
1023
|
+
}
|
|
1024
|
+
catch (err) {
|
|
1025
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1026
|
+
process.exit(1);
|
|
1027
|
+
}
|
|
1837
1028
|
});
|
|
1838
1029
|
program
|
|
1839
1030
|
.command("templates")
|
|
1840
|
-
.description("List workflow templates (--list for JSON) or interactively pick one to
|
|
1031
|
+
.description("List workflow templates (--list for JSON) or interactively pick one to create in cloud and set as current (requires COGNETIVY_API_KEY).")
|
|
1841
1032
|
.option("--list", "Print templates as JSON (no picker)")
|
|
1842
|
-
.action(async (opts)
|
|
1033
|
+
.action(async function templatesCommandAction(opts) {
|
|
1843
1034
|
const cwd = process.cwd();
|
|
1844
1035
|
if (opts.list || !process.stdin.isTTY) {
|
|
1845
1036
|
console.log(JSON.stringify(listWorkflowTemplates(), null, 2));
|
|
1846
1037
|
return;
|
|
1847
1038
|
}
|
|
1848
|
-
await
|
|
1039
|
+
await requireCloudApiKey();
|
|
1849
1040
|
const templates = listWorkflowTemplatesForPicker();
|
|
1850
1041
|
const picked = await p.select({
|
|
1851
|
-
message: "Pick a workflow template to
|
|
1042
|
+
message: "Pick a workflow template to create in your cloud org",
|
|
1852
1043
|
options: templates.map((t) => ({
|
|
1853
1044
|
value: t.id,
|
|
1854
1045
|
label: t.name,
|
|
@@ -1861,16 +1052,19 @@ program
|
|
|
1861
1052
|
}
|
|
1862
1053
|
const templateId = picked;
|
|
1863
1054
|
try {
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1055
|
+
const orgId = await resolveCloudOrganizationId();
|
|
1056
|
+
const result = await applyWorkflowTemplateToCloud({ organizationId: orgId, templateId, cwd });
|
|
1057
|
+
p.note(`Created workflow "${result.template.name}" (${result.workflowId}) in cloud.`, "Template applied");
|
|
1866
1058
|
console.log(JSON.stringify({
|
|
1867
1059
|
template_id: result.template.id,
|
|
1868
|
-
workflow_id: result.
|
|
1869
|
-
|
|
1870
|
-
version_id: result.
|
|
1060
|
+
workflow_id: result.workflowId,
|
|
1061
|
+
cloud_current_workflow_id: result.workflowId,
|
|
1062
|
+
version_id: result.versionId,
|
|
1871
1063
|
}, null, 2));
|
|
1872
|
-
const
|
|
1873
|
-
|
|
1064
|
+
const appUrl = getCloudAppUrl();
|
|
1065
|
+
const url = buildCloudOnboardingUrl(appUrl, result.workflowId);
|
|
1066
|
+
await openUrl(url);
|
|
1067
|
+
printOpenedUrlMessage(url, { workflow: true });
|
|
1874
1068
|
}
|
|
1875
1069
|
catch (err) {
|
|
1876
1070
|
console.error(err instanceof Error ? `Error: ${err.message}` : String(err));
|
|
@@ -1883,7 +1077,6 @@ program
|
|
|
1883
1077
|
.option("--force", "Overwrite if skill already exists")
|
|
1884
1078
|
.option("--no-init", "Skip cognetivy workspace init; only install skills")
|
|
1885
1079
|
.option("--interactive", "Show interactive prompt to choose tool(s) and install accordingly")
|
|
1886
|
-
.option("--cloud", "Install cloud-mode skill (no .cognetivy/ workspace; use --cloud on commands)")
|
|
1887
1080
|
.action(async (target, opts) => {
|
|
1888
1081
|
const cwd = process.cwd();
|
|
1889
1082
|
const useTUI = opts.interactive === true || target === undefined;
|
|
@@ -1892,9 +1085,8 @@ program
|
|
|
1892
1085
|
await runInstallTUI({ cwd, force: opts.force, init: opts.init !== false });
|
|
1893
1086
|
return;
|
|
1894
1087
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
await ensureWorkspace(cwd);
|
|
1088
|
+
if (opts.init !== false) {
|
|
1089
|
+
await ensureMinimalWorkspace(cwd);
|
|
1898
1090
|
}
|
|
1899
1091
|
const normalized = target.toLowerCase();
|
|
1900
1092
|
const targetMap = {
|
|
@@ -1919,9 +1111,6 @@ program
|
|
|
1919
1111
|
let targetsToInstall = resolved === "all"
|
|
1920
1112
|
? ["agent", "agents", "cursor", "factory", "gemini", "openclaw", "opencode", "qwen", "workspace"]
|
|
1921
1113
|
: [resolved];
|
|
1922
|
-
if (skillMode === "cloud") {
|
|
1923
|
-
targetsToInstall = targetsToInstall.filter((t) => t !== "workspace");
|
|
1924
|
-
}
|
|
1925
1114
|
const optsCommon = { force: opts.force, cwd, config: skillsConfig };
|
|
1926
1115
|
try {
|
|
1927
1116
|
for (const internalTarget of targetsToInstall) {
|
|
@@ -1932,7 +1121,7 @@ program
|
|
|
1932
1121
|
}
|
|
1933
1122
|
}
|
|
1934
1123
|
for (const internalTarget of targetsToInstall) {
|
|
1935
|
-
const cognetivyPath = await installCognetivySkill(internalTarget, cwd, skillsConfig
|
|
1124
|
+
const cognetivyPath = await installCognetivySkill(internalTarget, cwd, skillsConfig);
|
|
1936
1125
|
const label = targetToLabel(internalTarget);
|
|
1937
1126
|
console.log(`[${label}] Cognetivy skill at ${cognetivyPath}`);
|
|
1938
1127
|
}
|
|
@@ -2207,30 +1396,7 @@ program
|
|
|
2207
1396
|
const workspacePath = opts.workspace ? path.resolve(process.cwd(), opts.workspace) : process.cwd();
|
|
2208
1397
|
await runMcpServer(workspacePath);
|
|
2209
1398
|
});
|
|
2210
|
-
|
|
2211
|
-
.command("studio")
|
|
2212
|
-
.description("Open read-only Studio (workflow, runs, events, collections) in browser. Optional --workspace, --port, --api-only.")
|
|
2213
|
-
.option("--workspace <path>", "Workspace directory (default: cwd)")
|
|
2214
|
-
.option("--port <number>", "Port for Studio server", (v) => parseInt(v, 10), STUDIO_DEFAULT_PORT)
|
|
2215
|
-
.option("--api-only", "Only serve API (for use with Vite dev server; see studio/README)")
|
|
2216
|
-
.action(async (opts) => {
|
|
2217
|
-
const cwd = process.cwd();
|
|
2218
|
-
const workspacePath = opts.workspace ? path.resolve(cwd, opts.workspace) : cwd;
|
|
2219
|
-
await requireWorkspace(workspacePath);
|
|
2220
|
-
const requestedPort = opts.port ?? STUDIO_DEFAULT_PORT;
|
|
2221
|
-
const { port: actualPort } = await startStudioServer(workspacePath, requestedPort, { apiOnly: opts.apiOnly });
|
|
2222
|
-
if (!opts.apiOnly) {
|
|
2223
|
-
const url = `http://127.0.0.1:${actualPort}`;
|
|
2224
|
-
await openUrl(url);
|
|
2225
|
-
console.log(`Studio at ${url} (workspace: ${workspacePath}). Press Ctrl+C to stop.`);
|
|
2226
|
-
}
|
|
2227
|
-
else {
|
|
2228
|
-
console.log(`Studio API at http://127.0.0.1:${actualPort} (workspace: ${workspacePath}).`);
|
|
2229
|
-
console.log(`Run the app in dev: cd studio && npm run dev, then open http://localhost:5173`);
|
|
2230
|
-
console.log("Press Ctrl+C to stop.");
|
|
2231
|
-
}
|
|
2232
|
-
});
|
|
2233
|
-
const DEFAULT_BEHAVIOR_DESCRIPTION = "Guided onboarding: choose cloud or local, sign in if cloud, install or update platform skills (Cursor, Claude Code, etc.), ensure at least one workflow (template picker if needed), then opens the Cognetivy app in your browser.";
|
|
1399
|
+
const DEFAULT_BEHAVIOR_DESCRIPTION = "Guided onboarding: sign in if needed, install or update platform skills (Cursor, Claude Code, etc.), ensure at least one cloud workflow (template picker if needed), then start the local studio (browser + WebSocket executor).";
|
|
2234
1400
|
program
|
|
2235
1401
|
.command("docs")
|
|
2236
1402
|
.description("Open CLI reference (all commands and options) in browser. No arguments.")
|
|
@@ -2262,71 +1428,75 @@ function runUpdateNotifier() {
|
|
|
2262
1428
|
// ignore
|
|
2263
1429
|
}
|
|
2264
1430
|
}
|
|
2265
|
-
/** Guided onboarding when user runs `cognetivy` with no args:
|
|
1431
|
+
/** Guided onboarding when user runs `cognetivy` with no args: auth, skills, cloud workflow, then open app. */
|
|
2266
1432
|
async function runDefaultOnboardingFlow(cwd) {
|
|
2267
1433
|
runUpdateNotifier();
|
|
2268
1434
|
const authenticated = await isCloudAuthenticated();
|
|
2269
|
-
let
|
|
1435
|
+
let loginServerHandle;
|
|
2270
1436
|
if (!authenticated) {
|
|
2271
|
-
|
|
2272
|
-
const
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
});
|
|
2279
|
-
if (p.isCancel(choice)) {
|
|
2280
|
-
p.cancel("Cancelled.");
|
|
2281
|
-
process.exit(0);
|
|
1437
|
+
const signInApiBase = getCloudApiUrl();
|
|
1438
|
+
const apiLooksLocal = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(signInApiBase);
|
|
1439
|
+
p.note(`Sign in once; your API key is stored locally.\nBackend API for this run: ${signInApiBase}${apiLooksLocal ? "" : "\nTip: for a local Nest server use --dev or --api-url http://localhost:3000."}`, "Cognetivy");
|
|
1440
|
+
const staticRoot = resolveLocalStudioStaticRoot();
|
|
1441
|
+
const canAuthViaLocalStudio = localStudioBundleHasCliAuth(staticRoot);
|
|
1442
|
+
if (canAuthViaLocalStudio) {
|
|
1443
|
+
loginServerHandle = await createLocalStudioServer({ workspaceCwd: cwd });
|
|
2282
1444
|
}
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
1445
|
+
else {
|
|
1446
|
+
console.log("Tip: Run `npm run build:local-studio` in this package so sign-in opens local studio instead of the hosted app.");
|
|
1447
|
+
}
|
|
1448
|
+
const authAppUrl = loginServerHandle ? resolveLocalStudioBrowserBase(loginServerHandle) : getCloudAppUrl();
|
|
1449
|
+
console.log(loginServerHandle ? "Opening browser to sign in (local studio)…" : "Opening browser to sign in…");
|
|
1450
|
+
const result = await runLoginFlow({ appUrl: authAppUrl });
|
|
1451
|
+
if (result.error) {
|
|
1452
|
+
if (loginServerHandle) {
|
|
1453
|
+
await loginServerHandle.close();
|
|
2291
1454
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
1455
|
+
console.error(result.error);
|
|
1456
|
+
process.exit(1);
|
|
1457
|
+
}
|
|
1458
|
+
if (!result.code) {
|
|
1459
|
+
if (loginServerHandle) {
|
|
1460
|
+
await loginServerHandle.close();
|
|
2295
1461
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
1462
|
+
console.error("No authorization code received.");
|
|
1463
|
+
process.exit(1);
|
|
1464
|
+
}
|
|
1465
|
+
const apiUrl = getCloudApiUrl();
|
|
1466
|
+
const res = await fetch(`${apiUrl}/auth/cli/token`, {
|
|
1467
|
+
method: "POST",
|
|
1468
|
+
headers: { "Content-Type": "application/json" },
|
|
1469
|
+
body: JSON.stringify({ code: result.code }),
|
|
1470
|
+
});
|
|
1471
|
+
if (!res.ok) {
|
|
1472
|
+
const text = await res.text();
|
|
1473
|
+
if (loginServerHandle) {
|
|
1474
|
+
await loginServerHandle.close();
|
|
2306
1475
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
1476
|
+
console.error(text || res.statusText);
|
|
1477
|
+
process.exit(1);
|
|
1478
|
+
}
|
|
1479
|
+
const data = (await res.json());
|
|
1480
|
+
const apiKey = data?.api_key ?? "";
|
|
1481
|
+
if (!apiKey) {
|
|
1482
|
+
if (loginServerHandle) {
|
|
1483
|
+
await loginServerHandle.close();
|
|
2312
1484
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
1485
|
+
console.error("No API key in response.");
|
|
1486
|
+
process.exit(1);
|
|
2315
1487
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
const index = await readWorkflowIndexOptional(cwd);
|
|
2319
|
-
mode = index?.preferred_mode === "local" ? "local" : "cloud";
|
|
1488
|
+
writeStoredApiKey(apiKey);
|
|
1489
|
+
console.log("Logged in. API key saved.");
|
|
2320
1490
|
}
|
|
2321
1491
|
const { runInstallTUI } = await import("./install-tui.js");
|
|
2322
1492
|
const installedVersion = await readInstalledSkillsVersion(cwd);
|
|
2323
1493
|
const currentVersion = getCurrentVersionSync();
|
|
2324
1494
|
if (installedVersion == null) {
|
|
2325
|
-
await runInstallTUI({ cwd, init: true,
|
|
1495
|
+
await runInstallTUI({ cwd, init: true, skipTemplate: true });
|
|
2326
1496
|
}
|
|
2327
1497
|
else if (isNewerVersion(currentVersion, installedVersion)) {
|
|
2328
1498
|
const shouldUpdate = await p.confirm({
|
|
2329
|
-
message: `Skills were installed with v${installedVersion}; you're on v${currentVersion}. Update skill files? (Your
|
|
1499
|
+
message: `Skills were installed with v${installedVersion}; you're on v${currentVersion}. Update skill files? (Your .cognetivy skills folder is not removed.)`,
|
|
2330
1500
|
initialValue: true,
|
|
2331
1501
|
});
|
|
2332
1502
|
if (p.isCancel(shouldUpdate)) {
|
|
@@ -2336,30 +1506,19 @@ async function runDefaultOnboardingFlow(cwd) {
|
|
|
2336
1506
|
await runInstallTUI({ cwd, force: true, init: false });
|
|
2337
1507
|
}
|
|
2338
1508
|
}
|
|
2339
|
-
|
|
2340
|
-
await ensureWorkspace(cwd, { force: false });
|
|
2341
|
-
}
|
|
1509
|
+
await ensureMinimalWorkspace(cwd);
|
|
2342
1510
|
const index = await readWorkflowIndexOptional(cwd);
|
|
2343
|
-
if (index && index.preferred_mode !== mode) {
|
|
2344
|
-
await writeWorkflowIndex({ ...index, preferred_mode: mode }, cwd);
|
|
2345
|
-
}
|
|
2346
1511
|
let hasWorkflow = false;
|
|
2347
1512
|
let cloudWorkflowList = [];
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
hasWorkflow = list.length >= 1 || (index?.cloud_current_workflow_id != null);
|
|
2354
|
-
}
|
|
2355
|
-
catch {
|
|
2356
|
-
hasWorkflow = false;
|
|
2357
|
-
}
|
|
1513
|
+
try {
|
|
1514
|
+
const orgId = await resolveCloudOrganizationId();
|
|
1515
|
+
const list = await cloudListWorkflows(orgId);
|
|
1516
|
+
cloudWorkflowList = list;
|
|
1517
|
+
hasWorkflow = list.length >= 1 || (index?.cloud_current_workflow_id != null);
|
|
2358
1518
|
}
|
|
2359
|
-
|
|
2360
|
-
hasWorkflow =
|
|
1519
|
+
catch {
|
|
1520
|
+
hasWorkflow = false;
|
|
2361
1521
|
}
|
|
2362
|
-
let localCurrentWorkflowId = null;
|
|
2363
1522
|
let cloudCurrentWorkflowId = null;
|
|
2364
1523
|
if (!hasWorkflow) {
|
|
2365
1524
|
const templates = listWorkflowTemplatesForPicker();
|
|
@@ -2373,17 +1532,10 @@ async function runDefaultOnboardingFlow(cwd) {
|
|
|
2373
1532
|
else {
|
|
2374
1533
|
const templateId = templateSelection;
|
|
2375
1534
|
try {
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
p.note(`Created workflow "${result.template.name}" (${result.workflowId}) in cloud.`, "Template applied");
|
|
2381
|
-
}
|
|
2382
|
-
else {
|
|
2383
|
-
const result = await applyWorkflowTemplateToWorkspace({ cwd, templateId });
|
|
2384
|
-
localCurrentWorkflowId = result.workflow.workflow_id;
|
|
2385
|
-
p.note(`Applied template "${result.template.name}". Workflow: ${result.workflow.workflow_id}`, "Template applied");
|
|
2386
|
-
}
|
|
1535
|
+
const orgId = await resolveCloudOrganizationId();
|
|
1536
|
+
const result = await applyWorkflowTemplateToCloud({ organizationId: orgId, templateId, cwd });
|
|
1537
|
+
cloudCurrentWorkflowId = result.workflowId;
|
|
1538
|
+
p.note(`Created workflow "${result.template.name}" (${result.workflowId}) in cloud.`, "Template applied");
|
|
2387
1539
|
}
|
|
2388
1540
|
catch (err) {
|
|
2389
1541
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -2391,21 +1543,10 @@ async function runDefaultOnboardingFlow(cwd) {
|
|
|
2391
1543
|
}
|
|
2392
1544
|
}
|
|
2393
1545
|
}
|
|
2394
|
-
else if (
|
|
2395
|
-
cloudCurrentWorkflowId =
|
|
2396
|
-
index?.cloud_current_workflow_id ?? cloudWorkflowList[0]?.id ?? null;
|
|
2397
|
-
}
|
|
2398
|
-
if (mode === "local") {
|
|
2399
|
-
const workflowIdToOpen = localCurrentWorkflowId ??
|
|
2400
|
-
(await readWorkflowIndexOptional(cwd).then((idx) => idx?.current_workflow_id ?? null));
|
|
2401
|
-
await launchLocalStudio(cwd, undefined, workflowIdToOpen);
|
|
2402
|
-
}
|
|
2403
|
-
else {
|
|
2404
|
-
const appUrl = getCloudAppUrl();
|
|
2405
|
-
const url = buildCloudOnboardingUrl(appUrl, cloudCurrentWorkflowId);
|
|
2406
|
-
await openUrl(url);
|
|
2407
|
-
printOpenedUrlMessage(url, { workflow: Boolean(cloudCurrentWorkflowId) });
|
|
1546
|
+
else if (cloudCurrentWorkflowId == null) {
|
|
1547
|
+
cloudCurrentWorkflowId = index?.cloud_current_workflow_id ?? cloudWorkflowList[0]?.id ?? null;
|
|
2408
1548
|
}
|
|
1549
|
+
await runLocalStudioForeground(cwd, { existingHandle: loginServerHandle });
|
|
2409
1550
|
}
|
|
2410
1551
|
program.action(async () => {
|
|
2411
1552
|
const opts = program.opts();
|
|
@@ -2415,9 +1556,7 @@ program.action(async () => {
|
|
|
2415
1556
|
}
|
|
2416
1557
|
const cwd = process.cwd();
|
|
2417
1558
|
if (!process.stdin.isTTY) {
|
|
2418
|
-
|
|
2419
|
-
await openUrl(appUrl);
|
|
2420
|
-
printOpenedUrlMessage(appUrl, { workflow: false });
|
|
1559
|
+
await runLocalStudioForeground(cwd);
|
|
2421
1560
|
return;
|
|
2422
1561
|
}
|
|
2423
1562
|
await runDefaultOnboardingFlow(cwd);
|