@crewx/cli 0.9.0-rc.13 → 0.9.0-rc.131
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 +27 -6
- package/dist/builtin.d.ts +1 -1
- package/dist/builtin.js +7 -2
- package/dist/commands/agent.js +1 -107
- package/dist/commands/cal.d.ts +15 -0
- package/dist/commands/cal.js +44 -0
- package/dist/commands/db.d.ts +2 -0
- package/dist/commands/db.js +381 -1
- package/dist/commands/detached.d.ts +95 -0
- package/dist/commands/detached.js +620 -0
- package/dist/commands/doctor.d.ts +77 -0
- package/dist/commands/doctor.js +475 -22
- package/dist/commands/emit-trailer.d.ts +25 -0
- package/dist/commands/emit-trailer.js +33 -0
- package/dist/commands/execute.d.ts +8 -4
- package/dist/commands/execute.js +201 -49
- package/dist/commands/hook/command-marker.d.ts +2 -0
- package/dist/commands/hook/command-marker.js +5 -0
- package/dist/commands/hook/install.d.ts +0 -1
- package/dist/commands/hook/install.js +75 -61
- package/dist/commands/hook/status.js +3 -3
- package/dist/commands/hook/uninstall.js +2 -2
- package/dist/commands/init.d.ts +34 -0
- package/dist/commands/init.js +132 -59
- package/dist/commands/kill.d.ts +2 -8
- package/dist/commands/kill.js +6 -47
- package/dist/commands/log.js +4 -3
- package/dist/commands/parse-common-flags.d.ts +7 -1
- package/dist/commands/parse-common-flags.js +37 -4
- package/dist/commands/ps.d.ts +2 -2
- package/dist/commands/ps.js +25 -15
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.js +303 -0
- package/dist/commands/query.d.ts +7 -2
- package/dist/commands/query.js +196 -46
- package/dist/commands/registry.js +4 -2
- package/dist/commands/resolve-prompt.js +23 -1
- package/dist/commands/resolve-recipient.d.ts +14 -0
- package/dist/commands/resolve-recipient.js +47 -0
- package/dist/commands/result.d.ts +8 -3
- package/dist/commands/result.js +139 -7
- 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/stop.d.ts +8 -0
- package/dist/commands/stop.js +119 -0
- package/dist/commands/write-output.d.ts +3 -0
- package/dist/commands/write-output.js +24 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -1
- package/dist/logging.d.ts +1 -1
- package/dist/logging.js +3 -2
- package/dist/main.d.ts +3 -2
- package/dist/main.js +96 -24
- package/dist/utils/env-defaults.d.ts +2 -5
- package/dist/utils/env-defaults.js +10 -5
- package/dist/utils/inherited-trace.d.ts +24 -0
- package/dist/utils/inherited-trace.js +40 -0
- package/dist/utils/product-package-root.d.ts +6 -0
- package/dist/utils/product-package-root.js +39 -0
- package/dist/utils/sdk-compat.d.ts +24 -0
- package/dist/utils/sdk-compat.js +120 -0
- package/package.json +16 -12
package/dist/commands/init.js
CHANGED
|
@@ -44,6 +44,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
44
44
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
45
45
|
};
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.buildDefaultAgents = buildDefaultAgents;
|
|
48
|
+
exports.parseInitProvider = parseInitProvider;
|
|
49
|
+
exports.resolveInitProvider = resolveInitProvider;
|
|
47
50
|
exports.handleInit = handleInit;
|
|
48
51
|
const fs_1 = require("fs");
|
|
49
52
|
const path_1 = require("path");
|
|
@@ -52,6 +55,7 @@ const git = __importStar(require("isomorphic-git"));
|
|
|
52
55
|
const nodeFs = __importStar(require("fs"));
|
|
53
56
|
const os_1 = __importDefault(require("os"));
|
|
54
57
|
const repository_1 = require("@crewx/sdk/repository");
|
|
58
|
+
const sdk_1 = require("@crewx/sdk");
|
|
55
59
|
const install_1 = require("./hook/install");
|
|
56
60
|
const STATUSLINE_SCRIPT_NAME = 'claude-usage-statusline.js';
|
|
57
61
|
const STATUSLINE_SCRIPT_MARKER = 'CrewX claude-usage-statusline';
|
|
@@ -84,6 +88,11 @@ const CREWX_MARKER = '# CrewX runtime';
|
|
|
84
88
|
const CREWX_GITIGNORE = `# CrewX runtime
|
|
85
89
|
.crewx/
|
|
86
90
|
|
|
91
|
+
# Secrets (workspace .env — see docs/manual)
|
|
92
|
+
.env
|
|
93
|
+
.env.*
|
|
94
|
+
!.env.example
|
|
95
|
+
|
|
87
96
|
# Memory runtime state (regenerable from entries/)
|
|
88
97
|
memory/*/.dirty-summary
|
|
89
98
|
memory/*/graph.json
|
|
@@ -97,59 +106,66 @@ skills/*/.crewx/
|
|
|
97
106
|
|
|
98
107
|
# OS
|
|
99
108
|
.DS_Store`.trim();
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
provider: 'acp/claude',
|
|
124
|
-
working_directory: './',
|
|
125
|
-
description: 'Implements code changes and tests',
|
|
126
|
-
options: {
|
|
127
|
-
query: { effort: 'high' },
|
|
128
|
-
execute: { effort: 'high', mode: 'bypassPermissions' },
|
|
129
|
-
},
|
|
130
|
-
inline: {
|
|
131
|
-
model: 'claude-sonnet-4-6',
|
|
132
|
-
prompt: `Implement what the planner specifies. Prefer editing\nexisting files. Run tests before reporting done.`,
|
|
109
|
+
/** Build the three default agents using the selected CLI provider profile. */
|
|
110
|
+
function buildDefaultAgents(provider) {
|
|
111
|
+
const profile = (0, sdk_1.getDefaultAgentProfile)(provider);
|
|
112
|
+
if (!profile) {
|
|
113
|
+
throw new Error(`DEFAULT_AGENT_PROFILE_NOT_FOUND: ${provider}`);
|
|
114
|
+
}
|
|
115
|
+
return [
|
|
116
|
+
{
|
|
117
|
+
id: 'planner',
|
|
118
|
+
name: 'Planner',
|
|
119
|
+
role: 'Product/Architecture Planner',
|
|
120
|
+
team: 'core',
|
|
121
|
+
provider,
|
|
122
|
+
working_directory: './',
|
|
123
|
+
description: 'Owns requirements analysis, design, and work breakdown',
|
|
124
|
+
options: {
|
|
125
|
+
query: profile.planner.query,
|
|
126
|
+
execute: profile.planner.execute,
|
|
127
|
+
},
|
|
128
|
+
inline: {
|
|
129
|
+
model: profile.planner.model,
|
|
130
|
+
prompt: `You are a planner. Break down user goals into concrete,\ntestable steps. Challenge assumptions. Never write code directly.`,
|
|
131
|
+
},
|
|
133
132
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
{
|
|
134
|
+
id: 'developer',
|
|
135
|
+
name: 'Developer',
|
|
136
|
+
role: 'Implementation Engineer',
|
|
137
|
+
team: 'core',
|
|
138
|
+
provider,
|
|
139
|
+
working_directory: './',
|
|
140
|
+
description: 'Implements code changes and tests',
|
|
141
|
+
options: {
|
|
142
|
+
query: profile.worker.query,
|
|
143
|
+
execute: profile.worker.execute,
|
|
144
|
+
},
|
|
145
|
+
inline: {
|
|
146
|
+
model: profile.worker.model,
|
|
147
|
+
prompt: `Implement what the planner specifies. Prefer editing\nexisting files. Run tests before reporting done.`,
|
|
148
|
+
},
|
|
146
149
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
{
|
|
151
|
+
id: 'reviewer',
|
|
152
|
+
name: 'Reviewer',
|
|
153
|
+
role: 'Code Reviewer',
|
|
154
|
+
team: 'core',
|
|
155
|
+
provider,
|
|
156
|
+
working_directory: './',
|
|
157
|
+
description: 'Reviews code quality, security, and readability',
|
|
158
|
+
options: {
|
|
159
|
+
query: profile.worker.query,
|
|
160
|
+
execute: profile.worker.execute,
|
|
161
|
+
},
|
|
162
|
+
inline: {
|
|
163
|
+
model: profile.worker.model,
|
|
164
|
+
prompt: `Review diffs for correctness, security, readability.\nCite file:line. Be blunt, not polite.`,
|
|
165
|
+
},
|
|
150
166
|
},
|
|
151
|
-
|
|
152
|
-
|
|
167
|
+
];
|
|
168
|
+
}
|
|
153
169
|
const GOAL_TEMPLATE = `---
|
|
154
170
|
type: goal
|
|
155
171
|
description: CrewX Goal — OKR
|
|
@@ -370,10 +386,11 @@ function generateDefaultYaml(agents) {
|
|
|
370
386
|
description: "${a.description}"
|
|
371
387
|
options:
|
|
372
388
|
query:
|
|
373
|
-
|
|
389
|
+
mode: "${a.options.query.mode}"
|
|
390
|
+
effort: "${a.options.query.effort}"
|
|
374
391
|
execute:
|
|
375
|
-
|
|
376
|
-
|
|
392
|
+
mode: "${a.options.execute.mode}"
|
|
393
|
+
effort: "${a.options.execute.effort}"
|
|
377
394
|
inline:
|
|
378
395
|
model: "${a.inline.model}"
|
|
379
396
|
prompt: |
|
|
@@ -386,11 +403,51 @@ agents:
|
|
|
386
403
|
${agentBlocks}
|
|
387
404
|
|
|
388
405
|
# Usage examples:
|
|
389
|
-
# crewx
|
|
390
|
-
# crewx
|
|
406
|
+
# crewx q --to planner "analyze this codebase"
|
|
407
|
+
# crewx x --to developer "implement the feature described above"
|
|
391
408
|
# crewx agent ls
|
|
392
409
|
`;
|
|
393
410
|
}
|
|
411
|
+
function isInitProvider(value) {
|
|
412
|
+
return value === 'cli/claude' || value === 'cli/codex';
|
|
413
|
+
}
|
|
414
|
+
function invalidProviderError(value) {
|
|
415
|
+
if (value === undefined || value.length === 0) {
|
|
416
|
+
return new Error('Missing --provider value. Expected: cli/claude | cli/codex');
|
|
417
|
+
}
|
|
418
|
+
return new Error(`Invalid --provider value: "${value}". Expected: cli/claude | cli/codex`);
|
|
419
|
+
}
|
|
420
|
+
/** Parse the provider option accepted by `crewx init`. */
|
|
421
|
+
function parseInitProvider(args) {
|
|
422
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
423
|
+
const arg = args[index];
|
|
424
|
+
if (arg === '--provider') {
|
|
425
|
+
const value = args[index + 1];
|
|
426
|
+
if (value === undefined || value.startsWith('--'))
|
|
427
|
+
throw invalidProviderError(undefined);
|
|
428
|
+
if (!isInitProvider(value))
|
|
429
|
+
throw invalidProviderError(value);
|
|
430
|
+
return value;
|
|
431
|
+
}
|
|
432
|
+
if (arg?.startsWith('--provider=')) {
|
|
433
|
+
const value = arg.slice('--provider='.length);
|
|
434
|
+
if (!isInitProvider(value))
|
|
435
|
+
throw invalidProviderError(value);
|
|
436
|
+
return value;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return undefined;
|
|
440
|
+
}
|
|
441
|
+
/** Resolve an explicit provider or detect Claude, then Codex, using PATH only. */
|
|
442
|
+
function resolveInitProvider(provider, deps = {}) {
|
|
443
|
+
if (provider !== undefined)
|
|
444
|
+
return provider;
|
|
445
|
+
if ((0, sdk_1.isProviderAvailable)('cli/claude', deps))
|
|
446
|
+
return 'cli/claude';
|
|
447
|
+
if ((0, sdk_1.isProviderAvailable)('cli/codex', deps))
|
|
448
|
+
return 'cli/codex';
|
|
449
|
+
return 'cli/claude';
|
|
450
|
+
}
|
|
394
451
|
/**
|
|
395
452
|
* Programmatic init — creates crewx.yaml, support dirs, and optionally installs hooks.
|
|
396
453
|
* Throws on unrecoverable errors (PATH_NOT_FOUND, YAML_CREATE_FAILED).
|
|
@@ -399,7 +456,8 @@ ${agentBlocks}
|
|
|
399
456
|
* server paths both produce a row in ~/.crewx/crewx.db.
|
|
400
457
|
*/
|
|
401
458
|
async function handleInit(opts) {
|
|
402
|
-
const { path: target, skipHook = false, force = false } = opts;
|
|
459
|
+
const { path: target, skipHook = false, force = false, provider: requestedProvider } = opts;
|
|
460
|
+
const provider = resolveInitProvider(requestedProvider);
|
|
403
461
|
const errors = [];
|
|
404
462
|
let yamlCreated = false;
|
|
405
463
|
let hookInstalled = false;
|
|
@@ -417,7 +475,7 @@ async function handleInit(opts) {
|
|
|
417
475
|
}
|
|
418
476
|
if (!skippedReason) {
|
|
419
477
|
try {
|
|
420
|
-
const content = generateDefaultYaml(
|
|
478
|
+
const content = generateDefaultYaml(buildDefaultAgents(provider));
|
|
421
479
|
(0, fs_1.writeFileSync)(yamlPath, content, 'utf-8');
|
|
422
480
|
yamlCreated = true;
|
|
423
481
|
}
|
|
@@ -435,7 +493,7 @@ async function handleInit(opts) {
|
|
|
435
493
|
}
|
|
436
494
|
}
|
|
437
495
|
// 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']) {
|
|
496
|
+
for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi', 'workflows']) {
|
|
439
497
|
try {
|
|
440
498
|
(0, fs_1.mkdirSync)((0, path_1.join)(target, dir), { recursive: true });
|
|
441
499
|
}
|
|
@@ -456,6 +514,21 @@ async function handleInit(opts) {
|
|
|
456
514
|
console.log(`✅ ${t.dir}/ ${action} (${t.file})`);
|
|
457
515
|
}
|
|
458
516
|
}
|
|
517
|
+
try {
|
|
518
|
+
const workflowTemplatesDir = (0, sdk_1.resolveWorkflowTemplatesPath)();
|
|
519
|
+
for (const filename of [sdk_1.WI_DEFAULT_FLOW_FILENAME, sdk_1.WI_PLAN_FLOW_FILENAME]) {
|
|
520
|
+
const sourcePath = (0, path_1.join)(workflowTemplatesDir, filename);
|
|
521
|
+
const targetPath = (0, path_1.join)(target, 'workflows', filename);
|
|
522
|
+
if (force || !(0, fs_1.existsSync)(targetPath)) {
|
|
523
|
+
const action = (0, fs_1.existsSync)(targetPath) ? 'updated' : 'created';
|
|
524
|
+
(0, fs_1.copyFileSync)(sourcePath, targetPath);
|
|
525
|
+
console.log(`✅ workflows/ ${action} (${filename})`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch (e) {
|
|
530
|
+
errors.push(`WORKFLOW_TEMPLATE_FAILED:${e.message}`);
|
|
531
|
+
}
|
|
459
532
|
// Always register workspace in ~/.crewx/crewx.db (best-effort, idempotent)
|
|
460
533
|
let workspaceId;
|
|
461
534
|
let slug;
|
|
@@ -487,7 +560,7 @@ async function handleInit(opts) {
|
|
|
487
560
|
await initGitRepo(target, errors);
|
|
488
561
|
// Idempotent statusLine merge into ~/.claude/settings.json
|
|
489
562
|
const statusLineResult = ensureClaudeStatusLine();
|
|
490
|
-
return { yamlCreated, hookInstalled, errors, skippedReason, workspaceId, slug, ...statusLineResult };
|
|
563
|
+
return { yamlCreated, hookInstalled, errors, provider, skippedReason, workspaceId, slug, ...statusLineResult };
|
|
491
564
|
}
|
|
492
565
|
function ensureClaudeStatusLine() {
|
|
493
566
|
const home = os_1.default.homedir();
|
package/dist/commands/kill.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
* Kills a running task by ID or kills all running tasks.
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* crewx kill <task-id> Kill a specific running task
|
|
7
|
-
* crewx kill --all Kill all running tasks
|
|
8
|
-
*/
|
|
1
|
+
/** Compatibility entry point for `crewx kill`; the implementation lives in stop.ts. */
|
|
2
|
+
export { handleStop } from './stop';
|
|
9
3
|
export declare function handleKill(args: string[]): Promise<void>;
|
package/dist/commands/kill.js
CHANGED
|
@@ -1,52 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* crewx kill handler.
|
|
4
|
-
* Kills a running task by ID or kills all running tasks.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* crewx kill <task-id> Kill a specific running task
|
|
8
|
-
* crewx kill --all Kill all running tasks
|
|
9
|
-
*/
|
|
10
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleStop = void 0;
|
|
11
4
|
exports.handleKill = handleKill;
|
|
12
|
-
|
|
5
|
+
/** Compatibility entry point for `crewx kill`; the implementation lives in stop.ts. */
|
|
6
|
+
var stop_1 = require("./stop");
|
|
7
|
+
Object.defineProperty(exports, "handleStop", { enumerable: true, get: function () { return stop_1.handleStop; } });
|
|
8
|
+
const stop_2 = require("./stop");
|
|
13
9
|
async function handleKill(args) {
|
|
14
|
-
|
|
15
|
-
const taskId = args.find(a => !a.startsWith('--'));
|
|
16
|
-
if (!taskId && !killAll) {
|
|
17
|
-
console.error('Error: Please provide a task ID or use --all to kill all running tasks.');
|
|
18
|
-
console.error('');
|
|
19
|
-
console.error('Usage:');
|
|
20
|
-
console.error(' crewx kill <task-id> Kill a running task by ID');
|
|
21
|
-
console.error(' crewx kill --all Kill all running tasks');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const repo = new repository_1.TaskRepository();
|
|
26
|
-
if (killAll) {
|
|
27
|
-
const running = repo.getRunningTasks();
|
|
28
|
-
if (running.length === 0) {
|
|
29
|
-
console.log('No running tasks found.');
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
console.log(`Found ${running.length} running task(s). Killing...`);
|
|
33
|
-
for (const task of running) {
|
|
34
|
-
const r = repo.killTask(task.id);
|
|
35
|
-
if (r.killed) {
|
|
36
|
-
console.log(`Killed task ${task.id}${r.pid ? ` (PID: ${r.pid})` : ''}`);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
console.log(`Task ${task.id} could not be killed (may have already finished)`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const r = repo.killTask(taskId);
|
|
45
|
-
if (r.killed) {
|
|
46
|
-
console.log(`Killed task ${taskId}${r.pid ? ` (PID: ${r.pid})` : ''}`);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
console.error(`Error: Task not found or not running: ${taskId}`);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
10
|
+
return (0, stop_2.handleStop)(args, 'kill');
|
|
52
11
|
}
|
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: --to, --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
|
|
@@ -12,8 +12,12 @@
|
|
|
12
12
|
export interface CommonFlags {
|
|
13
13
|
/** Thread name for conversation continuity. */
|
|
14
14
|
thread?: string;
|
|
15
|
+
/** Explicit agent recipient. */
|
|
16
|
+
to?: string;
|
|
15
17
|
/** Provider override (e.g., cli/claude). */
|
|
16
18
|
provider?: string;
|
|
19
|
+
/** Model override (e.g., claude-sonnet-5). */
|
|
20
|
+
model?: string;
|
|
17
21
|
/** Raw metadata JSON string. */
|
|
18
22
|
metadata?: string;
|
|
19
23
|
/** Enable verbose/debug output mode. */
|
|
@@ -28,6 +32,8 @@ export interface CommonFlags {
|
|
|
28
32
|
promptFile?: string;
|
|
29
33
|
/** Whether overdrive (boost) is active for this request. */
|
|
30
34
|
overdrive: boolean;
|
|
35
|
+
/** Output file path for saving result (--out/-o). */
|
|
36
|
+
out?: string;
|
|
31
37
|
/** Template variables from --var key=value flags. */
|
|
32
38
|
vars: Record<string, string>;
|
|
33
39
|
/** 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: --to, --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
|
|
@@ -61,25 +61,30 @@ exports.UnknownOptionError = UnknownOptionError;
|
|
|
61
61
|
* The `--` sentinel itself is NOT included in `rest`.
|
|
62
62
|
*/
|
|
63
63
|
function parseCommonFlags(args) {
|
|
64
|
+
const { value: to, consumed: toConsumed } = parseToFlag(args);
|
|
64
65
|
const thread = parseFlag(args, '--thread');
|
|
65
66
|
const provider = parseFlag(args, '--provider');
|
|
67
|
+
const model = parseFlag(args, '--model');
|
|
66
68
|
const metadata = parseFlag(args, '--metadata');
|
|
67
69
|
const config = parseFlag(args, '--config', '-c');
|
|
68
70
|
const outputFormat = parseFlag(args, '--output-format');
|
|
69
71
|
const effort = parseFlag(args, '--effort');
|
|
70
72
|
const promptFile = parseFlag(args, '--prompt-file', '-f');
|
|
73
|
+
const out = parseFlag(args, '--out', '-o');
|
|
71
74
|
const verbose = hasFlag(args, '--verbose');
|
|
72
75
|
const overdrive = hasFlag(args, '--overdrive');
|
|
73
76
|
// Collect consumed positions for known flags
|
|
74
|
-
const consumed = new Set();
|
|
77
|
+
const consumed = new Set(toConsumed);
|
|
75
78
|
const flagPairs = [
|
|
76
79
|
{ names: ['--thread'] },
|
|
77
80
|
{ names: ['--provider'] },
|
|
81
|
+
{ names: ['--model'] },
|
|
78
82
|
{ names: ['--metadata'] },
|
|
79
83
|
{ names: ['--config', '-c'] },
|
|
80
84
|
{ names: ['--output-format'] },
|
|
81
85
|
{ names: ['--effort'] },
|
|
82
86
|
{ names: ['--prompt-file', '-f'] },
|
|
87
|
+
{ names: ['--out', '-o'] },
|
|
83
88
|
];
|
|
84
89
|
// Parse --var key=value flags (multiple allowed; last value wins on duplicate keys)
|
|
85
90
|
const vars = {};
|
|
@@ -145,7 +150,7 @@ function parseCommonFlags(args) {
|
|
|
145
150
|
if (!escapeMode && token.startsWith('--')) {
|
|
146
151
|
throw new UnknownOptionError(`Unknown option: ${token}. Use "--" to pass literal flag-like tokens as message.\n` +
|
|
147
152
|
` Did you mean: crewx serve ${token}\n` +
|
|
148
|
-
` or: crewx q -- ${token} <message
|
|
153
|
+
` or: crewx q --to <agent> -- ${token} <message>`);
|
|
149
154
|
}
|
|
150
155
|
// Reject short -x flags that are not numeric (e.g. -f was consumed above)
|
|
151
156
|
if (!escapeMode && token.startsWith('-') && token.length > 1 && !/^-?\d/.test(token)) {
|
|
@@ -153,7 +158,35 @@ function parseCommonFlags(args) {
|
|
|
153
158
|
}
|
|
154
159
|
rest.push(token);
|
|
155
160
|
}
|
|
156
|
-
return { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, rest };
|
|
161
|
+
return { to, thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest };
|
|
162
|
+
}
|
|
163
|
+
/** Parse the explicit recipient flag without treating tokens after `--` as flags. */
|
|
164
|
+
function parseToFlag(args) {
|
|
165
|
+
let value;
|
|
166
|
+
const consumed = [];
|
|
167
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
168
|
+
const arg = args[index];
|
|
169
|
+
if (arg === '--')
|
|
170
|
+
break;
|
|
171
|
+
if (arg.startsWith('--to=')) {
|
|
172
|
+
const candidate = arg.slice('--to='.length);
|
|
173
|
+
if (!candidate.trim())
|
|
174
|
+
throw new UnknownOptionError('--to requires an agent id');
|
|
175
|
+
value = candidate;
|
|
176
|
+
consumed.push(index);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (arg !== '--to')
|
|
180
|
+
continue;
|
|
181
|
+
const candidate = args[index + 1];
|
|
182
|
+
if (candidate === undefined || candidate === '--' || candidate.startsWith('--') || !candidate.trim()) {
|
|
183
|
+
throw new UnknownOptionError('--to requires an agent id');
|
|
184
|
+
}
|
|
185
|
+
value = candidate;
|
|
186
|
+
consumed.push(index, index + 1);
|
|
187
|
+
index += 1;
|
|
188
|
+
}
|
|
189
|
+
return { value, consumed };
|
|
157
190
|
}
|
|
158
191
|
/**
|
|
159
192
|
* Parse metadata JSON string from --metadata flag.
|
package/dist/commands/ps.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* crewx ps handler.
|
|
3
|
-
* Lists
|
|
3
|
+
* Lists active tasks (pending or running) in table format.
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* crewx ps List all running tasks
|
|
6
|
+
* crewx ps List all pending and running tasks
|
|
7
7
|
* crewx ps --json Output as JSON array
|
|
8
8
|
*/
|
|
9
9
|
export declare function handlePs(args: string[]): Promise<void>;
|
package/dist/commands/ps.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* crewx ps handler.
|
|
4
|
-
* Lists
|
|
4
|
+
* Lists active tasks (pending or running) in table format.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* crewx ps List all running tasks
|
|
7
|
+
* crewx ps List all pending and running tasks
|
|
8
8
|
* crewx ps --json Output as JSON array
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.handlePs = handlePs;
|
|
12
12
|
const repository_1 = require("@crewx/sdk/repository");
|
|
13
|
+
const cal_1 = require("./cal");
|
|
13
14
|
function formatElapsed(ms) {
|
|
14
15
|
const s = Math.floor(ms / 1000);
|
|
15
16
|
if (s < 60)
|
|
@@ -34,9 +35,9 @@ function isAgyCommand(codingAgentCommand) {
|
|
|
34
35
|
const base = firstToken.split('/').pop() ?? firstToken;
|
|
35
36
|
return base.startsWith('agy');
|
|
36
37
|
}
|
|
37
|
-
function getLastActive(task) {
|
|
38
|
+
function getLastActive(task, taskRepo) {
|
|
38
39
|
try {
|
|
39
|
-
const entries =
|
|
40
|
+
const entries = taskRepo.readLogsTail(task.id, 1)?.entries ?? [];
|
|
40
41
|
if (Array.isArray(entries) && entries.length > 0) {
|
|
41
42
|
const lastEntry = entries[entries.length - 1];
|
|
42
43
|
const ts = lastEntry?.timestamp;
|
|
@@ -59,12 +60,13 @@ function getLastActive(task) {
|
|
|
59
60
|
}
|
|
60
61
|
return { display: '—', isoTimestamp: null, logCapable: true };
|
|
61
62
|
}
|
|
62
|
-
function taskToRow(task) {
|
|
63
|
+
function taskToRow(task, taskRepo) {
|
|
63
64
|
const elapsed = formatElapsed(Date.now() - new Date(task.started_at).getTime());
|
|
64
|
-
const lastActive = getLastActive(task);
|
|
65
|
+
const lastActive = getLastActive(task, taskRepo);
|
|
65
66
|
return [
|
|
66
67
|
task.id,
|
|
67
68
|
task.agent_id ?? '—',
|
|
69
|
+
task.status,
|
|
68
70
|
task.pid !== null && task.pid !== undefined ? String(task.pid) : '—',
|
|
69
71
|
elapsed,
|
|
70
72
|
task.mode ?? '—',
|
|
@@ -83,14 +85,14 @@ function renderTable(headers, rows) {
|
|
|
83
85
|
}
|
|
84
86
|
async function handlePs(args) {
|
|
85
87
|
const repo = new repository_1.TaskRepository();
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
88
|
-
console.
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const reaped = repo.reapOrphanedTasks();
|
|
89
|
+
if (reaped > 0)
|
|
90
|
+
console.error(`Reaped ${reaped} orphaned task(s)`);
|
|
91
|
+
repo.reapRunningWorkflowTasks();
|
|
92
|
+
const tasks = repo.getActiveTasks();
|
|
91
93
|
if (args.includes('--json')) {
|
|
92
94
|
const withLastActive = tasks.map((task) => {
|
|
93
|
-
const lastActive = getLastActive(task);
|
|
95
|
+
const lastActive = getLastActive(task, repo);
|
|
94
96
|
return {
|
|
95
97
|
...task,
|
|
96
98
|
last_active_at: lastActive.isoTimestamp,
|
|
@@ -100,8 +102,16 @@ async function handlePs(args) {
|
|
|
100
102
|
console.log(JSON.stringify(withLastActive, null, 2));
|
|
101
103
|
return;
|
|
102
104
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
if (tasks.length === 0) {
|
|
106
|
+
console.log('No active tasks.');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const headers = ['TASK ID', 'AGENT', 'STATUS', 'PID', 'ELAPSED', 'MODE', 'LAST ACTIVE'];
|
|
110
|
+
const rows = tasks.map((task) => taskToRow(task, repo));
|
|
105
111
|
renderTable(headers, rows);
|
|
106
|
-
console.log(`\n ${tasks.length}
|
|
112
|
+
console.log(`\n ${tasks.length} active task(s)`);
|
|
113
|
+
(0, cal_1.writeCalFooter)({
|
|
114
|
+
commandId: 'crewx.ps',
|
|
115
|
+
params: { taskId: tasks[0].id },
|
|
116
|
+
});
|
|
107
117
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handlePublish(args: string[]): Promise<void>;
|