@crewx/cli 0.9.0-rc.109 → 0.9.0-rc.110
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/detached.d.ts +9 -1
- package/dist/commands/detached.js +28 -1
- package/dist/commands/execute.js +71 -48
- package/dist/commands/query.js +71 -48
- package/package.json +14 -14
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* trace context and are never repurposed as the runner assignment.
|
|
7
7
|
*/
|
|
8
8
|
import { TaskRepository } from '@crewx/sdk/repository';
|
|
9
|
-
import type { TaskActor } from '@crewx/sdk';
|
|
9
|
+
import type { DurableTaskAdmission, TaskActor } from '@crewx/sdk';
|
|
10
10
|
export type ReceiptActorKind = 'human' | 'agent' | 'system' | 'unknown';
|
|
11
11
|
export interface ReceiptActor {
|
|
12
12
|
kind: ReceiptActorKind;
|
|
@@ -20,6 +20,14 @@ export declare function resolveCliTaskActor(metadata: Record<string, unknown>, a
|
|
|
20
20
|
* cron runners cannot diverge after root context is stripped.
|
|
21
21
|
*/
|
|
22
22
|
export declare function resolveReceiptActor(metadata: Record<string, unknown>, agentId?: string | undefined): ReceiptActor;
|
|
23
|
+
/**
|
|
24
|
+
* Report a blocked direct admission (WI-CTO-20260919-004 R2 finding #1) to
|
|
25
|
+
* the operator. Never called for an adopted (already pending) receipt — see
|
|
26
|
+
* admitDurableTask()'s own doc comment.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reportAdmissionBlocked(admission: Extract<DurableTaskAdmission, {
|
|
29
|
+
ok: false;
|
|
30
|
+
}>): void;
|
|
23
31
|
/**
|
|
24
32
|
* Remove receipt-selection flags, respecting the `--` literal-args sentinel.
|
|
25
33
|
*/
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.resolveCliTaskActor = resolveCliTaskActor;
|
|
11
11
|
exports.resolveReceiptActor = resolveReceiptActor;
|
|
12
|
+
exports.reportAdmissionBlocked = reportAdmissionBlocked;
|
|
12
13
|
exports.extractReceiptFlags = extractReceiptFlags;
|
|
13
14
|
exports.resolveReceiptMode = resolveReceiptMode;
|
|
14
15
|
exports.adoptAssignedTask = adoptAssignedTask;
|
|
@@ -50,6 +51,14 @@ function resolveReceiptActor(metadata, agentId = process.env['CREWX_AGENT_ID'])
|
|
|
50
51
|
const actor = resolveCliTaskActor(metadata, agentId);
|
|
51
52
|
return { kind: actor.actorKind, id: actor.actorId };
|
|
52
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Report a blocked direct admission (WI-CTO-20260919-004 R2 finding #1) to
|
|
56
|
+
* the operator. Never called for an adopted (already pending) receipt — see
|
|
57
|
+
* admitDurableTask()'s own doc comment.
|
|
58
|
+
*/
|
|
59
|
+
function reportAdmissionBlocked(admission) {
|
|
60
|
+
process.stderr.write(`${admission.message}\n`);
|
|
61
|
+
}
|
|
53
62
|
const DETACHED_RUNNER_POLL_INTERVAL_MS = 200;
|
|
54
63
|
const DETACHED_RUNNER_ADOPTION_TIMEOUT_MS = 30_000;
|
|
55
64
|
const DETACHED_VALUE_FLAGS = [
|
|
@@ -421,7 +430,18 @@ async function runDetached(command, filteredArgs, reason) {
|
|
|
421
430
|
process.exit(2);
|
|
422
431
|
return;
|
|
423
432
|
}
|
|
424
|
-
|
|
433
|
+
// This process is a separate OS process from the embedded server and
|
|
434
|
+
// would otherwise never see a desktop update's admission gate at all
|
|
435
|
+
// (WI-CTO-20260919-004 R2 finding #1) — reserve-then-check before the
|
|
436
|
+
// pending receipt is written below, not after; see admitDurableTask()'s
|
|
437
|
+
// own doc comment for why that ordering closes the TOCTOU.
|
|
438
|
+
const admission = (0, sdk_1.admitDurableTask)(`direct-cli:${command}`);
|
|
439
|
+
if (!admission.ok) {
|
|
440
|
+
reportAdmissionBlocked(admission);
|
|
441
|
+
process.exit(1);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const taskId = admission.taskId;
|
|
425
445
|
const startedAt = new Date().toISOString();
|
|
426
446
|
const workspacePath = process.cwd();
|
|
427
447
|
const hasWorkspaceConfig = (0, fs_1.existsSync)((0, path_1.join)(workspacePath, 'crewx.yaml'))
|
|
@@ -455,10 +475,17 @@ async function runDetached(command, filteredArgs, reason) {
|
|
|
455
475
|
});
|
|
456
476
|
}
|
|
457
477
|
catch (error) {
|
|
478
|
+
// The receipt's own pending row failed to persist — nothing durable was
|
|
479
|
+
// admitted, so the reservation's job is done regardless.
|
|
480
|
+
admission.release();
|
|
458
481
|
process.stderr.write(`Failed to create detached task receipt: ${errorMessage(error)}\n`);
|
|
459
482
|
process.exit(1);
|
|
460
483
|
return;
|
|
461
484
|
}
|
|
485
|
+
// The pending row above is now the durable, DB-visible signal of this
|
|
486
|
+
// work's admission — the reservation only ever existed to bridge the gap
|
|
487
|
+
// before it landed.
|
|
488
|
+
admission.release();
|
|
462
489
|
const runnerArgs = buildDetachedRunnerArgs(filteredArgs, agentRef, finalMessage);
|
|
463
490
|
const commandForRunner = runnerCommand(command);
|
|
464
491
|
const logDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx', 'logs');
|
package/dist/commands/execute.js
CHANGED
|
@@ -178,63 +178,86 @@ async function handleExecute(args, command = 'execute', emitState = (0, emit_tra
|
|
|
178
178
|
taskActor = (0, detached_1.readAssignedTaskActor)(taskRepo, adoption.taskId);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
+
// A synchronous `crewx x` runs in this same process, but this process is
|
|
182
|
+
// still separate from the embedded server and never sees its in-memory
|
|
183
|
+
// UpdateGateService (WI-CTO-20260919-004 R2 finding #1) — only the durable
|
|
184
|
+
// marker it writes. Reserve-then-check before calling into the SDK below,
|
|
185
|
+
// not after; see admitDurableTask()'s own doc comment. Never checked for
|
|
186
|
+
// an adopted receipt (selfTaskId set): that work was already admitted by
|
|
187
|
+
// whichever process first created its pending DB row.
|
|
188
|
+
let admission;
|
|
189
|
+
if (selfTaskId === undefined) {
|
|
190
|
+
admission = (0, sdk_1.admitDurableTask)(`direct-cli:${command}`);
|
|
191
|
+
if (!admission.ok) {
|
|
192
|
+
(0, detached_1.reportAdmissionBlocked)(admission);
|
|
193
|
+
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
194
|
+
process.exit(1);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
181
198
|
let exitCode = 0;
|
|
182
199
|
let result;
|
|
183
200
|
try {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
try {
|
|
202
|
+
result = await crewx.execute(agentRef, finalMessage, {
|
|
203
|
+
provider,
|
|
204
|
+
model,
|
|
205
|
+
effort: effort || undefined,
|
|
206
|
+
overdrive: overdrive || undefined,
|
|
207
|
+
threadId: thread,
|
|
208
|
+
taskId: selfTaskId,
|
|
209
|
+
actor: assignedTaskId === undefined ? actor : taskActor,
|
|
210
|
+
metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
|
|
211
|
+
vars: Object.keys(vars).length > 0 ? vars : undefined,
|
|
212
|
+
trace: inheritedTrace,
|
|
213
|
+
});
|
|
214
|
+
if (!result.ok) {
|
|
215
|
+
const errMsg = result.error?.message ?? 'Execute failed';
|
|
216
|
+
console.error(errMsg);
|
|
217
|
+
(0, write_output_1.appendError)(out, errMsg);
|
|
218
|
+
exitCode = 1;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
if (verbose) {
|
|
222
|
+
process.stderr.write(`\n📊 Results from ${agentRef}:\n`);
|
|
223
|
+
process.stderr.write('═'.repeat(60) + '\n');
|
|
224
|
+
process.stderr.write('🟢 Status: Success\n');
|
|
225
|
+
process.stderr.write(`🤖 Provider: ${result.meta.provider}\n`);
|
|
226
|
+
process.stderr.write(`⏱️ Duration: ${result.meta.durationMs}ms\n`);
|
|
227
|
+
process.stderr.write('\n📄 Response:\n');
|
|
228
|
+
process.stderr.write('─'.repeat(40) + '\n');
|
|
229
|
+
}
|
|
230
|
+
(0, write_output_1.writeResult)(out, result.data);
|
|
231
|
+
if (verbose)
|
|
232
|
+
process.stderr.write('\n✅ Execute completed successfully\n');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
237
|
+
console.error(`Error: ${errMsg}`);
|
|
238
|
+
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
200
239
|
exitCode = 1;
|
|
201
240
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
241
|
+
finally {
|
|
242
|
+
try {
|
|
243
|
+
await crewx.close();
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
(0, emit_trailer_1.emitDelegationResult)({
|
|
247
|
+
command,
|
|
248
|
+
trace: inheritedTrace,
|
|
249
|
+
taskId: result?.meta.taskId,
|
|
250
|
+
agentId: result?.meta.agentId,
|
|
251
|
+
isError: true,
|
|
252
|
+
state: emitState,
|
|
253
|
+
});
|
|
254
|
+
throw err;
|
|
211
255
|
}
|
|
212
|
-
(0, write_output_1.writeResult)(out, result.data);
|
|
213
|
-
if (verbose)
|
|
214
|
-
process.stderr.write('\n✅ Execute completed successfully\n');
|
|
215
256
|
}
|
|
216
257
|
}
|
|
217
|
-
catch (err) {
|
|
218
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
219
|
-
console.error(`Error: ${errMsg}`);
|
|
220
|
-
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
221
|
-
exitCode = 1;
|
|
222
|
-
}
|
|
223
258
|
finally {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
(0, emit_trailer_1.emitDelegationResult)({
|
|
229
|
-
command,
|
|
230
|
-
trace: inheritedTrace,
|
|
231
|
-
taskId: result?.meta.taskId,
|
|
232
|
-
agentId: result?.meta.agentId,
|
|
233
|
-
isError: true,
|
|
234
|
-
state: emitState,
|
|
235
|
-
});
|
|
236
|
-
throw err;
|
|
237
|
-
}
|
|
259
|
+
if (admission?.ok)
|
|
260
|
+
admission.release();
|
|
238
261
|
}
|
|
239
262
|
(0, emit_trailer_1.emitDelegationResult)({
|
|
240
263
|
command,
|
package/dist/commands/query.js
CHANGED
|
@@ -175,64 +175,87 @@ async function handleQuery(args, command = 'query', emitState = (0, emit_trailer
|
|
|
175
175
|
taskActor = (0, detached_1.readAssignedTaskActor)(taskRepo, adoption.taskId);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
+
// A synchronous `crewx q` runs in this same process, but this process is
|
|
179
|
+
// still separate from the embedded server and never sees its in-memory
|
|
180
|
+
// UpdateGateService (WI-CTO-20260919-004 R2 finding #1) — only the durable
|
|
181
|
+
// marker it writes. Reserve-then-check before calling into the SDK below,
|
|
182
|
+
// not after; see admitDurableTask()'s own doc comment. Never checked for
|
|
183
|
+
// an adopted receipt (selfTaskId set): that work was already admitted by
|
|
184
|
+
// whichever process first created its pending DB row.
|
|
185
|
+
let admission;
|
|
186
|
+
if (selfTaskId === undefined) {
|
|
187
|
+
admission = (0, sdk_1.admitDurableTask)(`direct-cli:${command}`);
|
|
188
|
+
if (!admission.ok) {
|
|
189
|
+
(0, detached_1.reportAdmissionBlocked)(admission);
|
|
190
|
+
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
191
|
+
process.exit(1);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
178
195
|
let exitCode = 0;
|
|
179
196
|
let result;
|
|
180
197
|
try {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
try {
|
|
199
|
+
result = await crewx.query(agentRef, finalMessage, {
|
|
200
|
+
provider,
|
|
201
|
+
model,
|
|
202
|
+
effort: effort || undefined,
|
|
203
|
+
overdrive: overdrive || undefined,
|
|
204
|
+
threadId: thread,
|
|
205
|
+
taskId: selfTaskId,
|
|
206
|
+
actor: assignedTaskId === undefined ? actor : taskActor,
|
|
207
|
+
metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
|
|
208
|
+
vars: Object.keys(vars).length > 0 ? vars : undefined,
|
|
209
|
+
trace: inheritedTrace,
|
|
210
|
+
});
|
|
211
|
+
if (!result.ok) {
|
|
212
|
+
const errMsg = result.error?.message ?? 'Query failed';
|
|
213
|
+
console.error(errMsg);
|
|
214
|
+
(0, write_output_1.appendError)(out, errMsg);
|
|
215
|
+
exitCode = 1;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
if (verbose) {
|
|
219
|
+
process.stderr.write(`\n📊 Results from ${agentRef}:\n`);
|
|
220
|
+
process.stderr.write('═'.repeat(60) + '\n');
|
|
221
|
+
process.stderr.write('🟢 Status: Success\n');
|
|
222
|
+
process.stderr.write(`🤖 Provider: ${result.meta.provider}\n`);
|
|
223
|
+
process.stderr.write(`⏱️ Duration: ${result.meta.durationMs}ms\n`);
|
|
224
|
+
process.stderr.write('\n📄 Response:\n');
|
|
225
|
+
process.stderr.write('─'.repeat(40) + '\n');
|
|
226
|
+
}
|
|
227
|
+
(0, write_output_1.writeResult)(out, result.data);
|
|
228
|
+
if (verbose) {
|
|
229
|
+
process.stderr.write('\n✅ Query completed successfully\n');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
235
|
+
console.error(`Error: ${errMsg}`);
|
|
236
|
+
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
197
237
|
exitCode = 1;
|
|
198
238
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
process.stderr.write('═'.repeat(60) + '\n');
|
|
203
|
-
process.stderr.write('🟢 Status: Success\n');
|
|
204
|
-
process.stderr.write(`🤖 Provider: ${result.meta.provider}\n`);
|
|
205
|
-
process.stderr.write(`⏱️ Duration: ${result.meta.durationMs}ms\n`);
|
|
206
|
-
process.stderr.write('\n📄 Response:\n');
|
|
207
|
-
process.stderr.write('─'.repeat(40) + '\n');
|
|
239
|
+
finally {
|
|
240
|
+
try {
|
|
241
|
+
await crewx.close();
|
|
208
242
|
}
|
|
209
|
-
(
|
|
210
|
-
|
|
211
|
-
|
|
243
|
+
catch (err) {
|
|
244
|
+
(0, emit_trailer_1.emitDelegationResult)({
|
|
245
|
+
command,
|
|
246
|
+
trace: inheritedTrace,
|
|
247
|
+
taskId: result?.meta.taskId,
|
|
248
|
+
agentId: result?.meta.agentId,
|
|
249
|
+
isError: true,
|
|
250
|
+
state: emitState,
|
|
251
|
+
});
|
|
252
|
+
throw err;
|
|
212
253
|
}
|
|
213
254
|
}
|
|
214
255
|
}
|
|
215
|
-
catch (err) {
|
|
216
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
217
|
-
console.error(`Error: ${errMsg}`);
|
|
218
|
-
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
219
|
-
exitCode = 1;
|
|
220
|
-
}
|
|
221
256
|
finally {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
catch (err) {
|
|
226
|
-
(0, emit_trailer_1.emitDelegationResult)({
|
|
227
|
-
command,
|
|
228
|
-
trace: inheritedTrace,
|
|
229
|
-
taskId: result?.meta.taskId,
|
|
230
|
-
agentId: result?.meta.agentId,
|
|
231
|
-
isError: true,
|
|
232
|
-
state: emitState,
|
|
233
|
-
});
|
|
234
|
-
throw err;
|
|
235
|
-
}
|
|
257
|
+
if (admission?.ok)
|
|
258
|
+
admission.release();
|
|
236
259
|
}
|
|
237
260
|
(0, emit_trailer_1.emitDelegationResult)({
|
|
238
261
|
command,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/cli",
|
|
3
|
-
"version": "0.9.0-rc.
|
|
3
|
+
"version": "0.9.0-rc.110",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
"better-sqlite3": "*",
|
|
26
26
|
"dotenv": "17.2.3",
|
|
27
27
|
"isomorphic-git": "1.37.1",
|
|
28
|
-
"@crewx/sdk": "0.9.0-rc.
|
|
29
|
-
"@crewx/knowledge-core": "0.1.17-rc.
|
|
30
|
-
"@crewx/
|
|
31
|
-
"@crewx/doc": "0.1.9-rc.
|
|
32
|
-
"@crewx/
|
|
33
|
-
"@crewx/wbs": "0.1.10-rc.
|
|
34
|
-
"@crewx/cron": "0.1.10-rc.
|
|
35
|
-
"@crewx/
|
|
36
|
-
"@crewx/
|
|
37
|
-
"@crewx/
|
|
38
|
-
"@crewx/
|
|
39
|
-
"@crewx/
|
|
40
|
-
"@crewx/
|
|
28
|
+
"@crewx/sdk": "0.9.0-rc.110",
|
|
29
|
+
"@crewx/knowledge-core": "0.1.17-rc.120",
|
|
30
|
+
"@crewx/memory": "0.1.23-rc.127",
|
|
31
|
+
"@crewx/doc": "0.1.9-rc.103",
|
|
32
|
+
"@crewx/search": "0.1.10-rc.106",
|
|
33
|
+
"@crewx/wbs": "0.1.10-rc.136",
|
|
34
|
+
"@crewx/cron": "0.1.10-rc.145",
|
|
35
|
+
"@crewx/skill": "0.1.20-rc.4",
|
|
36
|
+
"@crewx/workflow": "0.3.22-rc.156",
|
|
37
|
+
"@crewx/chromex": "0.1.0-rc.143",
|
|
38
|
+
"@crewx/notify": "0.1.0-rc.81",
|
|
39
|
+
"@crewx/wi": "0.1.10-rc.130",
|
|
40
|
+
"@crewx/shared": "0.0.6-rc.25"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/better-sqlite3": "*",
|