@crewx/cli 0.8.9 → 0.9.0-rc.1
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/commands/registry.js +1 -1
- package/dist/commands/restart.d.ts +23 -0
- package/dist/commands/restart.js +148 -0
- package/dist/main.js +6 -0
- package/package.json +6 -6
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* crewx restart handler.
|
|
3
|
+
* Restarts a failed task as a new task, reusing the original task's
|
|
4
|
+
* thread / agent / mode / model / provider. The `provider` column is not
|
|
5
|
+
* persisted on the task row, but the SDK records the effective provider in
|
|
6
|
+
* `metadata.provider`, so we recover it from there (falling back to the
|
|
7
|
+
* agent's configured provider when absent).
|
|
8
|
+
*
|
|
9
|
+
* Unlike the Web UI `Retry` (fire-and-forget), CLI `restart` awaits the new
|
|
10
|
+
* task to completion and prints the final response — the CLI process is the
|
|
11
|
+
* tracking owner, so it must not exit before the task finishes.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* crewx restart <task-id>
|
|
15
|
+
*
|
|
16
|
+
* Behavior:
|
|
17
|
+
* - Only tasks with status='failed' can be restarted.
|
|
18
|
+
* - A new taskId is generated; the original task row is never mutated.
|
|
19
|
+
* - metadata.restartedFromTaskId (+ retriedFromTaskId for compat) is recorded.
|
|
20
|
+
* - The Web UI `TSK.RETRY` system-message prefix is reused verbatim.
|
|
21
|
+
* - stdout carries the agent final response; guidance/errors go to stderr.
|
|
22
|
+
*/
|
|
23
|
+
export declare function handleRestart(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* crewx restart handler.
|
|
4
|
+
* Restarts a failed task as a new task, reusing the original task's
|
|
5
|
+
* thread / agent / mode / model / provider. The `provider` column is not
|
|
6
|
+
* persisted on the task row, but the SDK records the effective provider in
|
|
7
|
+
* `metadata.provider`, so we recover it from there (falling back to the
|
|
8
|
+
* agent's configured provider when absent).
|
|
9
|
+
*
|
|
10
|
+
* Unlike the Web UI `Retry` (fire-and-forget), CLI `restart` awaits the new
|
|
11
|
+
* task to completion and prints the final response — the CLI process is the
|
|
12
|
+
* tracking owner, so it must not exit before the task finishes.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* crewx restart <task-id>
|
|
16
|
+
*
|
|
17
|
+
* Behavior:
|
|
18
|
+
* - Only tasks with status='failed' can be restarted.
|
|
19
|
+
* - A new taskId is generated; the original task row is never mutated.
|
|
20
|
+
* - metadata.restartedFromTaskId (+ retriedFromTaskId for compat) is recorded.
|
|
21
|
+
* - The Web UI `TSK.RETRY` system-message prefix is reused verbatim.
|
|
22
|
+
* - stdout carries the agent final response; guidance/errors go to stderr.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.handleRestart = handleRestart;
|
|
26
|
+
const sdk_1 = require("@crewx/sdk");
|
|
27
|
+
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
28
|
+
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
29
|
+
/**
|
|
30
|
+
* Build the retry system-message prefix.
|
|
31
|
+
* Intentionally identical to the server `ThreadService.retryTask()` prefix so
|
|
32
|
+
* stored conversations / parsers stay compatible. `type="retry"` is preserved.
|
|
33
|
+
*/
|
|
34
|
+
function buildRetryPrefix(originalTaskId) {
|
|
35
|
+
return (`<crewx_system_message type="retry">\n` +
|
|
36
|
+
`Retrying a failed task.\n` +
|
|
37
|
+
`You must run \`crewx dreaming --task=${originalTaskId}\` to review where it stopped before continuing.\n` +
|
|
38
|
+
`</crewx_system_message>\n\n`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Recover the effective provider from a task row's `metadata` JSON.
|
|
42
|
+
* The SDK persists the resolved provider as `metadata.provider`. Returns
|
|
43
|
+
* the string when present and non-empty, otherwise `undefined` so the
|
|
44
|
+
* agent's configured provider default is used.
|
|
45
|
+
*/
|
|
46
|
+
function extractProvider(metadata) {
|
|
47
|
+
if (!metadata)
|
|
48
|
+
return undefined;
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(metadata);
|
|
51
|
+
const provider = parsed.provider;
|
|
52
|
+
return typeof provider === 'string' && provider.length > 0 ? provider : undefined;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function handleRestart(args) {
|
|
59
|
+
const verbose = args.includes('--verbose');
|
|
60
|
+
const taskId = args.find((a) => !a.startsWith('--'));
|
|
61
|
+
if (!taskId) {
|
|
62
|
+
process.stderr.write('Usage: crewx restart <task-id>\n');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const repo = new sdk_1.TaskRepository();
|
|
67
|
+
const original = repo.getTask(taskId);
|
|
68
|
+
if (!original) {
|
|
69
|
+
process.stderr.write(`Error: Task not found: ${taskId}\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (original.status !== 'failed') {
|
|
74
|
+
process.stderr.write(`Error: Task ${taskId} is not in failed state (current: ${original.status ?? 'unknown'}). ` +
|
|
75
|
+
`Only failed tasks can be restarted.\n`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!original.prompt) {
|
|
80
|
+
process.stderr.write(`Error: Task ${taskId} has no prompt to restart.\n`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!original.agent_id) {
|
|
85
|
+
process.stderr.write(`Error: Task ${taskId} has no agent to restart.\n`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const mode = original.mode === 'query' ? 'query' : 'execute';
|
|
90
|
+
const agentRef = `@${original.agent_id}`;
|
|
91
|
+
const newTaskId = (0, sdk_1.generateId)('tsk');
|
|
92
|
+
const restartPrompt = `${buildRetryPrefix(taskId)}${original.prompt}`;
|
|
93
|
+
// model: reuse the original task row value when present, otherwise fall back
|
|
94
|
+
// to the agent's configured default (resolved inside Crewx).
|
|
95
|
+
const model = original.model ?? undefined;
|
|
96
|
+
// provider: recovered from metadata.provider (SDK-persisted). Falls back to
|
|
97
|
+
// the agent's configured provider when absent. This preserves a
|
|
98
|
+
// `crewx x --provider ...` choice across restart.
|
|
99
|
+
const provider = extractProvider(original.metadata);
|
|
100
|
+
(0, sdk_1.setAuditVerbose)(verbose);
|
|
101
|
+
if (verbose) {
|
|
102
|
+
process.stderr.write(`🔁 Restart: ${taskId} → ${newTaskId}\n`);
|
|
103
|
+
process.stderr.write(`🤖 Agent: ${agentRef} Mode: ${mode}\n`);
|
|
104
|
+
if (original.thread_id)
|
|
105
|
+
process.stderr.write(`🔗 Thread: ${original.thread_id}\n`);
|
|
106
|
+
process.stderr.write('─'.repeat(60) + '\n');
|
|
107
|
+
}
|
|
108
|
+
const crewx = await (0, crewx_cli_1.createCliCrewx)();
|
|
109
|
+
const sdkOptions = {
|
|
110
|
+
taskId: newTaskId,
|
|
111
|
+
threadId: original.thread_id ?? undefined,
|
|
112
|
+
model,
|
|
113
|
+
provider,
|
|
114
|
+
metadata: {
|
|
115
|
+
restartedFromTaskId: taskId,
|
|
116
|
+
// Back-compat / search convenience: mirror the Web UI metadata key.
|
|
117
|
+
retriedFromTaskId: taskId,
|
|
118
|
+
},
|
|
119
|
+
trace: (0, inherited_trace_1.readInheritedTrace)(),
|
|
120
|
+
};
|
|
121
|
+
let exitCode = 0;
|
|
122
|
+
try {
|
|
123
|
+
const result = mode === 'query'
|
|
124
|
+
? await crewx.query(agentRef, restartPrompt, sdkOptions)
|
|
125
|
+
: await crewx.execute(agentRef, restartPrompt, sdkOptions);
|
|
126
|
+
if (result.ok) {
|
|
127
|
+
process.stdout.write(result.data + '\n');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const errMsg = result.error?.message ?? 'Restart failed';
|
|
131
|
+
const resultTaskId = result.meta?.taskId ?? newTaskId;
|
|
132
|
+
process.stderr.write(`Error: ${errMsg}\n`);
|
|
133
|
+
process.stderr.write(`taskId=${resultTaskId}\n`);
|
|
134
|
+
exitCode = 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
139
|
+
process.stderr.write(`Error: ${errMsg}\n`);
|
|
140
|
+
process.stderr.write(`taskId=${newTaskId}\n`);
|
|
141
|
+
exitCode = 1;
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await crewx.close();
|
|
145
|
+
}
|
|
146
|
+
if (exitCode !== 0)
|
|
147
|
+
process.exit(exitCode);
|
|
148
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -55,6 +55,7 @@ const agent_1 = require("./commands/agent");
|
|
|
55
55
|
const ps_1 = require("./commands/ps");
|
|
56
56
|
const kill_1 = require("./commands/kill");
|
|
57
57
|
const result_1 = require("./commands/result");
|
|
58
|
+
const restart_1 = require("./commands/restart");
|
|
58
59
|
const log_1 = require("./commands/log");
|
|
59
60
|
const doctor_1 = require("./commands/doctor");
|
|
60
61
|
const init_1 = require("./commands/init");
|
|
@@ -133,6 +134,10 @@ async function main() {
|
|
|
133
134
|
case 'result':
|
|
134
135
|
await (0, result_1.handleResult)(args.slice(1));
|
|
135
136
|
return;
|
|
137
|
+
// CLI Task Lifecycle 2단계: restart a failed task as a new task
|
|
138
|
+
case 'restart':
|
|
139
|
+
await (0, restart_1.handleRestart)(args.slice(1));
|
|
140
|
+
return;
|
|
136
141
|
// P1-1: log
|
|
137
142
|
case 'log':
|
|
138
143
|
await (0, log_1.handleLog)(args.slice(1));
|
|
@@ -269,6 +274,7 @@ Task Management:
|
|
|
269
274
|
kill <task-id> Kill a running task
|
|
270
275
|
kill --all Kill all running tasks
|
|
271
276
|
result [task-id] Get task result (or list recent tasks)
|
|
277
|
+
restart <task-id> Restart a failed task as a new task
|
|
272
278
|
|
|
273
279
|
Logs & Diagnostics:
|
|
274
280
|
log [ls|<task-id>] View task logs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-rc.1",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -24,17 +24,17 @@
|
|
|
24
24
|
"@crewx/adapter-slack": "0.1.4",
|
|
25
25
|
"better-sqlite3": "*",
|
|
26
26
|
"isomorphic-git": "1.37.1",
|
|
27
|
-
"@crewx/sdk": "0.
|
|
28
|
-
"@crewx/memory": "0.1.23",
|
|
27
|
+
"@crewx/sdk": "0.9.0-rc.1",
|
|
29
28
|
"@crewx/search": "0.1.10",
|
|
30
29
|
"@crewx/doc": "0.1.9",
|
|
31
30
|
"@crewx/wbs": "0.1.10",
|
|
32
|
-
"@crewx/
|
|
31
|
+
"@crewx/memory": "0.1.23",
|
|
33
32
|
"@crewx/workflow": "0.3.22",
|
|
33
|
+
"@crewx/cron": "0.1.10",
|
|
34
34
|
"@crewx/skill": "0.1.20",
|
|
35
|
-
"@crewx/chromex": "0.1.0",
|
|
36
35
|
"@crewx/wi": "0.1.10",
|
|
37
|
-
"@crewx/shared": "0.0.6"
|
|
36
|
+
"@crewx/shared": "0.0.6",
|
|
37
|
+
"@crewx/chromex": "0.1.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/better-sqlite3": "*",
|