@crewx/cli 0.9.0-rc.146 → 0.9.0-rc.147
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.js +1 -113
- package/dist/bootstrap/crewx-cli.js +1 -84
- package/dist/builtin.js +5 -132
- package/dist/commands/agent.js +4 -118
- package/dist/commands/cal.js +2 -44
- package/dist/commands/db.js +4 -602
- package/dist/commands/detached.js +15 -620
- package/dist/commands/doctor.js +4 -649
- package/dist/commands/emit-trailer.js +2 -33
- package/dist/commands/execute.js +15 -294
- package/dist/commands/hook/command-marker.js +1 -5
- package/dist/commands/hook/install.js +8 -189
- package/dist/commands/hook/paths.js +1 -94
- package/dist/commands/hook/status.js +1 -86
- package/dist/commands/hook/uninstall.js +1 -71
- package/dist/commands/hook-dispatch.js +2 -180
- package/dist/commands/init.js +31 -437
- package/dist/commands/kill.js +1 -11
- package/dist/commands/log.js +3 -96
- package/dist/commands/parse-agent-message.js +1 -52
- package/dist/commands/parse-common-flags.js +3 -212
- package/dist/commands/ps.js +2 -117
- package/dist/commands/publish.js +7 -283
- package/dist/commands/query.js +16 -292
- package/dist/commands/registry.js +1 -33
- package/dist/commands/resolve-prompt.js +3 -76
- package/dist/commands/resolve-recipient.js +3 -47
- package/dist/commands/restart.js +18 -172
- package/dist/commands/result.js +1 -209
- package/dist/commands/shortcut.js +4 -253
- package/dist/commands/slack.js +16 -560
- package/dist/commands/stop.js +8 -119
- package/dist/commands/write-output.js +1 -24
- package/dist/index.js +1 -8
- package/dist/logging.js +10 -87
- package/dist/main.js +6 -289
- package/dist/register-builtin-tools.js +1 -9
- package/dist/slack/file-download.js +1 -134
- package/dist/slack/markdown.js +1 -33
- package/dist/utils/env-defaults.js +1 -15
- package/dist/utils/inherited-trace.js +1 -65
- package/dist/utils/product-package-root.js +1 -39
- package/dist/utils/sdk-compat.js +1 -120
- package/dist/utils/version.js +1 -28
- package/package.json +15 -15
|
@@ -1,76 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Supports three input channels:
|
|
6
|
-
* 1. --prompt-file <path> — read content from a file
|
|
7
|
-
* 2. stdin pipe/redirect — read from process.stdin when not a TTY
|
|
8
|
-
* 3. argv prompt — positional argument passed directly on the command line
|
|
9
|
-
*
|
|
10
|
-
* When multiple sources are present, argv is used as a short label/prefix
|
|
11
|
-
* and the file/stdin content is appended after a blank line.
|
|
12
|
-
*/
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.readStdin = readStdin;
|
|
15
|
-
exports.resolvePrompt = resolvePrompt;
|
|
16
|
-
const fs_1 = require("fs");
|
|
17
|
-
function decodePromptFile(promptFile) {
|
|
18
|
-
const contents = (0, fs_1.readFileSync)(promptFile);
|
|
19
|
-
if (contents.length >= 3
|
|
20
|
-
&& contents[0] === 0xef
|
|
21
|
-
&& contents[1] === 0xbb
|
|
22
|
-
&& contents[2] === 0xbf) {
|
|
23
|
-
return contents.subarray(3).toString('utf8');
|
|
24
|
-
}
|
|
25
|
-
if (contents.length >= 2 && contents[0] === 0xff && contents[1] === 0xfe) {
|
|
26
|
-
return contents.subarray(2).toString('utf16le');
|
|
27
|
-
}
|
|
28
|
-
if (contents.length >= 2 && contents[0] === 0xfe && contents[1] === 0xff) {
|
|
29
|
-
const payload = contents.subarray(2);
|
|
30
|
-
for (let index = 0; index + 1 < payload.length; index += 2) {
|
|
31
|
-
const first = payload[index];
|
|
32
|
-
payload[index] = payload[index + 1];
|
|
33
|
-
payload[index + 1] = first;
|
|
34
|
-
}
|
|
35
|
-
return payload.toString('utf16le');
|
|
36
|
-
}
|
|
37
|
-
return contents.toString('utf8');
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Read all bytes from stdin (pipe or redirect).
|
|
41
|
-
* Returns empty string when stdin is a TTY (interactive terminal).
|
|
42
|
-
*/
|
|
43
|
-
async function readStdin() {
|
|
44
|
-
if (process.stdin.isTTY)
|
|
45
|
-
return '';
|
|
46
|
-
const chunks = [];
|
|
47
|
-
for await (const chunk of process.stdin)
|
|
48
|
-
chunks.push(chunk);
|
|
49
|
-
return Buffer.concat(chunks).toString('utf8').trimEnd();
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Resolve the final prompt from argv, stdin pipe, or --prompt-file.
|
|
53
|
-
*
|
|
54
|
-
* Priority:
|
|
55
|
-
* 1. promptFile is specified → read file content
|
|
56
|
-
* 2. argv is present → use argv (stdin is NOT read — prevents hang in child processes)
|
|
57
|
-
* 3. argv is empty, no promptFile → read stdin pipe/redirect
|
|
58
|
-
* 4. argv + promptFile both present → `${argv}\n\n${fileContent}`
|
|
59
|
-
* 5. Neither present → return '' (caller decides error handling)
|
|
60
|
-
*
|
|
61
|
-
* @param _readStdin - injectable stdin reader, defaults to the module-level
|
|
62
|
-
* readStdin. Exposed as a parameter so unit tests can substitute a stub
|
|
63
|
-
* without fighting ESM module binding rules.
|
|
64
|
-
*/
|
|
65
|
-
async function resolvePrompt(argvPrompt, promptFile, _readStdin = readStdin) {
|
|
66
|
-
let external = '';
|
|
67
|
-
if (promptFile) {
|
|
68
|
-
external = decodePromptFile(promptFile).trimEnd();
|
|
69
|
-
}
|
|
70
|
-
else if (!argvPrompt) {
|
|
71
|
-
external = (await _readStdin()).trimEnd();
|
|
72
|
-
}
|
|
73
|
-
if (argvPrompt && external)
|
|
74
|
-
return `${argvPrompt}\n\n${external}`;
|
|
75
|
-
return external || argvPrompt;
|
|
76
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.readStdin=f;exports.resolvePrompt=o;const s=require("fs");function u(n){const t=(0,s.readFileSync)(n);if(t.length>=3&&t[0]===239&&t[1]===187&&t[2]===191){return t.subarray(3).toString("utf8")}if(t.length>=2&&t[0]===255&&t[1]===254){return t.subarray(2).toString("utf16le")}if(t.length>=2&&t[0]===254&&t[1]===255){const r=t.subarray(2);for(let e=0;e+1<r.length;e+=2){const i=r[e];r[e]=r[e+1];r[e+1]=i}return r.toString("utf16le")}return t.toString("utf8")}async function f(){if(process.stdin.isTTY)return"";const n=[];for await(const t of process.stdin)n.push(t);return Buffer.concat(n).toString("utf8").trimEnd()}async function o(n,t,r=f){let e="";if(t){e=u(t).trimEnd()}else if(!n){e=(await r()).trimEnd()}if(n&&e)return`${n}
|
|
2
|
+
|
|
3
|
+
${e}`;return e||n}
|
|
@@ -1,47 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.resolveRecipient = resolveRecipient;
|
|
5
|
-
class RecipientResolutionError extends Error {
|
|
6
|
-
constructor(message) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = 'RecipientResolutionError';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
exports.RecipientResolutionError = RecipientResolutionError;
|
|
12
|
-
function resolveRecipient(options) {
|
|
13
|
-
const toRef = normalizeRecipient(options.toFlag, true);
|
|
14
|
-
const positionalRef = normalizeRecipient(options.positionalRef, false);
|
|
15
|
-
if (toRef && positionalRef && toRef !== positionalRef) {
|
|
16
|
-
throw new RecipientResolutionError(`Recipient was specified twice: --to ${toRef.slice(1)} conflicts with positional ${positionalRef}.`);
|
|
17
|
-
}
|
|
18
|
-
const agentRef = toRef ?? positionalRef;
|
|
19
|
-
if (agentRef)
|
|
20
|
-
return { agentRef };
|
|
21
|
-
if (!options.agentContext)
|
|
22
|
-
return { agentRef: '@crewx' };
|
|
23
|
-
const hintedId = options.bodyForHint?.match(/^@(\S+)/u)?.[1];
|
|
24
|
-
const retryId = hintedId ?? '<agent-id>';
|
|
25
|
-
const command = options.command ?? 'query';
|
|
26
|
-
const retryArgs = (options.invocationArgs ?? []).map(formatRetryArgument).join(' ');
|
|
27
|
-
const retryCommand = `crewx ${command} --to ${retryId}${retryArgs ? ` ${retryArgs}` : ''}`;
|
|
28
|
-
throw new RecipientResolutionError('No recipient was specified. Agent calls must set one explicitly; nothing was run.\n' +
|
|
29
|
-
`Retry command: ${retryCommand}\n` +
|
|
30
|
-
'To ask the built-in assistant on purpose, use --to crewx.');
|
|
31
|
-
}
|
|
32
|
-
function normalizeRecipient(value, required) {
|
|
33
|
-
if (value === undefined)
|
|
34
|
-
return undefined;
|
|
35
|
-
const id = value.trim().replace(/^@/u, '');
|
|
36
|
-
if (!id) {
|
|
37
|
-
if (required)
|
|
38
|
-
throw new RecipientResolutionError('--to requires an agent id.');
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
return `@${id}`;
|
|
42
|
-
}
|
|
43
|
-
function formatRetryArgument(value) {
|
|
44
|
-
if (!/\s/u.test(value))
|
|
45
|
-
return value;
|
|
46
|
-
return `"${value.replaceAll('"', '\\"')}"`;
|
|
47
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.RecipientResolutionError=void 0;exports.resolveRecipient=d;class r extends Error{constructor(t){super(t);this.name="RecipientResolutionError"}}exports.RecipientResolutionError=r;function d(e){const t=c(e.toFlag,true);const n=c(e.positionalRef,false);if(t&&n&&t!==n){throw new r(`Recipient was specified twice: --to ${t.slice(1)} conflicts with positional ${n}.`)}const i=t??n;if(i)return{agentRef:i};if(!e.agentContext)return{agentRef:"@crewx"};const s=e.bodyForHint?.match(/^@(\S+)/u)?.[1];const u=s??"<agent-id>";const a=e.command??"query";const o=(e.invocationArgs??[]).map(l).join(" ");const f=`crewx ${a} --to ${u}${o?` ${o}`:""}`;throw new r(`No recipient was specified. Agent calls must set one explicitly; nothing was run.
|
|
2
|
+
Retry command: ${f}
|
|
3
|
+
To ask the built-in assistant on purpose, use --to crewx.`)}function c(e,t){if(e===void 0)return void 0;const n=e.trim().replace(/^@/u,"");if(!n){if(t)throw new r("--to requires an agent id.");return void 0}return`@${n}`}function l(e){if(!/\s/u.test(e))return e;return`"${e.replaceAll('"','\\"')}"`}
|
package/dist/commands/restart.js
CHANGED
|
@@ -1,172 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* observed (`terminalReason: 'runner_lost'`): it may still be running, so it is refused
|
|
20
|
-
* by default (same decision as the SDK's `isTaskRetryableByDefault`).
|
|
21
|
-
* - A new taskId is generated; the original task row is never mutated.
|
|
22
|
-
* - metadata.restartedFromTaskId (+ retriedFromTaskId for compat) is recorded.
|
|
23
|
-
* - The Web UI `TSK.RETRY` system-message prefix is reused verbatim.
|
|
24
|
-
* - stdout carries the agent final response; guidance/errors go to stderr.
|
|
25
|
-
*/
|
|
26
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
exports.handleRestart = handleRestart;
|
|
28
|
-
const sdk_1 = require("@crewx/sdk");
|
|
29
|
-
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
30
|
-
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
31
|
-
/**
|
|
32
|
-
* Build the retry system-message prefix.
|
|
33
|
-
* Intentionally identical to the server `ThreadService.retryTask()` prefix so
|
|
34
|
-
* stored conversations / parsers stay compatible. `type="retry"` is preserved.
|
|
35
|
-
*/
|
|
36
|
-
function buildRetryPrefix(originalTaskId) {
|
|
37
|
-
return (`<crewx_system_message type="retry">\n` +
|
|
38
|
-
`Retrying a failed task.\n` +
|
|
39
|
-
`You must run \`crewx dreaming --task=${originalTaskId}\` to review where it stopped before continuing.\n` +
|
|
40
|
-
`</crewx_system_message>\n\n`);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Recover the effective provider from a task row's `metadata` JSON.
|
|
44
|
-
* The SDK persists the resolved provider as `metadata.provider`. Returns
|
|
45
|
-
* the string when present and non-empty, otherwise `undefined` so the
|
|
46
|
-
* agent's configured provider default is used.
|
|
47
|
-
*/
|
|
48
|
-
function parseTaskMetadata(metadata) {
|
|
49
|
-
if (!metadata)
|
|
50
|
-
return {};
|
|
51
|
-
try {
|
|
52
|
-
const parsed = JSON.parse(metadata);
|
|
53
|
-
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
54
|
-
? parsed
|
|
55
|
-
: {};
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return {};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
function extractProvider(metadata) {
|
|
62
|
-
const provider = metadata.provider;
|
|
63
|
-
return typeof provider === 'string' && provider.length > 0 ? provider : undefined;
|
|
64
|
-
}
|
|
65
|
-
async function handleRestart(args) {
|
|
66
|
-
const verbose = args.includes('--verbose');
|
|
67
|
-
const taskId = args.find((a) => !a.startsWith('--'));
|
|
68
|
-
if (!taskId) {
|
|
69
|
-
process.stderr.write('Usage: crewx restart <task-id>\n');
|
|
70
|
-
process.exit(1);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const repo = new sdk_1.TaskRepository();
|
|
74
|
-
const original = repo.getTask(taskId);
|
|
75
|
-
if (!original) {
|
|
76
|
-
process.stderr.write(`Error: Task not found: ${taskId}\n`);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (!(0, sdk_1.isTaskRetryableByDefault)(original)) {
|
|
81
|
-
if ((0, sdk_1.normalizeTaskStatus)(original) === 'failed') {
|
|
82
|
-
// failed + runner_lost: the run was marked failed without anyone seeing it end.
|
|
83
|
-
process.stderr.write(`Error: Task ${taskId} was not restarted: the end of the run was not observed (runner lost), ` +
|
|
84
|
-
`so it may have done part of the work or may still be running. ` +
|
|
85
|
-
`Check it with \`crewx log ${taskId}\` or \`crewx ps\` before running it again.\n`);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
process.stderr.write(`Error: Task ${taskId} is not in failed state (current: ${original.status ?? 'unknown'}). ` +
|
|
89
|
-
`Only failed tasks can be restarted.\n`);
|
|
90
|
-
}
|
|
91
|
-
process.exit(1);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
if (!original.prompt) {
|
|
95
|
-
process.stderr.write(`Error: Task ${taskId} has no prompt to restart.\n`);
|
|
96
|
-
process.exit(1);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (!original.agent_id) {
|
|
100
|
-
process.stderr.write(`Error: Task ${taskId} has no agent to restart.\n`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const mode = original.mode === 'query' ? 'query' : 'execute';
|
|
105
|
-
const agentRef = `@${original.agent_id}`;
|
|
106
|
-
const newTaskId = (0, sdk_1.generateId)('tsk');
|
|
107
|
-
const restartPrompt = `${buildRetryPrefix(taskId)}${original.prompt}`;
|
|
108
|
-
// model: reuse the original task row value when present, otherwise fall back
|
|
109
|
-
// to the agent's configured default (resolved inside Crewx).
|
|
110
|
-
const model = original.model ?? undefined;
|
|
111
|
-
// provider: recovered from metadata.provider (SDK-persisted). Falls back to
|
|
112
|
-
// the agent's configured provider when absent. This preserves a
|
|
113
|
-
// `crewx x --provider ...` choice across restart.
|
|
114
|
-
const originalMetadata = parseTaskMetadata(original.metadata);
|
|
115
|
-
const provider = extractProvider(originalMetadata);
|
|
116
|
-
const originalWasOverdrive = originalMetadata.overdrive === true;
|
|
117
|
-
const originalOverdriveMode = originalMetadata.overdriveState === 'latch' ? 'latch' : 'count';
|
|
118
|
-
(0, sdk_1.setAuditVerbose)(verbose);
|
|
119
|
-
if (verbose) {
|
|
120
|
-
process.stderr.write(`🔁 Restart: ${taskId} → ${newTaskId}\n`);
|
|
121
|
-
process.stderr.write(`🤖 Agent: ${agentRef} Mode: ${mode}\n`);
|
|
122
|
-
if (original.thread_id)
|
|
123
|
-
process.stderr.write(`🔗 Thread: ${original.thread_id}\n`);
|
|
124
|
-
process.stderr.write('─'.repeat(60) + '\n');
|
|
125
|
-
}
|
|
126
|
-
const crewx = await (0, crewx_cli_1.createCliCrewx)();
|
|
127
|
-
const sdkOptions = {
|
|
128
|
-
taskId: newTaskId,
|
|
129
|
-
threadId: original.thread_id ?? undefined,
|
|
130
|
-
model,
|
|
131
|
-
provider,
|
|
132
|
-
...(originalWasOverdrive ? { overdrive: { mode: originalOverdriveMode } } : {}),
|
|
133
|
-
metadata: {
|
|
134
|
-
restartedFromTaskId: taskId,
|
|
135
|
-
// Back-compat / search convenience: mirror the Web UI metadata key.
|
|
136
|
-
retriedFromTaskId: taskId,
|
|
137
|
-
...(originalWasOverdrive ? {
|
|
138
|
-
overdrive: true,
|
|
139
|
-
overdriveState: originalOverdriveMode,
|
|
140
|
-
overdriveMode: mode,
|
|
141
|
-
} : {}),
|
|
142
|
-
},
|
|
143
|
-
trace: (0, inherited_trace_1.readInheritedTrace)(),
|
|
144
|
-
};
|
|
145
|
-
let exitCode = 0;
|
|
146
|
-
try {
|
|
147
|
-
const result = mode === 'query'
|
|
148
|
-
? await crewx.query(agentRef, restartPrompt, sdkOptions)
|
|
149
|
-
: await crewx.execute(agentRef, restartPrompt, sdkOptions);
|
|
150
|
-
if (result.ok) {
|
|
151
|
-
process.stdout.write(result.data + '\n');
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
const errMsg = result.error?.message ?? 'Restart failed';
|
|
155
|
-
const resultTaskId = result.meta?.taskId ?? newTaskId;
|
|
156
|
-
process.stderr.write(`Error: ${errMsg}\n`);
|
|
157
|
-
process.stderr.write(`taskId=${resultTaskId}\n`);
|
|
158
|
-
exitCode = 1;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
163
|
-
process.stderr.write(`Error: ${errMsg}\n`);
|
|
164
|
-
process.stderr.write(`taskId=${newTaskId}\n`);
|
|
165
|
-
exitCode = 1;
|
|
166
|
-
}
|
|
167
|
-
finally {
|
|
168
|
-
await crewx.close();
|
|
169
|
-
}
|
|
170
|
-
if (exitCode !== 0)
|
|
171
|
-
process.exit(exitCode);
|
|
172
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.handleRestart=I;const n=require("@crewx/sdk");const x=require("../bootstrap/crewx-cli");const $=require("../utils/inherited-trace");function T(o){return`<crewx_system_message type="retry">
|
|
2
|
+
Retrying a failed task.
|
|
3
|
+
You must run \`crewx dreaming --task=${o}\` to review where it stopped before continuing.
|
|
4
|
+
</crewx_system_message>
|
|
5
|
+
|
|
6
|
+
`}function _(o){if(!o)return{};try{const t=JSON.parse(o);return t&&typeof t==="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function b(o){const t=o.provider;return typeof t==="string"&&t.length>0?t:void 0}async function I(o){const t=o.includes("--verbose");const r=o.find(s=>!s.startsWith("--"));if(!r){process.stderr.write("Usage: crewx restart <task-id>\n");process.exit(1);return}const v=new n.TaskRepository;const e=v.getTask(r);if(!e){process.stderr.write(`Error: Task not found: ${r}
|
|
7
|
+
`);process.exit(1);return}if(!(0,n.isTaskRetryableByDefault)(e)){if((0,n.normalizeTaskStatus)(e)==="failed"){process.stderr.write(`Error: Task ${r} was not restarted: the end of the run was not observed (runner lost), so it may have done part of the work or may still be running. Check it with \`crewx log ${r}\` or \`crewx ps\` before running it again.
|
|
8
|
+
`)}else{process.stderr.write(`Error: Task ${r} is not in failed state (current: ${e.status??"unknown"}). Only failed tasks can be restarted.
|
|
9
|
+
`)}process.exit(1);return}if(!e.prompt){process.stderr.write(`Error: Task ${r} has no prompt to restart.
|
|
10
|
+
`);process.exit(1);return}if(!e.agent_id){process.stderr.write(`Error: Task ${r} has no agent to restart.
|
|
11
|
+
`);process.exit(1);return}const d=e.mode==="query"?"query":"execute";const c=`@${e.agent_id}`;const a=(0,n.generateId)("tsk");const f=`${T(r)}${e.prompt}`;const y=e.model??void 0;const u=_(e.metadata);const h=b(u);const w=u.overdrive===true;const k=u.overdriveState==="latch"?"latch":"count";(0,n.setAuditVerbose)(t);if(t){process.stderr.write(`\u{1F501} Restart: ${r} \u2192 ${a}
|
|
12
|
+
`);process.stderr.write(`\u{1F916} Agent: ${c} Mode: ${d}
|
|
13
|
+
`);if(e.thread_id)process.stderr.write(`\u{1F517} Thread: ${e.thread_id}
|
|
14
|
+
`);process.stderr.write("\u2500".repeat(60)+"\n")}const p=await(0,x.createCliCrewx)();const g={taskId:a,threadId:e.thread_id??void 0,model:y,provider:h,...w?{overdrive:{mode:k}}:{},metadata:{restartedFromTaskId:r,retriedFromTaskId:r,...w?{overdrive:true,overdriveState:k,overdriveMode:d}:{}},trace:(0,$.readInheritedTrace)()};let i=0;try{const s=d==="query"?await p.query(c,f,g):await p.execute(c,f,g);if(s.ok){process.stdout.write(s.data+"\n")}else{const l=s.error?.message??"Restart failed";const m=s.meta?.taskId??a;process.stderr.write(`Error: ${l}
|
|
15
|
+
`);process.stderr.write(`taskId=${m}
|
|
16
|
+
`);i=1}}catch(s){const l=s instanceof Error?s.message:String(s);process.stderr.write(`Error: ${l}
|
|
17
|
+
`);process.stderr.write(`taskId=${a}
|
|
18
|
+
`);i=1}finally{await p.close()}if(i!==0)process.exit(i)}
|
package/dist/commands/result.js
CHANGED
|
@@ -1,209 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* crewx result handler.
|
|
4
|
-
* Retrieves the result of a completed task by its ID.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* crewx result <task-id> Print raw result
|
|
8
|
-
* crewx result <task-id> --json Print full task record as JSON
|
|
9
|
-
* crewx result <task-id> --wait=<seconds> Poll (1s interval) up to the given
|
|
10
|
-
* number of seconds for
|
|
11
|
-
* the task to leave 'pending'/'running'. Exit 124 on
|
|
12
|
-
* timeout. --wait=0 behaves like no --wait
|
|
13
|
-
* (single immediate check).
|
|
14
|
-
* crewx result List recent tasks (latest 10)
|
|
15
|
-
*/
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.handleResult = handleResult;
|
|
18
|
-
const sdk_1 = require("@crewx/sdk");
|
|
19
|
-
const repository_1 = require("@crewx/sdk/repository");
|
|
20
|
-
const cal_1 = require("./cal");
|
|
21
|
-
const POLL_INTERVAL_MS = 1000;
|
|
22
|
-
const REAP_INTERVAL_MS = 10_000;
|
|
23
|
-
/**
|
|
24
|
-
* A run whose end was not observed is `failed` with the structured reason `runner_lost`, not a
|
|
25
|
-
* status of its own: it may have done part of the work or may still be running.
|
|
26
|
-
*/
|
|
27
|
-
function isRunnerLost(task) {
|
|
28
|
-
return task.status === 'failed' && (0, repository_1.readTaskTerminalReason)(task) === 'runner_lost';
|
|
29
|
-
}
|
|
30
|
-
function statusIcon(task) {
|
|
31
|
-
if (isRunnerLost(task))
|
|
32
|
-
return '⚠️';
|
|
33
|
-
switch (task.status) {
|
|
34
|
-
case 'pending': return '🕓';
|
|
35
|
-
case 'running': return '⏳';
|
|
36
|
-
case 'success': return '✅';
|
|
37
|
-
case 'failed': return '❌';
|
|
38
|
-
case 'stopped': return '⏹';
|
|
39
|
-
default: return '❓';
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function isActiveStatus(status) {
|
|
43
|
-
return status === 'pending' || status === 'running';
|
|
44
|
-
}
|
|
45
|
-
function sleep(ms) {
|
|
46
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
47
|
-
}
|
|
48
|
-
function resultCommandId(status) {
|
|
49
|
-
switch (status) {
|
|
50
|
-
case 'pending': return 'crewx.result-pending';
|
|
51
|
-
case 'running': return 'crewx.result-running';
|
|
52
|
-
case 'success': return 'crewx.result-done';
|
|
53
|
-
case 'failed':
|
|
54
|
-
case 'stopped':
|
|
55
|
-
return 'crewx.result-terminal-abnormal';
|
|
56
|
-
default: return 'crewx.result';
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function writeResultCalFooter(task, lastWaitSeconds) {
|
|
60
|
-
const params = { taskId: task.id };
|
|
61
|
-
if (task.agent_id)
|
|
62
|
-
params.agent = task.agent_id;
|
|
63
|
-
if (task.thread_id)
|
|
64
|
-
params.thread = task.thread_id;
|
|
65
|
-
if (isActiveStatus(task.status)) {
|
|
66
|
-
params.wait = String((0, cal_1.suggestWaitSeconds)({
|
|
67
|
-
startedAt: task.started_at,
|
|
68
|
-
lastWaitSeconds,
|
|
69
|
-
}));
|
|
70
|
-
}
|
|
71
|
-
(0, cal_1.writeCalFooter)({ commandId: resultCommandId(task.status), params });
|
|
72
|
-
}
|
|
73
|
-
function formatRuntimeDuration(startedAt, now = Date.now()) {
|
|
74
|
-
const startedAtMs = Date.parse(startedAt);
|
|
75
|
-
const elapsedSeconds = Number.isFinite(startedAtMs)
|
|
76
|
-
? Math.max(0, Math.floor((now - startedAtMs) / 1000))
|
|
77
|
-
: 0;
|
|
78
|
-
const hours = Math.floor(elapsedSeconds / 3600);
|
|
79
|
-
const minutes = Math.floor((elapsedSeconds % 3600) / 60);
|
|
80
|
-
const seconds = elapsedSeconds % 60;
|
|
81
|
-
if (hours > 0)
|
|
82
|
-
return `${hours}h ${minutes}m ${seconds}s`;
|
|
83
|
-
if (minutes > 0)
|
|
84
|
-
return `${minutes}m ${seconds}s`;
|
|
85
|
-
return `${seconds}s`;
|
|
86
|
-
}
|
|
87
|
-
/** Parses `--wait=<seconds>`. Returns undefined when the flag is absent. */
|
|
88
|
-
function parseWaitSeconds(args) {
|
|
89
|
-
const arg = args.find(a => a.startsWith('--wait='));
|
|
90
|
-
if (arg === undefined)
|
|
91
|
-
return undefined;
|
|
92
|
-
const n = Number(arg.slice('--wait='.length));
|
|
93
|
-
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
94
|
-
}
|
|
95
|
-
async function handleResult(args) {
|
|
96
|
-
const jsonMode = args.includes('--json');
|
|
97
|
-
const waitSeconds = parseWaitSeconds(args);
|
|
98
|
-
const taskId = args.find(a => !a.startsWith('--'));
|
|
99
|
-
const repo = new repository_1.TaskRepository();
|
|
100
|
-
const initialReaped = repo.reapOrphanedTasks({ tickIntervalMs: REAP_INTERVAL_MS });
|
|
101
|
-
if (initialReaped > 0)
|
|
102
|
-
console.error(`Reaped ${initialReaped} orphaned task(s)`);
|
|
103
|
-
if (!taskId) {
|
|
104
|
-
const all = repo.getAllTasks();
|
|
105
|
-
const recent = all.slice(0, 10);
|
|
106
|
-
if (recent.length === 0) {
|
|
107
|
-
console.log('No tasks found.');
|
|
108
|
-
console.log('Tip: Run `crewx query` or `crewx execute` to start a task.');
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
console.log('Recent Tasks (latest 10)\n');
|
|
112
|
-
recent.forEach((task, idx) => {
|
|
113
|
-
const icon = statusIcon(task);
|
|
114
|
-
console.log(`${idx + 1}. ${icon} ${task.id}`);
|
|
115
|
-
console.log(` Agent: ${task.agent_id ?? '—'} Mode: ${task.mode ?? '—'}`);
|
|
116
|
-
console.log(` Started: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.started_at))}`);
|
|
117
|
-
if (task.completed_at) {
|
|
118
|
-
console.log(` Completed: ${(0, sdk_1.formatDisplayTimestamp)(new Date(task.completed_at))}`);
|
|
119
|
-
}
|
|
120
|
-
console.log('');
|
|
121
|
-
});
|
|
122
|
-
console.log('Tip: Run `crewx result <task-id>` to see full output.');
|
|
123
|
-
if (!jsonMode)
|
|
124
|
-
writeResultCalFooter(recent[0]);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
let task = repo.getTask(taskId);
|
|
128
|
-
if (!task) {
|
|
129
|
-
console.error(`Error: Task not found: ${taskId}`);
|
|
130
|
-
process.exit(1);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (waitSeconds !== undefined && waitSeconds > 0 && isActiveStatus(task.status)) {
|
|
134
|
-
const deadline = Date.now() + waitSeconds * 1000;
|
|
135
|
-
let lastReapAt = Date.now();
|
|
136
|
-
while (task && isActiveStatus(task.status)) {
|
|
137
|
-
if (Date.now() >= deadline) {
|
|
138
|
-
console.error(`Task ${taskId} is still ${task.status} (waited ${waitSeconds}s; ` +
|
|
139
|
-
`running for ${formatRuntimeDuration(task.started_at)}). ` +
|
|
140
|
-
'Not stalled — check again with a longer wait.');
|
|
141
|
-
writeResultCalFooter(task, waitSeconds);
|
|
142
|
-
process.exit(124);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
await sleep(Math.min(POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
|
|
146
|
-
if (Date.now() - lastReapAt >= REAP_INTERVAL_MS) {
|
|
147
|
-
const reaped = repo.reapOrphanedTasks({ tickIntervalMs: REAP_INTERVAL_MS });
|
|
148
|
-
if (reaped > 0)
|
|
149
|
-
console.error(`Reaped ${reaped} orphaned task(s)`);
|
|
150
|
-
lastReapAt = Date.now();
|
|
151
|
-
}
|
|
152
|
-
task = repo.getTask(taskId);
|
|
153
|
-
if (!task) {
|
|
154
|
-
console.error(`Error: Task not found: ${taskId}`);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (jsonMode) {
|
|
161
|
-
console.log(JSON.stringify(task, null, 2));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (task.status === 'pending') {
|
|
165
|
-
console.error(`🕓 Task ${taskId} is pending (waiting to start — runner has not adopted the task yet).`);
|
|
166
|
-
const nextWaitSeconds = (0, cal_1.suggestWaitSeconds)({
|
|
167
|
-
startedAt: task.started_at,
|
|
168
|
-
lastWaitSeconds: waitSeconds,
|
|
169
|
-
});
|
|
170
|
-
console.error(`Use \`crewx result ${taskId} --wait=${nextWaitSeconds}\` to wait for completion.`);
|
|
171
|
-
writeResultCalFooter(task, waitSeconds);
|
|
172
|
-
process.exit(1);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (task.status === 'running') {
|
|
176
|
-
console.error(`Task ${taskId} is still running.`);
|
|
177
|
-
const nextWaitSeconds = (0, cal_1.suggestWaitSeconds)({
|
|
178
|
-
startedAt: task.started_at,
|
|
179
|
-
lastWaitSeconds: waitSeconds,
|
|
180
|
-
});
|
|
181
|
-
console.error(`Use \`crewx result ${taskId} --wait=${nextWaitSeconds}\` to wait longer or \`crewx log ${taskId}\` to inspect progress.`);
|
|
182
|
-
writeResultCalFooter(task, waitSeconds);
|
|
183
|
-
process.exit(1);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
if (task.status === 'stopped') {
|
|
187
|
-
if (task.result !== null && task.result !== undefined) {
|
|
188
|
-
console.log(task.result);
|
|
189
|
-
}
|
|
190
|
-
console.error(`⏹ Task ${taskId} was stopped by user: ${task.error ?? 'no further details'}.`);
|
|
191
|
-
writeResultCalFooter(task);
|
|
192
|
-
process.exit(1);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
if (isRunnerLost(task)) {
|
|
196
|
-
console.error(`⚠️ Task ${taskId} runner lost before completion: ${task.error ?? 'no further details'}.`);
|
|
197
|
-
writeResultCalFooter(task);
|
|
198
|
-
process.exit(1);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (task.status === 'failed') {
|
|
202
|
-
console.error(`Task ${taskId} failed: ${task.error ?? 'unknown error'}`);
|
|
203
|
-
writeResultCalFooter(task);
|
|
204
|
-
process.exit(1);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
console.log(task.result ?? '');
|
|
208
|
-
writeResultCalFooter(task);
|
|
209
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.handleResult=M;const g=require("@crewx/sdk");const w=require("@crewx/sdk/repository");const d=require("./cal");const x=1e3;const f=1e4;function $(t){return t.status==="failed"&&(0,w.readTaskTerminalReason)(t)==="runner_lost"}function T(t){if($(t))return"\u26A0\uFE0F";switch(t.status){case"pending":return"\u{1F553}";case"running":return"\u23F3";case"success":return"\u2705";case"failed":return"\u274C";case"stopped":return"\u23F9";default:return"\u2753"}}function p(t){return t==="pending"||t==="running"}function _(t){return new Promise(s=>setTimeout(s,t))}function R(t){switch(t){case"pending":return"crewx.result-pending";case"running":return"crewx.result-running";case"success":return"crewx.result-done";case"failed":case"stopped":return"crewx.result-terminal-abnormal";default:return"crewx.result"}}function c(t,s){const r={taskId:t.id};if(t.agent_id)r.agent=t.agent_id;if(t.thread_id)r.thread=t.thread_id;if(p(t.status)){r.wait=String((0,d.suggestWaitSeconds)({startedAt:t.started_at,lastWaitSeconds:s}))}(0,d.writeCalFooter)({commandId:R(t.status),params:r})}function S(t,s=Date.now()){const r=Date.parse(t);const n=Number.isFinite(r)?Math.max(0,Math.floor((s-r)/1e3)):0;const i=Math.floor(n/3600);const u=Math.floor(n%3600/60);const e=n%60;if(i>0)return`${i}h ${u}m ${e}s`;if(u>0)return`${u}m ${e}s`;return`${e}s`}function k(t){const s=t.find(n=>n.startsWith("--wait="));if(s===void 0)return void 0;const r=Number(s.slice("--wait=".length));return Number.isFinite(r)&&r>=0?r:0}async function M(t){const s=t.includes("--json");const r=k(t);const n=t.find(o=>!o.startsWith("--"));const i=new w.TaskRepository;const u=i.reapOrphanedTasks({tickIntervalMs:f});if(u>0)console.error(`Reaped ${u} orphaned task(s)`);if(!n){const o=i.getAllTasks();const l=o.slice(0,10);if(l.length===0){console.log("No tasks found.");console.log("Tip: Run `crewx query` or `crewx execute` to start a task.");return}console.log("Recent Tasks (latest 10)\n");l.forEach((a,m)=>{const h=T(a);console.log(`${m+1}. ${h} ${a.id}`);console.log(` Agent: ${a.agent_id??"\u2014"} Mode: ${a.mode??"\u2014"}`);console.log(` Started: ${(0,g.formatDisplayTimestamp)(new Date(a.started_at))}`);if(a.completed_at){console.log(` Completed: ${(0,g.formatDisplayTimestamp)(new Date(a.completed_at))}`)}console.log("")});console.log("Tip: Run `crewx result <task-id>` to see full output.");if(!s)c(l[0]);return}let e=i.getTask(n);if(!e){console.error(`Error: Task not found: ${n}`);process.exit(1);return}if(r!==void 0&&r>0&&p(e.status)){const o=Date.now()+r*1e3;let l=Date.now();while(e&&p(e.status)){if(Date.now()>=o){console.error(`Task ${n} is still ${e.status} (waited ${r}s; running for ${S(e.started_at)}). Not stalled \u2014 check again with a longer wait.`);c(e,r);process.exit(124);return}await _(Math.min(x,Math.max(0,o-Date.now())));if(Date.now()-l>=f){const a=i.reapOrphanedTasks({tickIntervalMs:f});if(a>0)console.error(`Reaped ${a} orphaned task(s)`);l=Date.now()}e=i.getTask(n);if(!e){console.error(`Error: Task not found: ${n}`);process.exit(1);return}}}if(s){console.log(JSON.stringify(e,null,2));return}if(e.status==="pending"){console.error(`\u{1F553} Task ${n} is pending (waiting to start \u2014 runner has not adopted the task yet).`);const o=(0,d.suggestWaitSeconds)({startedAt:e.started_at,lastWaitSeconds:r});console.error(`Use \`crewx result ${n} --wait=${o}\` to wait for completion.`);c(e,r);process.exit(1);return}if(e.status==="running"){console.error(`Task ${n} is still running.`);const o=(0,d.suggestWaitSeconds)({startedAt:e.started_at,lastWaitSeconds:r});console.error(`Use \`crewx result ${n} --wait=${o}\` to wait longer or \`crewx log ${n}\` to inspect progress.`);c(e,r);process.exit(1);return}if(e.status==="stopped"){if(e.result!==null&&e.result!==void 0){console.log(e.result)}console.error(`\u23F9 Task ${n} was stopped by user: ${e.error??"no further details"}.`);c(e);process.exit(1);return}if($(e)){console.error(`\u26A0\uFE0F Task ${n} runner lost before completion: ${e.error??"no further details"}.`);c(e);process.exit(1);return}if(e.status==="failed"){console.error(`Task ${n} failed: ${e.error??"unknown error"}`);c(e);process.exit(1);return}console.log(e.result??"");c(e)}
|