@crewx/cli 0.9.0-rc.8 → 0.9.0-rc.80
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/bootstrap/codex-writable-roots.d.ts +13 -0
- package/dist/bootstrap/codex-writable-roots.js +25 -0
- package/dist/bootstrap/crewx-cli.js +2 -1
- package/dist/builtin.js +1 -0
- package/dist/commands/agent.js +0 -58
- package/dist/commands/db.d.ts +1 -0
- package/dist/commands/db.js +191 -1
- package/dist/commands/doctor.d.ts +17 -0
- package/dist/commands/doctor.js +21 -11
- package/dist/commands/execute.d.ts +4 -0
- package/dist/commands/execute.js +103 -3
- package/dist/commands/init.js +22 -1
- package/dist/commands/log.js +4 -3
- package/dist/commands/parse-common-flags.d.ts +5 -1
- package/dist/commands/parse-common-flags.js +6 -2
- package/dist/commands/ps.js +7 -6
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.js +270 -0
- package/dist/commands/query.d.ts +1 -0
- package/dist/commands/query.js +11 -2
- package/dist/commands/registry.js +3 -1
- package/dist/commands/result.d.ts +7 -3
- package/dist/commands/result.js +41 -6
- package/dist/commands/shortcut.d.ts +1 -0
- package/dist/commands/shortcut.js +267 -0
- package/dist/commands/slack.js +2 -1
- package/dist/commands/write-output.d.ts +3 -0
- package/dist/commands/write-output.js +24 -0
- package/dist/logging.d.ts +1 -1
- package/dist/logging.js +3 -2
- package/dist/main.d.ts +3 -2
- package/dist/main.js +49 -7
- package/dist/utils/env-defaults.d.ts +2 -5
- package/dist/utils/env-defaults.js +10 -5
- package/dist/utils/sdk-compat.d.ts +21 -0
- package/dist/utils/sdk-compat.js +72 -0
- package/package.json +13 -11
package/dist/commands/execute.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Flags:
|
|
7
7
|
* --thread <name> Conversation thread name
|
|
8
8
|
* --provider <cli/xxx> Provider override
|
|
9
|
+
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
9
10
|
* --metadata <json> Extra metadata JSON (double-quoted object). Propagated to events/hooks/tracing.
|
|
10
11
|
* e.g. --metadata='{"workflow_id":"wf-1"}'
|
|
11
12
|
* --verbose Debug output mode (default: raw agent response only)
|
|
@@ -13,6 +14,9 @@
|
|
|
13
14
|
* --output-format <fmt> Output format (json|text|stream-json)
|
|
14
15
|
* --effort <level> Model effort (high|medium|low)
|
|
15
16
|
* -f/--prompt-file <path> Read task body from file (bypasses cmd.exe argv truncation)
|
|
17
|
+
* --detach Re-spawn as a detached runner; print task-id and exit 0 immediately.
|
|
18
|
+
* Ignored when CREWX_TRACE_ID is already set (recursive-spawn guard) or
|
|
19
|
+
* on win32 (unsupported — exits with an error).
|
|
16
20
|
*
|
|
17
21
|
* Stdin support:
|
|
18
22
|
* Pipe or redirect content into crewx x to supply the task body via stdin.
|
|
@@ -21,12 +25,72 @@
|
|
|
21
25
|
*/
|
|
22
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
27
|
exports.handleExecute = handleExecute;
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
29
|
+
const fs_1 = require("fs");
|
|
30
|
+
const path_1 = require("path");
|
|
31
|
+
const os_1 = require("os");
|
|
24
32
|
const sdk_1 = require("@crewx/sdk");
|
|
25
33
|
const parse_agent_message_1 = require("./parse-agent-message");
|
|
26
34
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
27
35
|
const resolve_prompt_1 = require("./resolve-prompt");
|
|
28
36
|
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
29
37
|
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
38
|
+
const write_output_1 = require("./write-output");
|
|
39
|
+
/**
|
|
40
|
+
* Split `--detach` out of argv, respecting the `--` literal-args sentinel
|
|
41
|
+
* (a `--detach` appearing after `--` is message text, not the flag).
|
|
42
|
+
*/
|
|
43
|
+
function extractDetachFlag(args) {
|
|
44
|
+
const rest = [];
|
|
45
|
+
let detach = false;
|
|
46
|
+
let escapeMode = false;
|
|
47
|
+
for (const arg of args) {
|
|
48
|
+
if (!escapeMode && arg === '--') {
|
|
49
|
+
escapeMode = true;
|
|
50
|
+
rest.push(arg);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!escapeMode && arg === '--detach') {
|
|
54
|
+
detach = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
rest.push(arg);
|
|
58
|
+
}
|
|
59
|
+
return { detach, rest };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Double-detach: re-spawn this same CLI entry (minus --detach) as a detached
|
|
63
|
+
* process so it survives the parent's exit. The task-id is pre-generated here
|
|
64
|
+
* and injected as CREWX_TRACE_ID so the runner's own task row is created under
|
|
65
|
+
* this id (see handleExecute's `selfTaskId` derivation below) — it doubles as
|
|
66
|
+
* both this task's row id and the root of any further delegation it spawns.
|
|
67
|
+
*
|
|
68
|
+
* stdout contract (script-parseable): task-id only, on the first line.
|
|
69
|
+
* Everything else goes to stderr.
|
|
70
|
+
*/
|
|
71
|
+
function runDetached(filteredArgs) {
|
|
72
|
+
const taskId = (0, sdk_1.generateId)('tsk');
|
|
73
|
+
const logDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx', 'logs');
|
|
74
|
+
if (!(0, fs_1.existsSync)(logDir))
|
|
75
|
+
(0, fs_1.mkdirSync)(logDir, { recursive: true });
|
|
76
|
+
const logPath = (0, path_1.join)(logDir, `${taskId}.log`);
|
|
77
|
+
const logFd = (0, fs_1.openSync)(logPath, 'a');
|
|
78
|
+
const entry = process.argv[1];
|
|
79
|
+
const child = (0, child_process_1.spawn)(process.execPath, [entry, 'x', ...filteredArgs], {
|
|
80
|
+
detached: true,
|
|
81
|
+
stdio: ['ignore', logFd, logFd],
|
|
82
|
+
env: { ...process.env, CREWX_TRACE_ID: taskId },
|
|
83
|
+
});
|
|
84
|
+
(0, fs_1.closeSync)(logFd);
|
|
85
|
+
child.on('error', (err) => {
|
|
86
|
+
process.stderr.write(`Failed to spawn detached runner: ${err.message}\n`);
|
|
87
|
+
});
|
|
88
|
+
child.unref();
|
|
89
|
+
console.log(taskId);
|
|
90
|
+
process.stderr.write(`Detached task ${taskId} started (log: ${logPath}).\n`);
|
|
91
|
+
process.stderr.write(`Use \`crewx result ${taskId} --wait=N\` to wait for completion.\n`);
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
30
94
|
/**
|
|
31
95
|
* Handle `crewx execute <agentRef> <message>` command.
|
|
32
96
|
*
|
|
@@ -34,7 +98,26 @@ const inherited_trace_1 = require("../utils/inherited-trace");
|
|
|
34
98
|
* --verbose: debug info written to stderr, response to stdout.
|
|
35
99
|
*/
|
|
36
100
|
async function handleExecute(args) {
|
|
37
|
-
const {
|
|
101
|
+
const { detach, rest: detachFilteredArgs } = extractDetachFlag(args);
|
|
102
|
+
if (detach) {
|
|
103
|
+
// Recursive-spawn guard: a CREWX_TRACE_ID already present means this
|
|
104
|
+
// process is itself running inside a traced context (either the
|
|
105
|
+
// respawned runner, or a delegated sub-call) — never chain a second
|
|
106
|
+
// detach off of it. Silently fall through to normal (synchronous) execution.
|
|
107
|
+
if (process.env['CREWX_TRACE_ID']) {
|
|
108
|
+
process.stderr.write('Note: --detach ignored (already running inside a traced context; CREWX_TRACE_ID is set).\n');
|
|
109
|
+
}
|
|
110
|
+
else if (process.platform === 'win32') {
|
|
111
|
+
console.error('Error: --detach is not supported on win32.');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
runDetached(detachFilteredArgs);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = (0, parse_common_flags_1.parseCommonFlags)(detachFilteredArgs);
|
|
38
121
|
const { agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest);
|
|
39
122
|
// No @mention → default to @crewx agent (matches cli-bak behaviour)
|
|
40
123
|
const agentRef = parsedAgentRef || '@crewx';
|
|
@@ -55,6 +138,7 @@ async function handleExecute(args) {
|
|
|
55
138
|
console.error('Options:');
|
|
56
139
|
console.error(' --thread <name> Conversation thread name');
|
|
57
140
|
console.error(' --provider <cli/xxx> Provider override');
|
|
141
|
+
console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
|
|
58
142
|
console.error(' --metadata <json> Extra metadata (JSON object, double-quoted).');
|
|
59
143
|
console.error(' Propagated to events/hooks/tracing.');
|
|
60
144
|
console.error(' Invalid JSON aborts with exit code 2.');
|
|
@@ -62,6 +146,7 @@ async function handleExecute(args) {
|
|
|
62
146
|
console.error(' --verbose Debug output mode');
|
|
63
147
|
console.error(' --config/-c <path> Config file path');
|
|
64
148
|
console.error(' --output-format <fmt> Output format (json|text|stream-json)');
|
|
149
|
+
console.error(' --out/-o <path> Save result to file (stdout suppressed)');
|
|
65
150
|
console.error(' --effort <level> Model effort (high|medium|low)');
|
|
66
151
|
console.error(' -f/--prompt-file <path> Read task body from file');
|
|
67
152
|
console.error(' --var key=value Template variable (repeatable)');
|
|
@@ -80,6 +165,8 @@ async function handleExecute(args) {
|
|
|
80
165
|
process.stderr.write(`🔗 Thread: ${thread}\n`);
|
|
81
166
|
if (provider)
|
|
82
167
|
process.stderr.write(`🔌 Provider: ${provider}\n`);
|
|
168
|
+
if (model)
|
|
169
|
+
process.stderr.write(`🧠 Model: ${model}\n`);
|
|
83
170
|
if (outputFormat)
|
|
84
171
|
process.stderr.write(`📄 Output-format: ${outputFormat}\n`);
|
|
85
172
|
if (effort)
|
|
@@ -97,20 +184,32 @@ async function handleExecute(args) {
|
|
|
97
184
|
process.stderr.write(`Error: ${msg}\n`);
|
|
98
185
|
process.exit(2);
|
|
99
186
|
}
|
|
187
|
+
const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
|
|
188
|
+
// A trace with a rootTraceId but no parentTaskId means the id was pre-assigned
|
|
189
|
+
// to *this* task itself (the detach runner's parent injects only CREWX_TRACE_ID,
|
|
190
|
+
// never CREWX_PARENT_TASK_ID — see execute.ts's runDetached), not inherited from
|
|
191
|
+
// an ancestor task in a delegation chain (which always carries both). It doubles
|
|
192
|
+
// as this task's own row id so `crewx result <task-id>` can find it.
|
|
193
|
+
const selfTaskId = inheritedTrace && !inheritedTrace.parentTaskId
|
|
194
|
+
? (inheritedTrace.rootTraceId || undefined)
|
|
195
|
+
: undefined;
|
|
100
196
|
let exitCode = 0;
|
|
101
197
|
try {
|
|
102
198
|
const result = await crewx.execute(agentRef, finalMessage, {
|
|
103
199
|
provider,
|
|
200
|
+
model,
|
|
104
201
|
effort: effort || undefined,
|
|
105
202
|
overdrive: overdrive || undefined,
|
|
106
203
|
threadId: thread,
|
|
204
|
+
taskId: selfTaskId,
|
|
107
205
|
metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
|
|
108
206
|
vars: Object.keys(vars).length > 0 ? vars : undefined,
|
|
109
|
-
trace:
|
|
207
|
+
trace: inheritedTrace,
|
|
110
208
|
});
|
|
111
209
|
if (!result.ok) {
|
|
112
210
|
const errMsg = result.error?.message ?? 'Execute failed';
|
|
113
211
|
console.error(errMsg);
|
|
212
|
+
(0, write_output_1.appendError)(out, errMsg);
|
|
114
213
|
exitCode = 1;
|
|
115
214
|
}
|
|
116
215
|
else {
|
|
@@ -123,7 +222,7 @@ async function handleExecute(args) {
|
|
|
123
222
|
process.stderr.write('\n📄 Response:\n');
|
|
124
223
|
process.stderr.write('─'.repeat(40) + '\n');
|
|
125
224
|
}
|
|
126
|
-
|
|
225
|
+
(0, write_output_1.writeResult)(out, result.data);
|
|
127
226
|
if (verbose) {
|
|
128
227
|
process.stderr.write('\n✅ Execute completed successfully\n');
|
|
129
228
|
}
|
|
@@ -132,6 +231,7 @@ async function handleExecute(args) {
|
|
|
132
231
|
catch (err) {
|
|
133
232
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
134
233
|
console.error(`Error: ${errMsg}`);
|
|
234
|
+
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
135
235
|
exitCode = 1;
|
|
136
236
|
}
|
|
137
237
|
finally {
|
package/dist/commands/init.js
CHANGED
|
@@ -52,6 +52,7 @@ const git = __importStar(require("isomorphic-git"));
|
|
|
52
52
|
const nodeFs = __importStar(require("fs"));
|
|
53
53
|
const os_1 = __importDefault(require("os"));
|
|
54
54
|
const repository_1 = require("@crewx/sdk/repository");
|
|
55
|
+
const sdk_1 = require("@crewx/sdk");
|
|
55
56
|
const install_1 = require("./hook/install");
|
|
56
57
|
const STATUSLINE_SCRIPT_NAME = 'claude-usage-statusline.js';
|
|
57
58
|
const STATUSLINE_SCRIPT_MARKER = 'CrewX claude-usage-statusline';
|
|
@@ -84,6 +85,11 @@ const CREWX_MARKER = '# CrewX runtime';
|
|
|
84
85
|
const CREWX_GITIGNORE = `# CrewX runtime
|
|
85
86
|
.crewx/
|
|
86
87
|
|
|
88
|
+
# Secrets (workspace .env — see docs/manual)
|
|
89
|
+
.env
|
|
90
|
+
.env.*
|
|
91
|
+
!.env.example
|
|
92
|
+
|
|
87
93
|
# Memory runtime state (regenerable from entries/)
|
|
88
94
|
memory/*/.dirty-summary
|
|
89
95
|
memory/*/graph.json
|
|
@@ -435,7 +441,7 @@ async function handleInit(opts) {
|
|
|
435
441
|
}
|
|
436
442
|
}
|
|
437
443
|
// Always create docs dirs and templates, regardless of whether yaml was skipped
|
|
438
|
-
for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi']) {
|
|
444
|
+
for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi', 'workflows']) {
|
|
439
445
|
try {
|
|
440
446
|
(0, fs_1.mkdirSync)((0, path_1.join)(target, dir), { recursive: true });
|
|
441
447
|
}
|
|
@@ -456,6 +462,21 @@ async function handleInit(opts) {
|
|
|
456
462
|
console.log(`✅ ${t.dir}/ ${action} (${t.file})`);
|
|
457
463
|
}
|
|
458
464
|
}
|
|
465
|
+
try {
|
|
466
|
+
const workflowTemplatesDir = (0, sdk_1.resolveWorkflowTemplatesPath)();
|
|
467
|
+
for (const filename of [sdk_1.WI_DEFAULT_FLOW_FILENAME, sdk_1.WI_PLAN_FLOW_FILENAME]) {
|
|
468
|
+
const sourcePath = (0, path_1.join)(workflowTemplatesDir, filename);
|
|
469
|
+
const targetPath = (0, path_1.join)(target, 'workflows', filename);
|
|
470
|
+
if (force || !(0, fs_1.existsSync)(targetPath)) {
|
|
471
|
+
const action = (0, fs_1.existsSync)(targetPath) ? 'updated' : 'created';
|
|
472
|
+
(0, fs_1.copyFileSync)(sourcePath, targetPath);
|
|
473
|
+
console.log(`✅ workflows/ ${action} (${filename})`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
catch (e) {
|
|
478
|
+
errors.push(`WORKFLOW_TEMPLATE_FAILED:${e.message}`);
|
|
479
|
+
}
|
|
459
480
|
// Always register workspace in ~/.crewx/crewx.db (best-effort, idempotent)
|
|
460
481
|
let workspaceId;
|
|
461
482
|
let slug;
|
package/dist/commands/log.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.handleLog = handleLog;
|
|
13
|
+
const sdk_1 = require("@crewx/sdk");
|
|
13
14
|
const repository_1 = require("@crewx/sdk/repository");
|
|
14
15
|
function statusIcon(status) {
|
|
15
16
|
switch (status) {
|
|
@@ -36,10 +37,10 @@ async function handleLog(args) {
|
|
|
36
37
|
console.log(`Status: ${statusIcon(task.status)} ${task.status}`);
|
|
37
38
|
console.log(`Agent: ${task.agent_id ?? '—'}`);
|
|
38
39
|
console.log(`Mode: ${task.mode ?? '—'}`);
|
|
39
|
-
console.log(`Started: ${new Date(task.started_at)
|
|
40
|
+
console.log(`Started: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.started_at))}`);
|
|
40
41
|
if (task.completed_at) {
|
|
41
42
|
const duration = new Date(task.completed_at).getTime() - new Date(task.started_at).getTime();
|
|
42
|
-
console.log(`Completed: ${new Date(task.completed_at)
|
|
43
|
+
console.log(`Completed: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.completed_at))} (${duration}ms)`);
|
|
43
44
|
}
|
|
44
45
|
console.log('='.repeat(60));
|
|
45
46
|
console.log('');
|
|
@@ -78,7 +79,7 @@ async function handleLog(args) {
|
|
|
78
79
|
: 'running...';
|
|
79
80
|
console.log(`${idx + 1}. ${icon} ${task.id}`);
|
|
80
81
|
console.log(` Agent: ${task.agent_id ?? '—'} Mode: ${task.mode ?? '—'}`);
|
|
81
|
-
console.log(` Started: ${new Date(task.started_at)
|
|
82
|
+
console.log(` Started: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.started_at))}`);
|
|
82
83
|
console.log(` Duration: ${duration}`);
|
|
83
84
|
console.log('');
|
|
84
85
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Common flag parser for query/execute commands.
|
|
3
3
|
*
|
|
4
4
|
* Supports both `--flag=value` and `--flag value` forms.
|
|
5
|
-
* Handles: --thread, --provider, --metadata, --verbose, --config/-c,
|
|
5
|
+
* Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
|
|
6
6
|
* --output-format, --effort, --prompt-file/-f, --overdrive.
|
|
7
7
|
*
|
|
8
8
|
* Strict mode: unknown --xxx tokens after known flags are consumed throw an
|
|
@@ -14,6 +14,8 @@ export interface CommonFlags {
|
|
|
14
14
|
thread?: string;
|
|
15
15
|
/** Provider override (e.g., cli/claude). */
|
|
16
16
|
provider?: string;
|
|
17
|
+
/** Model override (e.g., claude-sonnet-5). */
|
|
18
|
+
model?: string;
|
|
17
19
|
/** Raw metadata JSON string. */
|
|
18
20
|
metadata?: string;
|
|
19
21
|
/** Enable verbose/debug output mode. */
|
|
@@ -28,6 +30,8 @@ export interface CommonFlags {
|
|
|
28
30
|
promptFile?: string;
|
|
29
31
|
/** Whether overdrive (boost) is active for this request. */
|
|
30
32
|
overdrive: boolean;
|
|
33
|
+
/** Output file path for saving result (--out/-o). */
|
|
34
|
+
out?: string;
|
|
31
35
|
/** Template variables from --var key=value flags. */
|
|
32
36
|
vars: Record<string, string>;
|
|
33
37
|
/** Remaining non-flag positional arguments. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Common flag parser for query/execute commands.
|
|
4
4
|
*
|
|
5
5
|
* Supports both `--flag=value` and `--flag value` forms.
|
|
6
|
-
* Handles: --thread, --provider, --metadata, --verbose, --config/-c,
|
|
6
|
+
* Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
|
|
7
7
|
* --output-format, --effort, --prompt-file/-f, --overdrive.
|
|
8
8
|
*
|
|
9
9
|
* Strict mode: unknown --xxx tokens after known flags are consumed throw an
|
|
@@ -63,11 +63,13 @@ exports.UnknownOptionError = UnknownOptionError;
|
|
|
63
63
|
function parseCommonFlags(args) {
|
|
64
64
|
const thread = parseFlag(args, '--thread');
|
|
65
65
|
const provider = parseFlag(args, '--provider');
|
|
66
|
+
const model = parseFlag(args, '--model');
|
|
66
67
|
const metadata = parseFlag(args, '--metadata');
|
|
67
68
|
const config = parseFlag(args, '--config', '-c');
|
|
68
69
|
const outputFormat = parseFlag(args, '--output-format');
|
|
69
70
|
const effort = parseFlag(args, '--effort');
|
|
70
71
|
const promptFile = parseFlag(args, '--prompt-file', '-f');
|
|
72
|
+
const out = parseFlag(args, '--out', '-o');
|
|
71
73
|
const verbose = hasFlag(args, '--verbose');
|
|
72
74
|
const overdrive = hasFlag(args, '--overdrive');
|
|
73
75
|
// Collect consumed positions for known flags
|
|
@@ -75,11 +77,13 @@ function parseCommonFlags(args) {
|
|
|
75
77
|
const flagPairs = [
|
|
76
78
|
{ names: ['--thread'] },
|
|
77
79
|
{ names: ['--provider'] },
|
|
80
|
+
{ names: ['--model'] },
|
|
78
81
|
{ names: ['--metadata'] },
|
|
79
82
|
{ names: ['--config', '-c'] },
|
|
80
83
|
{ names: ['--output-format'] },
|
|
81
84
|
{ names: ['--effort'] },
|
|
82
85
|
{ names: ['--prompt-file', '-f'] },
|
|
86
|
+
{ names: ['--out', '-o'] },
|
|
83
87
|
];
|
|
84
88
|
// Parse --var key=value flags (multiple allowed; last value wins on duplicate keys)
|
|
85
89
|
const vars = {};
|
|
@@ -153,7 +157,7 @@ function parseCommonFlags(args) {
|
|
|
153
157
|
}
|
|
154
158
|
rest.push(token);
|
|
155
159
|
}
|
|
156
|
-
return { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, rest };
|
|
160
|
+
return { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest };
|
|
157
161
|
}
|
|
158
162
|
/**
|
|
159
163
|
* Parse metadata JSON string from --metadata flag.
|
package/dist/commands/ps.js
CHANGED
|
@@ -34,9 +34,9 @@ function isAgyCommand(codingAgentCommand) {
|
|
|
34
34
|
const base = firstToken.split('/').pop() ?? firstToken;
|
|
35
35
|
return base.startsWith('agy');
|
|
36
36
|
}
|
|
37
|
-
function getLastActive(task) {
|
|
37
|
+
function getLastActive(task, taskRepo) {
|
|
38
38
|
try {
|
|
39
|
-
const entries =
|
|
39
|
+
const entries = taskRepo.readLogsTail(task.id, 1)?.entries ?? [];
|
|
40
40
|
if (Array.isArray(entries) && entries.length > 0) {
|
|
41
41
|
const lastEntry = entries[entries.length - 1];
|
|
42
42
|
const ts = lastEntry?.timestamp;
|
|
@@ -59,9 +59,9 @@ function getLastActive(task) {
|
|
|
59
59
|
}
|
|
60
60
|
return { display: '—', isoTimestamp: null, logCapable: true };
|
|
61
61
|
}
|
|
62
|
-
function taskToRow(task) {
|
|
62
|
+
function taskToRow(task, taskRepo) {
|
|
63
63
|
const elapsed = formatElapsed(Date.now() - new Date(task.started_at).getTime());
|
|
64
|
-
const lastActive = getLastActive(task);
|
|
64
|
+
const lastActive = getLastActive(task, taskRepo);
|
|
65
65
|
return [
|
|
66
66
|
task.id,
|
|
67
67
|
task.agent_id ?? '—',
|
|
@@ -83,6 +83,7 @@ function renderTable(headers, rows) {
|
|
|
83
83
|
}
|
|
84
84
|
async function handlePs(args) {
|
|
85
85
|
const repo = new repository_1.TaskRepository();
|
|
86
|
+
repo.reapRunningWorkflowTasks();
|
|
86
87
|
const tasks = repo.getRunningTasks();
|
|
87
88
|
if (tasks.length === 0) {
|
|
88
89
|
console.log('No running tasks.');
|
|
@@ -90,7 +91,7 @@ async function handlePs(args) {
|
|
|
90
91
|
}
|
|
91
92
|
if (args.includes('--json')) {
|
|
92
93
|
const withLastActive = tasks.map((task) => {
|
|
93
|
-
const lastActive = getLastActive(task);
|
|
94
|
+
const lastActive = getLastActive(task, repo);
|
|
94
95
|
return {
|
|
95
96
|
...task,
|
|
96
97
|
last_active_at: lastActive.isoTimestamp,
|
|
@@ -101,7 +102,7 @@ async function handlePs(args) {
|
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
103
104
|
const headers = ['TASK ID', 'AGENT', 'PID', 'ELAPSED', 'MODE', 'LAST ACTIVE'];
|
|
104
|
-
const rows = tasks.map(taskToRow);
|
|
105
|
+
const rows = tasks.map((task) => taskToRow(task, repo));
|
|
105
106
|
renderTable(headers, rows);
|
|
106
107
|
console.log(`\n ${tasks.length} running task(s)`);
|
|
107
108
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handlePublish(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handlePublish = handlePublish;
|
|
37
|
+
/**
|
|
38
|
+
* crewx publish handler — thin CLI wrapper over @crewx/sdk/publish.
|
|
39
|
+
*
|
|
40
|
+
* Usage:
|
|
41
|
+
* crewx publish [dir] [--dry-run] [--version <semver>] [--json] [--upload]
|
|
42
|
+
*
|
|
43
|
+
* All scanning, exclusion-rule judgment, secret detection, hashing, and
|
|
44
|
+
* tar.gz packing lives in @crewx/sdk/publish (planPublish / packTemplate).
|
|
45
|
+
* Submit+upload (WI-SHR-20260806-013) lives in the same package
|
|
46
|
+
* (uploadToMarketplace) for the same reason — see that module's header.
|
|
47
|
+
* This command only parses argv, forwards options, reads auth.json
|
|
48
|
+
* (read-only — see readAuthJson()'s own doc), and renders the result.
|
|
49
|
+
*/
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const publish_1 = require("@crewx/sdk/publish");
|
|
52
|
+
const parse_common_flags_1 = require("./parse-common-flags");
|
|
53
|
+
function parsePublishFlags(args) {
|
|
54
|
+
const flags = { dryRun: false, json: false, help: false, upload: false };
|
|
55
|
+
for (let i = 0; i < args.length; i++) {
|
|
56
|
+
const arg = args[i];
|
|
57
|
+
if (arg === '--help' || arg === '-h') {
|
|
58
|
+
flags.help = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (arg === '--dry-run') {
|
|
62
|
+
flags.dryRun = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (arg === '--json') {
|
|
66
|
+
flags.json = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === '--upload') {
|
|
70
|
+
flags.upload = true;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (arg === '--version') {
|
|
74
|
+
const value = args[i + 1];
|
|
75
|
+
if (value === undefined)
|
|
76
|
+
throw new parse_common_flags_1.UnknownOptionError('--version requires a value');
|
|
77
|
+
flags.version = value;
|
|
78
|
+
i++;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg.startsWith('--version=')) {
|
|
82
|
+
flags.version = arg.slice('--version='.length);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (arg.startsWith('-')) {
|
|
86
|
+
throw new parse_common_flags_1.UnknownOptionError(`Unknown option: ${arg}`);
|
|
87
|
+
}
|
|
88
|
+
if (flags.dir === undefined) {
|
|
89
|
+
flags.dir = arg;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
throw new parse_common_flags_1.UnknownOptionError(`Unknown option: ${arg}`);
|
|
93
|
+
}
|
|
94
|
+
return flags;
|
|
95
|
+
}
|
|
96
|
+
function resolveWorkspaceDir(flags) {
|
|
97
|
+
return flags.dir ?? process.env['CREWX_WORKSPACE'] ?? process.cwd();
|
|
98
|
+
}
|
|
99
|
+
function printJson(payload) {
|
|
100
|
+
console.log(JSON.stringify(payload));
|
|
101
|
+
}
|
|
102
|
+
/** Prints the error and exits 1. Never returns (matches `process.exit`'s `never` type). */
|
|
103
|
+
function failWithError(err, json) {
|
|
104
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
105
|
+
if (json) {
|
|
106
|
+
printJson({ success: false, error: message });
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.error(`✗ ${message}`);
|
|
110
|
+
}
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
function printHelp() {
|
|
114
|
+
console.log(`
|
|
115
|
+
crewx publish — package a workspace as a distributable template archive
|
|
116
|
+
|
|
117
|
+
Usage:
|
|
118
|
+
crewx publish [dir] [--dry-run] [--version <semver>] [--json] [--upload]
|
|
119
|
+
|
|
120
|
+
Arguments:
|
|
121
|
+
dir Workspace to publish (default: $CREWX_WORKSPACE or cwd)
|
|
122
|
+
|
|
123
|
+
Options:
|
|
124
|
+
--dry-run Scan + build manifest only; do not write a .tgz
|
|
125
|
+
--version <ver> Override manifest version (semver, e.g. 1.0.0)
|
|
126
|
+
--json Print machine-readable JSON to stdout
|
|
127
|
+
--upload Submit + upload the packed archive to marketplace
|
|
128
|
+
(requires CREWX_MARKETPLACE_URL and a prior login;
|
|
129
|
+
ignored when combined with --dry-run)
|
|
130
|
+
--help, -h Show this help
|
|
131
|
+
|
|
132
|
+
Notes:
|
|
133
|
+
Without --upload, this command only scans the workspace, applies
|
|
134
|
+
exclusion rules, checks for secrets, and packs a local
|
|
135
|
+
.crewx/publish/<name>-<version>.tgz archive.
|
|
136
|
+
`.trim());
|
|
137
|
+
}
|
|
138
|
+
/** CREWX_MARKETPLACE_URL — same env var name as the server's MARKETPLACE_DISABLED check, never a second name. */
|
|
139
|
+
function requireMarketplaceUrl() {
|
|
140
|
+
const url = process.env['CREWX_MARKETPLACE_URL'];
|
|
141
|
+
if (!url) {
|
|
142
|
+
throw new Error('publish: [E_ENV_MISSING] CREWX_MARKETPLACE_URL is not set — this environment variable is required for upload');
|
|
143
|
+
}
|
|
144
|
+
return url;
|
|
145
|
+
}
|
|
146
|
+
async function handlePublish(args) {
|
|
147
|
+
const flags = parsePublishFlags(args);
|
|
148
|
+
if (flags.help) {
|
|
149
|
+
printHelp();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const dir = resolveWorkspaceDir(flags);
|
|
153
|
+
process.stderr.write(`[publish] scanning ${dir}...\n`);
|
|
154
|
+
let plan;
|
|
155
|
+
try {
|
|
156
|
+
plan = await (0, publish_1.planPublish)(dir, { version: flags.version });
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
failWithError(err, flags.json);
|
|
160
|
+
}
|
|
161
|
+
if (plan.secretFindings.length > 0) {
|
|
162
|
+
if (flags.json) {
|
|
163
|
+
printJson({ success: false, error: 'secret findings detected', findings: plan.secretFindings });
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.error('✗ secret findings detected — publish aborted');
|
|
167
|
+
for (const f of plan.secretFindings) {
|
|
168
|
+
console.error(` ${f.path}:${f.line} (${f.rule})`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
if (flags.dryRun) {
|
|
174
|
+
if (flags.json) {
|
|
175
|
+
printJson({
|
|
176
|
+
success: true,
|
|
177
|
+
dryRun: true,
|
|
178
|
+
workspace: dir,
|
|
179
|
+
manifest: plan.manifest,
|
|
180
|
+
included: plan.included,
|
|
181
|
+
excluded: plan.excluded,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.log('✓ dry-run — no archive written');
|
|
186
|
+
console.log(` workspace: ${dir}`);
|
|
187
|
+
console.log(` name: ${plan.manifest.name} version: ${plan.manifest.version}`);
|
|
188
|
+
console.log(` included: ${plan.included.length} files`);
|
|
189
|
+
console.log(` excluded: ${plan.excluded.length} entries`);
|
|
190
|
+
for (const e of plan.excluded) {
|
|
191
|
+
console.log(` ${e.path} (${e.rule})`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
// Resolved before packing (not after) so a doomed --upload run (no
|
|
197
|
+
// marketplace url / no session) never writes a stray .tgz to the
|
|
198
|
+
// workspace — WI-SHR-20260806-013 AC-U5.
|
|
199
|
+
let marketplaceUrl = '';
|
|
200
|
+
let accessToken = '';
|
|
201
|
+
if (flags.upload) {
|
|
202
|
+
try {
|
|
203
|
+
marketplaceUrl = requireMarketplaceUrl();
|
|
204
|
+
accessToken = (0, publish_1.readAuthJson)().access_token;
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
if (err instanceof Error && !err.message.startsWith('publish: [')) {
|
|
208
|
+
failWithError(new Error(`publish: [E_AUTH_EXPIRED] Authentication is missing or expired — please log in again — ${err.message}`), flags.json);
|
|
209
|
+
}
|
|
210
|
+
failWithError(err, flags.json);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
process.stderr.write(`[publish] packing ${plan.manifest.name}@${plan.manifest.version}...\n`);
|
|
214
|
+
let packed;
|
|
215
|
+
try {
|
|
216
|
+
packed = await (0, publish_1.packTemplate)(dir, { version: flags.version });
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
failWithError(err, flags.json);
|
|
220
|
+
}
|
|
221
|
+
const fileCount = packed.manifest.files.length;
|
|
222
|
+
const totalBytes = fs.statSync(packed.tgzPath).size;
|
|
223
|
+
let uploadResult;
|
|
224
|
+
if (flags.upload) {
|
|
225
|
+
process.stderr.write(`[publish] uploading ${packed.manifest.name}@${packed.manifest.version} to ${marketplaceUrl}...\n`);
|
|
226
|
+
try {
|
|
227
|
+
uploadResult = await (0, publish_1.uploadToMarketplace)({
|
|
228
|
+
tgzPath: packed.tgzPath,
|
|
229
|
+
manifest: packed.manifest,
|
|
230
|
+
baseUrl: marketplaceUrl,
|
|
231
|
+
accessToken,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
failWithError(err, flags.json);
|
|
236
|
+
}
|
|
237
|
+
process.stderr.write(`[publish] submit -> ${uploadResult.submitOutcome}\n`);
|
|
238
|
+
}
|
|
239
|
+
if (flags.json) {
|
|
240
|
+
printJson({
|
|
241
|
+
success: true,
|
|
242
|
+
tgzPath: packed.tgzPath,
|
|
243
|
+
fileCount,
|
|
244
|
+
totalBytes,
|
|
245
|
+
manifest: packed.manifest,
|
|
246
|
+
...(uploadResult
|
|
247
|
+
? {
|
|
248
|
+
slug: uploadResult.slug,
|
|
249
|
+
version: uploadResult.version,
|
|
250
|
+
artifactChecksum: uploadResult.artifactChecksum,
|
|
251
|
+
artifactSizeBytes: uploadResult.artifactSizeBytes,
|
|
252
|
+
submitOutcome: uploadResult.submitOutcome,
|
|
253
|
+
versionUpdate: uploadResult.versionUpdate,
|
|
254
|
+
serverVersionBefore: uploadResult.serverVersionBefore,
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
console.log(`✓ packed: ${packed.tgzPath}`);
|
|
261
|
+
console.log(` files: ${fileCount} bytes: ${totalBytes}`);
|
|
262
|
+
if (uploadResult) {
|
|
263
|
+
console.log(`✓ uploaded: ${uploadResult.slug}@${uploadResult.version} (${uploadResult.submitOutcome})`);
|
|
264
|
+
console.log(` artifactChecksum: ${uploadResult.artifactChecksum} artifactSizeBytes: ${uploadResult.artifactSizeBytes}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!flags.upload) {
|
|
268
|
+
console.error('⚠ To upload, use --upload — check the generated file path');
|
|
269
|
+
}
|
|
270
|
+
}
|
package/dist/commands/query.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Flags:
|
|
6
6
|
* --thread <name> Conversation thread name
|
|
7
7
|
* --provider <cli/xxx> Provider override
|
|
8
|
+
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
8
9
|
* --metadata <json> Extra metadata JSON (double-quoted object). Propagated to events/hooks/tracing.
|
|
9
10
|
* e.g. --metadata='{"workflow_id":"wf-1"}'
|
|
10
11
|
* --verbose Debug output mode (default: raw agent response only)
|