@controllerai/cli 0.2.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/README.md +180 -0
- package/dist/api/client.js +330 -0
- package/dist/api/client.js.map +1 -0
- package/dist/appLinks.js +99 -0
- package/dist/appLinks.js.map +1 -0
- package/dist/argv.js +124 -0
- package/dist/argv.js.map +1 -0
- package/dist/commands/agent.js +813 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/auth.js +327 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/branch.js +441 -0
- package/dist/commands/branch.js.map +1 -0
- package/dist/commands/connect.js +148 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/connection.js +148 -0
- package/dist/commands/connection.js.map +1 -0
- package/dist/commands/data.js +441 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/deps.js +63 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/doctor.js +102 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.js +72 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/exec.js +306 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/expr.js +346 -0
- package/dist/commands/expr.js.map +1 -0
- package/dist/commands/flow.js +447 -0
- package/dist/commands/flow.js.map +1 -0
- package/dist/commands/integration.js +102 -0
- package/dist/commands/integration.js.map +1 -0
- package/dist/commands/node.js +885 -0
- package/dist/commands/node.js.map +1 -0
- package/dist/commands/organize.js +234 -0
- package/dist/commands/organize.js.map +1 -0
- package/dist/commands/run.js +437 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/schema.js +269 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/skills.js +1156 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/trigger.js +992 -0
- package/dist/commands/trigger.js.map +1 -0
- package/dist/commands/workflow.js +503 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +39 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/jsSource.js +32 -0
- package/dist/jsSource.js.map +1 -0
- package/dist/nodeProps.js +177 -0
- package/dist/nodeProps.js.map +1 -0
- package/dist/output.js +85 -0
- package/dist/output.js.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +41 -0
- package/skills/controllerai-agents/SKILL.md +169 -0
- package/skills/controllerai-agents/agents/openai.yaml +4 -0
- package/skills/controllerai-agents/references/instructions-and-versioning.md +76 -0
- package/skills/controllerai-ai-nodes/SKILL.md +83 -0
- package/skills/controllerai-ai-nodes/agents/openai.yaml +4 -0
- package/skills/controllerai-ai-nodes/references/selection-and-testing.md +46 -0
- package/skills/controllerai-data/SKILL.md +121 -0
- package/skills/controllerai-data/agents/openai.yaml +4 -0
- package/skills/controllerai-data/references/data-rails.md +46 -0
- package/skills/controllerai-expressions/SKILL.md +115 -0
- package/skills/controllerai-expressions/agents/openai.yaml +4 -0
- package/skills/controllerai-expressions/references/dsl-and-recipes.md +120 -0
- package/skills/controllerai-flow-control/SKILL.md +132 -0
- package/skills/controllerai-flow-control/agents/openai.yaml +4 -0
- package/skills/controllerai-flow-control/references/patterns.md +61 -0
- package/skills/controllerai-integration-actions/SKILL.md +95 -0
- package/skills/controllerai-integration-actions/agents/openai.yaml +4 -0
- package/skills/controllerai-node-config/SKILL.md +138 -0
- package/skills/controllerai-node-config/agents/openai.yaml +4 -0
- package/skills/controllerai-node-config/references/prop-and-readiness.md +72 -0
- package/skills/controllerai-runs/SKILL.md +109 -0
- package/skills/controllerai-runs/agents/openai.yaml +4 -0
- package/skills/controllerai-runs/references/debugging.md +53 -0
- package/skills/controllerai-start/SKILL.md +44 -0
- package/skills/controllerai-start/agents/openai.yaml +4 -0
- package/skills/controllerai-triggers/SKILL.md +174 -0
- package/skills/controllerai-triggers/agents/openai.yaml +4 -0
- package/skills/controllerai-triggers/references/lifecycle.md +54 -0
- package/skills/controllerai-workflows/SKILL.md +86 -0
- package/skills/controllerai-workflows/agents/openai.yaml +4 -0
- package/skills/controllerai-workflows/references/command-map.md +64 -0
- package/skills/manifest.json +248 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
export const DEFAULT_API_URL = 'https://api.app.getcontroller.ai';
|
|
5
|
+
const defaultConfigDirectory = () => join(homedir(), '.config', 'cai');
|
|
6
|
+
const defaultConfigPath = () => join(defaultConfigDirectory(), 'config.json');
|
|
7
|
+
export const configPath = () => process.env.CAI_CONFIG ?? defaultConfigPath();
|
|
8
|
+
/**
|
|
9
|
+
* Create the config parent securely without changing permissions on a directory
|
|
10
|
+
* the caller already owns. The default cai directory is CLI-owned and may always
|
|
11
|
+
* be hardened; a custom parent may only be chmodded when this call created it.
|
|
12
|
+
*/
|
|
13
|
+
const ensureConfigParent = (path) => {
|
|
14
|
+
const parent = dirname(path);
|
|
15
|
+
const parentExisted = existsSync(parent);
|
|
16
|
+
mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
17
|
+
if (!parentExisted || resolve(parent) === resolve(defaultConfigDirectory())) {
|
|
18
|
+
chmodSync(parent, 0o700);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const readFile = () => {
|
|
22
|
+
const path = configPath();
|
|
23
|
+
if (!existsSync(path))
|
|
24
|
+
return {};
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/** File config overlaid with env vars. Env always wins. */
|
|
33
|
+
export const loadConfig = () => {
|
|
34
|
+
const file = readFile();
|
|
35
|
+
const envWorkflow = process.env.CAI_WORKFLOW ? Number(process.env.CAI_WORKFLOW) : undefined;
|
|
36
|
+
return {
|
|
37
|
+
apiUrl: (process.env.CAI_API_URL ?? file.apiUrl ?? DEFAULT_API_URL).replace(/\/+$/, ''),
|
|
38
|
+
appUrl: file.appUrl,
|
|
39
|
+
token: process.env.CAI_TOKEN ?? file.token,
|
|
40
|
+
tokenKind: process.env.CAI_TOKEN ? detectTokenKind(process.env.CAI_TOKEN) : file.tokenKind,
|
|
41
|
+
workflowId: envWorkflow ?? file.workflowId,
|
|
42
|
+
headStateId: file.headStateId,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** Merge a patch into the persisted config file (env overrides are not written). */
|
|
46
|
+
export const saveConfig = (patch) => {
|
|
47
|
+
const path = configPath();
|
|
48
|
+
ensureConfigParent(path);
|
|
49
|
+
const next = { ...readFile(), ...patch };
|
|
50
|
+
writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
|
|
51
|
+
chmodSync(path, 0o600);
|
|
52
|
+
return next;
|
|
53
|
+
};
|
|
54
|
+
export const clearToken = () => {
|
|
55
|
+
const current = readFile();
|
|
56
|
+
const next = { ...current };
|
|
57
|
+
delete next.token;
|
|
58
|
+
delete next.tokenKind;
|
|
59
|
+
delete next.expiresAt;
|
|
60
|
+
const path = configPath();
|
|
61
|
+
ensureConfigParent(path);
|
|
62
|
+
writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
|
|
63
|
+
chmodSync(path, 0o600);
|
|
64
|
+
return next;
|
|
65
|
+
};
|
|
66
|
+
export const detectTokenKind = (token) => token.startsWith('cai_') ? 'cli' : token.startsWith('sk-') ? 'apiKey' : 'jwt';
|
|
67
|
+
export const maskToken = (token) => {
|
|
68
|
+
if (!token)
|
|
69
|
+
return '(none)';
|
|
70
|
+
if (token.length <= 12)
|
|
71
|
+
return `${token.slice(0, 3)}…`;
|
|
72
|
+
return `${token.slice(0, 6)}…${token.slice(-4)}`;
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ApiClient } from './api/client.js';
|
|
2
|
+
import { loadConfig } from './config.js';
|
|
3
|
+
import { userError } from './errors.js';
|
|
4
|
+
export const buildClient = (command) => {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
const overrideUrl = globalOpt(command, 'apiUrl');
|
|
7
|
+
if (typeof overrideUrl === 'string' && overrideUrl) {
|
|
8
|
+
config.apiUrl = overrideUrl.replace(/\/+$/, '');
|
|
9
|
+
}
|
|
10
|
+
return { config, api: new ApiClient(config) };
|
|
11
|
+
};
|
|
12
|
+
/** Walk to the root program to read a global flag from any depth of subcommand. */
|
|
13
|
+
export const globalOpt = (command, name) => {
|
|
14
|
+
let node = command;
|
|
15
|
+
while (node) {
|
|
16
|
+
const value = node.opts()[name];
|
|
17
|
+
if (value !== undefined)
|
|
18
|
+
return value;
|
|
19
|
+
node = node.parent;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
};
|
|
23
|
+
export const resolveWorkflowId = (command, config) => {
|
|
24
|
+
const flag = globalOpt(command, 'workflow');
|
|
25
|
+
const raw = flag ?? config.workflowId;
|
|
26
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
27
|
+
throw userError('No workflow selected. Pass --workflow <id>, set CAI_WORKFLOW, or run `cai use <id>`.', 'NO_WORKFLOW');
|
|
28
|
+
}
|
|
29
|
+
const id = Number(raw);
|
|
30
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
31
|
+
throw userError(`Invalid workflow id: ${String(raw)}`, 'BAD_WORKFLOW_ID');
|
|
32
|
+
}
|
|
33
|
+
return id;
|
|
34
|
+
};
|
|
35
|
+
export const requireContext = (command) => {
|
|
36
|
+
const { config, api } = buildClient(command);
|
|
37
|
+
return { config, api, workflowId: resolveWorkflowId(command, config) };
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAa,UAAU,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AASvC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAgB,EAAyC,EAAE;IACrF,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAChD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnD,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAA;AAC/C,CAAC,CAAA;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAgB,EAAE,IAAY,EAAW,EAAE;IACnE,IAAI,IAAI,GAAmB,OAAO,CAAA;IAClC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,GAAI,IAAI,CAAC,IAAI,EAA8B,CAAC,IAAI,CAAC,CAAA;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QACrC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAgB,EAAE,MAAiB,EAAU,EAAE;IAC/E,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC3C,MAAM,GAAG,GAAG,IAAI,IAAI,MAAM,CAAC,UAAU,CAAA;IACrC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACpD,MAAM,SAAS,CACb,sFAAsF,EACtF,aAAa,CACd,CAAA;IACH,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,SAAS,CAAC,wBAAwB,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAA;IAC3E,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAgB,EAAkB,EAAE;IACjE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IAC5C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAA;AACxE,CAAC,CAAA"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes are part of the CLI contract:
|
|
3
|
+
* 0 ok | 1 user/validation | 2 conflict (OCC) | 3 auth | 4 network
|
|
4
|
+
*/
|
|
5
|
+
export const EXIT = {
|
|
6
|
+
ok: 0,
|
|
7
|
+
user: 1,
|
|
8
|
+
conflict: 2,
|
|
9
|
+
auth: 3,
|
|
10
|
+
network: 4,
|
|
11
|
+
};
|
|
12
|
+
export class CaiError extends Error {
|
|
13
|
+
exitCode;
|
|
14
|
+
code;
|
|
15
|
+
detail;
|
|
16
|
+
/** Set when the backend scrubbed a 5xx and the real cause is only in its log. */
|
|
17
|
+
scrubbed;
|
|
18
|
+
constructor(message, opts = {}) {
|
|
19
|
+
// Every auth-class failure must be actionable without reading docs.
|
|
20
|
+
const exitCode = opts.exitCode ?? EXIT.user;
|
|
21
|
+
const actionable = exitCode === EXIT.auth && !/cai auth login/.test(message)
|
|
22
|
+
? `${message} Run \`cai auth login\` to re-authenticate.`
|
|
23
|
+
: message;
|
|
24
|
+
super(actionable);
|
|
25
|
+
this.name = 'CaiError';
|
|
26
|
+
this.exitCode = exitCode;
|
|
27
|
+
this.code = opts.code ?? 'ERROR';
|
|
28
|
+
this.detail = opts.detail;
|
|
29
|
+
this.scrubbed = opts.scrubbed ?? false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export const userError = (message, code = 'VALIDATION_ERROR') => new CaiError(message, { exitCode: EXIT.user, code });
|
|
33
|
+
export const authError = (message, code = 'UNAUTHORIZED') => new CaiError(message, { exitCode: EXIT.auth, code });
|
|
34
|
+
export const conflictError = (message, code = 'STATE_CONFLICT') => new CaiError(message, { exitCode: EXIT.conflict, code });
|
|
35
|
+
export const networkError = (message, code = 'NETWORK_ERROR') => new CaiError(message, { exitCode: EXIT.network, code });
|
|
36
|
+
/**
|
|
37
|
+
* Map an HTTP status + backend error code onto a CLI exit code.
|
|
38
|
+
* 401/403 -> auth, 409 (or STATE_CONFLICT) -> conflict, 4xx -> user, 5xx -> network.
|
|
39
|
+
*/
|
|
40
|
+
export const exitCodeForStatus = (status, backendCode) => {
|
|
41
|
+
if (backendCode === 'STATE_CONFLICT')
|
|
42
|
+
return EXIT.conflict;
|
|
43
|
+
if (status === 401 || status === 403)
|
|
44
|
+
return EXIT.auth;
|
|
45
|
+
if (status === 409)
|
|
46
|
+
return EXIT.conflict;
|
|
47
|
+
if (status >= 500)
|
|
48
|
+
return EXIT.network;
|
|
49
|
+
if (status >= 400)
|
|
50
|
+
return EXIT.user;
|
|
51
|
+
return EXIT.user;
|
|
52
|
+
};
|
|
53
|
+
/** The backend's error middleware replaces every 5xx cause with this string. */
|
|
54
|
+
export const SCRUBBED_MESSAGES = new Set(['Internal server error', 'INTERNAL_SERVER_ERROR']);
|
|
55
|
+
export const isScrubbed = (status, message) => status >= 500 && SCRUBBED_MESSAGES.has(message.trim());
|
|
56
|
+
export const SCRUBBED_HINT = 'The backend scrubbed this 5xx: the response carries no cause, and the CLI will not invent one. ' +
|
|
57
|
+
'The real stack trace is only in the backend container log ' +
|
|
58
|
+
'(feature stacks: .feature-stacks/<name>/be.log; docker: `docker logs <be-container>`).';
|
|
59
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { addGlobalOptions, applyExitOverride, collectFlags, explainUnknownOptions, normalizeArgv, } from './argv.js';
|
|
6
|
+
import { globalOpt } from './context.js';
|
|
7
|
+
import { CaiError, EXIT } from './errors.js';
|
|
8
|
+
import { emitError, setCommandPath, setJsonMode } from './output.js';
|
|
9
|
+
import { registerAuth } from './commands/auth.js';
|
|
10
|
+
import { registerAgent } from './commands/agent.js';
|
|
11
|
+
import { registerBranch } from './commands/branch.js';
|
|
12
|
+
import { registerConnection } from './commands/connection.js';
|
|
13
|
+
import { registerData } from './commands/data.js';
|
|
14
|
+
import { registerDeps } from './commands/deps.js';
|
|
15
|
+
import { registerDoctor } from './commands/doctor.js';
|
|
16
|
+
import { registerEvents } from './commands/events.js';
|
|
17
|
+
import { registerExec } from './commands/exec.js';
|
|
18
|
+
import { registerExpr } from './commands/expr.js';
|
|
19
|
+
import { registerFlow } from './commands/flow.js';
|
|
20
|
+
import { registerIntegration } from './commands/integration.js';
|
|
21
|
+
import { registerNode } from './commands/node.js';
|
|
22
|
+
import { registerOrganize } from './commands/organize.js';
|
|
23
|
+
import { registerRun } from './commands/run.js';
|
|
24
|
+
import { registerSchema } from './commands/schema.js';
|
|
25
|
+
import { registerTrigger } from './commands/trigger.js';
|
|
26
|
+
import { registerUse, registerWorkflow } from './commands/workflow.js';
|
|
27
|
+
import { registerConnect } from './commands/connect.js';
|
|
28
|
+
import { registerSkills } from './commands/skills.js';
|
|
29
|
+
import { CLI_VERSION } from './version.js';
|
|
30
|
+
export { CLI_VERSION } from './version.js';
|
|
31
|
+
export const buildProgram = () => {
|
|
32
|
+
const program = new Command();
|
|
33
|
+
program
|
|
34
|
+
.name('cai')
|
|
35
|
+
.description('Build and operate Controller AI workflows and agents')
|
|
36
|
+
.version(CLI_VERSION)
|
|
37
|
+
// No default on --json: absent must read as `undefined` so globalOpt() keeps
|
|
38
|
+
// walking up. A `false` here would shadow a --json given after the
|
|
39
|
+
// subcommand, and vice versa.
|
|
40
|
+
.option('--json', 'machine-readable output on stdout')
|
|
41
|
+
.option('--workflow <id>', 'workflow id (overrides `cai use` and CAI_WORKFLOW)')
|
|
42
|
+
.option('--api-url <url>', 'backend base URL (overrides CAI_API_URL)')
|
|
43
|
+
.option('--id <value>', 'positional id, for ids that begin with "-"')
|
|
44
|
+
.showHelpAfterError()
|
|
45
|
+
.enablePositionalOptions();
|
|
46
|
+
registerAuth(program);
|
|
47
|
+
registerConnect(program);
|
|
48
|
+
registerSkills(program);
|
|
49
|
+
registerDoctor(program);
|
|
50
|
+
registerAgent(program);
|
|
51
|
+
registerUse(program);
|
|
52
|
+
registerWorkflow(program);
|
|
53
|
+
registerFlow(program);
|
|
54
|
+
registerIntegration(program);
|
|
55
|
+
registerNode(program);
|
|
56
|
+
registerExpr(program);
|
|
57
|
+
registerRun(program);
|
|
58
|
+
registerExec(program);
|
|
59
|
+
registerConnection(program);
|
|
60
|
+
registerBranch(program);
|
|
61
|
+
registerData(program);
|
|
62
|
+
registerDeps(program);
|
|
63
|
+
registerEvents(program);
|
|
64
|
+
registerSchema(program);
|
|
65
|
+
registerTrigger(program);
|
|
66
|
+
registerOrganize(program);
|
|
67
|
+
// The three global flags are documented as working on every command, so they
|
|
68
|
+
// are declared on every command — commander only parses an option on the
|
|
69
|
+
// command that declares it, and `cai flow list --json` must work as readily as
|
|
70
|
+
// `cai --json flow list`.
|
|
71
|
+
addGlobalOptions(program);
|
|
72
|
+
program.hook('preAction', (_thisCommand, actionCommand) => {
|
|
73
|
+
// Read from the LEAF upwards so the flag is honoured in either position.
|
|
74
|
+
setJsonMode(Boolean(globalOpt(actionCommand, 'json')));
|
|
75
|
+
const path = [];
|
|
76
|
+
let node = actionCommand;
|
|
77
|
+
while (node) {
|
|
78
|
+
path.unshift(node.name());
|
|
79
|
+
node = node.parent;
|
|
80
|
+
}
|
|
81
|
+
setCommandPath(path.join(' '));
|
|
82
|
+
});
|
|
83
|
+
return program;
|
|
84
|
+
};
|
|
85
|
+
const main = async () => {
|
|
86
|
+
const program = buildProgram();
|
|
87
|
+
explainUnknownOptions(program);
|
|
88
|
+
applyExitOverride(program, error => {
|
|
89
|
+
// commander's own exits (help, version, bad usage) keep their codes
|
|
90
|
+
process.exit(error.exitCode === 0 ? 0 : EXIT.user);
|
|
91
|
+
});
|
|
92
|
+
await program.parseAsync(normalizeArgv(process.argv, collectFlags(program)));
|
|
93
|
+
};
|
|
94
|
+
// Only drive the CLI when this module is the process entry point; the test
|
|
95
|
+
// suite imports buildProgram() from here and must not trigger a parse+exit.
|
|
96
|
+
// `import.meta.url` is always the REAL path, so a symlinked bin (`npm link`, or a
|
|
97
|
+
// PATH shim that links dist/index.js) compares unequal to argv[1] and the CLI exits
|
|
98
|
+
// 0 having printed nothing — silently, which is the worst possible failure. Resolve
|
|
99
|
+
// argv[1] through realpath before comparing.
|
|
100
|
+
const isEntryPoint = () => {
|
|
101
|
+
const entry = process.argv[1];
|
|
102
|
+
if (!entry)
|
|
103
|
+
return false;
|
|
104
|
+
let resolved = entry;
|
|
105
|
+
try {
|
|
106
|
+
resolved = realpathSync(entry);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// not a real file (bundled/virtual entry) — fall back to the raw argv value
|
|
110
|
+
}
|
|
111
|
+
return import.meta.url === pathToFileURL(resolved).href;
|
|
112
|
+
};
|
|
113
|
+
if (isEntryPoint()) {
|
|
114
|
+
main().catch(error => {
|
|
115
|
+
const caiError = error instanceof CaiError
|
|
116
|
+
? error
|
|
117
|
+
: new CaiError(error instanceof Error ? error.message : String(error), {
|
|
118
|
+
exitCode: EXIT.user,
|
|
119
|
+
code: 'UNEXPECTED',
|
|
120
|
+
});
|
|
121
|
+
emitError(caiError);
|
|
122
|
+
process.exit(caiError.exitCode);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/jsSource.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { userError } from './errors.js';
|
|
3
|
+
const readUtf8 = (source, encoding) => readFileSync(source, encoding);
|
|
4
|
+
/**
|
|
5
|
+
* Resolve an inline expression or a UTF-8 file before any caller performs a
|
|
6
|
+
* write. `-` deliberately maps to stdin's file descriptor.
|
|
7
|
+
*/
|
|
8
|
+
export const resolveJsSource = (opts, settings = {}, reader = readUtf8) => {
|
|
9
|
+
const inlineFlag = settings.inlineFlag ?? '--js';
|
|
10
|
+
const fileFlag = settings.fileFlag ?? '--js-file';
|
|
11
|
+
const hasInline = opts.js !== undefined;
|
|
12
|
+
const hasFile = opts.jsFile !== undefined;
|
|
13
|
+
if (hasInline && hasFile) {
|
|
14
|
+
throw userError(`${inlineFlag} and ${fileFlag} are mutually exclusive.`, 'CONFLICTING_JS_SOURCE');
|
|
15
|
+
}
|
|
16
|
+
if (hasInline)
|
|
17
|
+
return opts.js;
|
|
18
|
+
if (hasFile) {
|
|
19
|
+
try {
|
|
20
|
+
return reader(opts.jsFile === '-' ? 0 : opts.jsFile, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw userError(`${fileFlag} "${opts.jsFile}" is not a readable UTF-8 file: ` +
|
|
24
|
+
`${error instanceof Error ? error.message : error}`, 'UNREADABLE_JS_FILE');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (settings.required !== false) {
|
|
28
|
+
throw userError(`Pass ${inlineFlag} <expression> or ${fileFlag} <path|->.`, 'MISSING_JS_SOURCE');
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=jsSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsSource.js","sourceRoot":"","sources":["../src/jsSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAevC,MAAM,QAAQ,GAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAEjF;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAqB,EACrB,WAA6B,EAAE,EAC/B,SAAqB,QAAQ,EACT,EAAE;IACtB,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,IAAI,MAAM,CAAA;IAChD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,WAAW,CAAA;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,KAAK,SAAS,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAA;IAEzC,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,SAAS,CACb,GAAG,UAAU,QAAQ,QAAQ,0BAA0B,EACvD,uBAAuB,CACxB,CAAA;IACH,CAAC;IACD,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC,EAAE,CAAA;IAC7B,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAO,EAAE,MAAM,CAAC,CAAA;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,CACb,GAAG,QAAQ,KAAK,IAAI,CAAC,MAAM,kCAAkC;gBAC3D,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,EACrD,oBAAoB,CACrB,CAAA;QACH,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAChC,MAAM,SAAS,CAAC,QAAQ,UAAU,oBAAoB,QAAQ,YAAY,EAAE,mBAAmB,CAAC,CAAA;IAClG,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const NODE_PROP_WRITE_KEYS = new Set([
|
|
2
|
+
'value',
|
|
3
|
+
'valueLabel',
|
|
4
|
+
'valueJs',
|
|
5
|
+
'expressionValue',
|
|
6
|
+
'expressionValueJs',
|
|
7
|
+
'useExpression',
|
|
8
|
+
]);
|
|
9
|
+
const isExplicitNodePropWrite = (value) => Boolean(value) &&
|
|
10
|
+
typeof value === 'object' &&
|
|
11
|
+
!Array.isArray(value) &&
|
|
12
|
+
Object.keys(value).some(key => NODE_PROP_WRITE_KEYS.has(key));
|
|
13
|
+
/**
|
|
14
|
+
* `add_node.props` is a map of per-prop write objects. Humans and skills naturally
|
|
15
|
+
* pass a direct map (`{"channel":"C123"}`), so accept both forms and normalize
|
|
16
|
+
* direct values to the backend's exact `{value: ...}` contract.
|
|
17
|
+
*/
|
|
18
|
+
export const normalizeNodePropWrites = (props) => Object.fromEntries(Object.entries(props).map(([key, value]) => [
|
|
19
|
+
key,
|
|
20
|
+
isExplicitNodePropWrite(value) ? value : { value },
|
|
21
|
+
]));
|
|
22
|
+
export const nodePropsFromPayload = (payload) => {
|
|
23
|
+
if (Array.isArray(payload))
|
|
24
|
+
return payload;
|
|
25
|
+
if (!payload || typeof payload !== 'object')
|
|
26
|
+
return [];
|
|
27
|
+
const record = payload;
|
|
28
|
+
for (const key of ['props', 'data', 'summary']) {
|
|
29
|
+
if (Array.isArray(record[key]))
|
|
30
|
+
return record[key];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
};
|
|
34
|
+
export const hasConfiguredPropValue = (prop) => ![prop.value, prop.valueJs, prop.expressionValue, prop.expressionValueJs].every(value => value === undefined || value === null || value === '');
|
|
35
|
+
// This mirrors the backend's TEXT_FAMILY_PROP_INPUT_TYPES. Callers always send
|
|
36
|
+
// valueJs; the backend chooses the stored field and get_node_props decompiles it
|
|
37
|
+
// back into one of these two readback channels.
|
|
38
|
+
const EXPRESSION_STORED_IN_VALUE = new Set([
|
|
39
|
+
'TEXT',
|
|
40
|
+
'SHORT_TEXT',
|
|
41
|
+
'LONG_TEXT',
|
|
42
|
+
'JSON',
|
|
43
|
+
'SQL',
|
|
44
|
+
'CUSTOM_DATA',
|
|
45
|
+
]);
|
|
46
|
+
export const expressionReadbackChannel = (prop) => Boolean(prop.allowsExpressionMode) &&
|
|
47
|
+
!EXPRESSION_STORED_IN_VALUE.has(String(prop.inputType ?? ''))
|
|
48
|
+
? 'expressionValueJs'
|
|
49
|
+
: 'valueJs';
|
|
50
|
+
const shellQuote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
|
|
51
|
+
const propName = (prop) => prop.name ?? prop.key;
|
|
52
|
+
const propNextCommand = (nodeId, prop, fallbackName) => {
|
|
53
|
+
const name = propName(prop ?? {}) ?? fallbackName;
|
|
54
|
+
if (prop?.remoteOptions) {
|
|
55
|
+
return (`cai node options ${nodeId} --prop ${name} --query "<option label>"; then ` +
|
|
56
|
+
`cai node set ${nodeId} --prop ${name} --value <exact-returned-value> ` +
|
|
57
|
+
'--label "<exact-returned-label>"');
|
|
58
|
+
}
|
|
59
|
+
const options = prop?.options ?? [];
|
|
60
|
+
if (options.length > 0) {
|
|
61
|
+
const values = options
|
|
62
|
+
.map(option => option.value ?? option.id)
|
|
63
|
+
.filter(value => value !== undefined);
|
|
64
|
+
const first = values[0];
|
|
65
|
+
if (first !== undefined) {
|
|
66
|
+
const multi = [
|
|
67
|
+
'MULTI_SELECT',
|
|
68
|
+
'MULTI_SELECT_DROPDOWN',
|
|
69
|
+
'STATIC_MULTI_SELECT_DROPDOWN',
|
|
70
|
+
].includes(String(prop?.inputType ?? ''));
|
|
71
|
+
const selected = multi ? [first] : first;
|
|
72
|
+
const choices = options
|
|
73
|
+
.map(option => {
|
|
74
|
+
const value = option.value ?? option.id;
|
|
75
|
+
const label = option.label ?? option.name ?? value;
|
|
76
|
+
return `${JSON.stringify(value)} (${String(label)})`;
|
|
77
|
+
})
|
|
78
|
+
.join(', ');
|
|
79
|
+
return `cai node set ${nodeId} --prop ${name} --value ${shellQuote(typeof selected === 'string' ? selected : JSON.stringify(selected))}; advertised choices: ${choices}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const supportsExpression = EXPRESSION_STORED_IN_VALUE.has(String(prop?.inputType ?? '')) ||
|
|
83
|
+
Boolean(prop?.allowsExpressionMode);
|
|
84
|
+
if (supportsExpression) {
|
|
85
|
+
return (`Choose by intent for ${name}: literal -> cai node set ${nodeId} --prop ${name} ` +
|
|
86
|
+
`--value <value>; runtime-derived -> cai expr context ${nodeId} --prop ${name}, then ` +
|
|
87
|
+
`cai expr set ${nodeId} --prop ${name} --js <expression>`);
|
|
88
|
+
}
|
|
89
|
+
return `cai node set ${nodeId} --prop ${name} --value <value>`;
|
|
90
|
+
};
|
|
91
|
+
/** Pure readiness projection used by `cai node status` and its tests. */
|
|
92
|
+
export const buildNodeReadiness = (nodeId, record, props) => {
|
|
93
|
+
const connectionId = record.connectionId ?? record.data?.connectionId ?? null;
|
|
94
|
+
const requireAuth = Boolean(record.requireAuth ?? record.data?.requireAuth);
|
|
95
|
+
const missingConnection = requireAuth && !connectionId;
|
|
96
|
+
const pendingReloadProps = props
|
|
97
|
+
.filter(prop => prop.reloadProps && prop.enabled !== false && !hasConfiguredPropValue(prop))
|
|
98
|
+
.map(prop => prop.name ?? prop.key)
|
|
99
|
+
.filter((name) => Boolean(name));
|
|
100
|
+
const pendingReloadSet = new Set(pendingReloadProps);
|
|
101
|
+
const missingRequiredProps = props
|
|
102
|
+
.filter(prop => prop.required &&
|
|
103
|
+
prop.enabled !== false &&
|
|
104
|
+
!hasConfiguredPropValue(prop) &&
|
|
105
|
+
!pendingReloadSet.has(prop.name ?? prop.key ?? ''))
|
|
106
|
+
.map(prop => prop.name ?? prop.key)
|
|
107
|
+
.filter((name) => Boolean(name));
|
|
108
|
+
const propsByName = new Map(props
|
|
109
|
+
.map(prop => [propName(prop), prop])
|
|
110
|
+
.filter((entry) => Boolean(entry[0])));
|
|
111
|
+
const outputs = record.outputs ?? record.data?.outputs ?? [];
|
|
112
|
+
const outputPortTypes = (Array.isArray(outputs) ? outputs : [])
|
|
113
|
+
.map((output) => output?.dataType)
|
|
114
|
+
.filter((value) => typeof value === 'string' && value.length > 0);
|
|
115
|
+
// get_node.outputs reports connection-port wrappers such as
|
|
116
|
+
// output.node.<id>#data. That says where a value came from, not what the
|
|
117
|
+
// process returned, and must never make downstream expression readiness true.
|
|
118
|
+
const processOutputType = record.processOutput?.dataType ?? record.data?.processOutput?.dataType ?? null;
|
|
119
|
+
const componentOutputType = record.resolvedOutputType ?? record.componentOutputType ?? null;
|
|
120
|
+
const outputTypes = [processOutputType ?? componentOutputType].filter((value) => typeof value === 'string' && value.length > 0);
|
|
121
|
+
const outputTypeSource = processOutputType
|
|
122
|
+
? 'processOutput'
|
|
123
|
+
: componentOutputType
|
|
124
|
+
? 'component'
|
|
125
|
+
: outputPortTypes.length
|
|
126
|
+
? 'port-wrapper'
|
|
127
|
+
: 'none';
|
|
128
|
+
const isUnresolvedType = (type) => /(^|[.#])any$|unknown|unresolved/i.test(type) ||
|
|
129
|
+
/^node\./.test(type) ||
|
|
130
|
+
/^output\.node\./.test(type);
|
|
131
|
+
const outputTypeStatus = processOutputType
|
|
132
|
+
? outputTypes.some(isUnresolvedType)
|
|
133
|
+
? 'unresolved'
|
|
134
|
+
: 'concrete'
|
|
135
|
+
: componentOutputType || outputPortTypes.length > 0
|
|
136
|
+
? 'unresolved'
|
|
137
|
+
: 'none';
|
|
138
|
+
const configurationBlockers = [
|
|
139
|
+
...(missingConnection ? ['connection'] : []),
|
|
140
|
+
...missingRequiredProps.map(name => `required prop: ${name}`),
|
|
141
|
+
...pendingReloadProps.map(name => `reload selector: ${name}`),
|
|
142
|
+
];
|
|
143
|
+
const blockedBy = [
|
|
144
|
+
...configurationBlockers,
|
|
145
|
+
...(outputTypeStatus === 'unresolved' ? ['output type'] : []),
|
|
146
|
+
];
|
|
147
|
+
const readyForRun = configurationBlockers.length === 0;
|
|
148
|
+
const readyForExpressions = readyForRun;
|
|
149
|
+
const readyForDownstreamExpressions = readyForRun && outputTypeStatus === 'concrete';
|
|
150
|
+
const next = missingConnection
|
|
151
|
+
? `cai connection list --node ${record.nodeSlug ?? record.data?.nodeSlug ?? '<nodeSlug>'}; then cai node set-connection ${nodeId} --connection <id> (if none exist, run cai connection connect ${record.nodeSlug ?? record.data?.nodeSlug ?? '<nodeSlug>'} and list again)`
|
|
152
|
+
: missingRequiredProps.length
|
|
153
|
+
? propNextCommand(nodeId, propsByName.get(missingRequiredProps[0]), missingRequiredProps[0])
|
|
154
|
+
: pendingReloadProps.length
|
|
155
|
+
? propNextCommand(nodeId, propsByName.get(pendingReloadProps[0]), pendingReloadProps[0])
|
|
156
|
+
: outputTypeStatus === 'unresolved'
|
|
157
|
+
? `cai run node ${nodeId} --inputs <values.json>`
|
|
158
|
+
: `cai expr context ${nodeId} --prop <prop>`;
|
|
159
|
+
return {
|
|
160
|
+
nodeId,
|
|
161
|
+
requireAuth,
|
|
162
|
+
connectionId,
|
|
163
|
+
missingConnection,
|
|
164
|
+
missingRequiredProps,
|
|
165
|
+
pendingReloadProps,
|
|
166
|
+
outputTypeStatus,
|
|
167
|
+
outputTypes,
|
|
168
|
+
outputPortTypes,
|
|
169
|
+
outputTypeSource,
|
|
170
|
+
readyForExpressions,
|
|
171
|
+
readyForRun,
|
|
172
|
+
readyForDownstreamExpressions,
|
|
173
|
+
blockedBy,
|
|
174
|
+
next,
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=nodeProps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeProps.js","sourceRoot":"","sources":["../src/nodeProps.ts"],"names":[],"mappings":"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"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { SCRUBBED_HINT } from './errors.js';
|
|
2
|
+
let jsonMode = false;
|
|
3
|
+
let commandPath = 'cai';
|
|
4
|
+
const warnings = [];
|
|
5
|
+
export const setJsonMode = (value) => {
|
|
6
|
+
jsonMode = value;
|
|
7
|
+
};
|
|
8
|
+
export const isJsonMode = () => jsonMode;
|
|
9
|
+
export const setCommandPath = (value) => {
|
|
10
|
+
commandPath = value;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Never let a silent null pass unremarked — the engine turns several real
|
|
14
|
+
* failures (unknown op on a CType, missing injected source, a null resolved
|
|
15
|
+
* config) into a quiet null. Warnings go to stderr so `--json` stdout stays
|
|
16
|
+
* pipeable, and are also embedded in the JSON envelope.
|
|
17
|
+
*/
|
|
18
|
+
export const warn = (message) => {
|
|
19
|
+
warnings.push(message);
|
|
20
|
+
process.stderr.write(`warning: ${message}\n`);
|
|
21
|
+
};
|
|
22
|
+
export const emit = (data, human) => {
|
|
23
|
+
if (jsonMode) {
|
|
24
|
+
const envelope = { ok: true, command: commandPath, data };
|
|
25
|
+
if (warnings.length)
|
|
26
|
+
envelope.warnings = [...warnings];
|
|
27
|
+
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
human();
|
|
31
|
+
};
|
|
32
|
+
export const emitError = (error) => {
|
|
33
|
+
if (jsonMode) {
|
|
34
|
+
const envelope = {
|
|
35
|
+
ok: false,
|
|
36
|
+
command: commandPath,
|
|
37
|
+
error: {
|
|
38
|
+
code: error.code,
|
|
39
|
+
message: error.message,
|
|
40
|
+
...(error.scrubbed ? { scrubbed: true } : {}),
|
|
41
|
+
...(error.detail !== undefined ? { detail: error.detail } : {}),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
if (warnings.length)
|
|
45
|
+
envelope.warnings = [...warnings];
|
|
46
|
+
process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
process.stderr.write(`error: ${error.message}\n`);
|
|
50
|
+
if (error.scrubbed)
|
|
51
|
+
process.stderr.write(`\n${SCRUBBED_HINT}\n`);
|
|
52
|
+
};
|
|
53
|
+
const cell = (value) => {
|
|
54
|
+
if (value === null || value === undefined)
|
|
55
|
+
return '-';
|
|
56
|
+
if (typeof value === 'object')
|
|
57
|
+
return JSON.stringify(value);
|
|
58
|
+
return String(value);
|
|
59
|
+
};
|
|
60
|
+
/** Left-aligned fixed-width table. Empty rows print a dash line, never nothing. */
|
|
61
|
+
export const table = (columns, rows) => {
|
|
62
|
+
if (rows.length === 0)
|
|
63
|
+
return '(none)';
|
|
64
|
+
const body = rows.map(r => r.map(cell));
|
|
65
|
+
const widths = columns.map((c, i) => Math.max(c.length, ...body.map(r => (r[i] ?? '').length)));
|
|
66
|
+
const line = (cells) => cells
|
|
67
|
+
.map((c, i) => c.padEnd(widths[i]))
|
|
68
|
+
.join(' ')
|
|
69
|
+
.trimEnd();
|
|
70
|
+
return [line(columns), line(widths.map(w => '-'.repeat(w))), ...body.map(line)].join('\n');
|
|
71
|
+
};
|
|
72
|
+
export const printTable = (columns, rows) => {
|
|
73
|
+
process.stdout.write(`${table(columns, rows)}\n`);
|
|
74
|
+
};
|
|
75
|
+
export const printKeyValues = (pairs) => {
|
|
76
|
+
const width = Math.max(...pairs.map(([k]) => k.length));
|
|
77
|
+
for (const [key, value] of pairs) {
|
|
78
|
+
process.stdout.write(`${key.padEnd(width)} ${cell(value)}\n`);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export const truncate = (value, max = 80) => {
|
|
82
|
+
const text = cell(value);
|
|
83
|
+
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=output.js.map
|