@crewx/cli 0.9.0-rc.128 → 0.9.0-rc.129
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/builtin.d.ts +1 -1
- package/dist/builtin.js +5 -2
- package/dist/commands/detached.d.ts +7 -1
- package/dist/commands/detached.js +33 -5
- package/dist/commands/execute.d.ts +1 -0
- package/dist/commands/execute.js +31 -9
- package/dist/commands/parse-common-flags.d.ts +3 -1
- package/dist/commands/parse-common-flags.js +33 -4
- package/dist/commands/query.d.ts +2 -1
- package/dist/commands/query.js +32 -10
- 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/main.js +10 -4
- package/dist/utils/product-package-root.d.ts +6 -0
- package/dist/utils/product-package-root.js +39 -0
- package/package.json +15 -15
package/dist/builtin.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export declare const BUILTIN_COMMANDS: Set<string>;
|
|
|
12
12
|
* Falls back to direct main() call on any tracer failure.
|
|
13
13
|
*/
|
|
14
14
|
export declare function wrapWithTracer(builtinName: string, main: (args?: string[]) => Promise<void>, args: string[]): Promise<void>;
|
|
15
|
-
export declare function handleBuiltin(builtinName: string, args: string[]): Promise<void>;
|
|
15
|
+
export declare function handleBuiltin(builtinName: string, args: string[], productPackageRoot?: string): Promise<void>;
|
package/dist/builtin.js
CHANGED
|
@@ -106,7 +106,7 @@ async function wrapWithTracer(builtinName, main, args) {
|
|
|
106
106
|
}
|
|
107
107
|
await main(args);
|
|
108
108
|
}
|
|
109
|
-
async function handleBuiltin(builtinName, args) {
|
|
109
|
+
async function handleBuiltin(builtinName, args, productPackageRoot) {
|
|
110
110
|
const loader = BUILTIN_MAP[builtinName];
|
|
111
111
|
if (!loader) {
|
|
112
112
|
console.error(`Unknown built-in tool: ${builtinName}`);
|
|
@@ -114,7 +114,10 @@ async function handleBuiltin(builtinName, args) {
|
|
|
114
114
|
}
|
|
115
115
|
try {
|
|
116
116
|
const mod = await loader();
|
|
117
|
-
|
|
117
|
+
const main = builtinName === 'skill'
|
|
118
|
+
? (skillArgs) => mod.main(skillArgs, { productPackageRoot })
|
|
119
|
+
: mod.main.bind(mod);
|
|
120
|
+
await wrapWithTracer(builtinName, main, args);
|
|
118
121
|
}
|
|
119
122
|
catch (err) {
|
|
120
123
|
const code = err.code;
|
|
@@ -48,6 +48,12 @@ export declare function resolveReceiptMode(options: {
|
|
|
48
48
|
detachedRunner: boolean;
|
|
49
49
|
agentContext: boolean;
|
|
50
50
|
}): ReceiptModeDecision;
|
|
51
|
+
/**
|
|
52
|
+
* Rebuild runner argv from the parsed request. The resolved prompt is passed
|
|
53
|
+
* as one argv value after `--`, so stdin is never needed by the detached
|
|
54
|
+
* child and prompt text beginning with a dash remains positional text.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildDetachedRunnerArgs(filteredArgs: string[], agentRef: string, finalMessage: string): string[];
|
|
51
57
|
export type AssignedTaskAdoption = {
|
|
52
58
|
kind: 'adopted';
|
|
53
59
|
taskId: string;
|
|
@@ -86,4 +92,4 @@ export declare function runDetachedMiddle(command: string, hop: DetachedMiddleHo
|
|
|
86
92
|
* Persist a receipt and launch its detached runner. Unix uses one hop. Windows
|
|
87
93
|
* uses a short-lived middle hop so the final runner has no live parent link.
|
|
88
94
|
*/
|
|
89
|
-
export declare function runDetached(command: string, filteredArgs: string[], reason: ReceiptModeReason): Promise<void>;
|
|
95
|
+
export declare function runDetached(command: string, filteredArgs: string[], reason: ReceiptModeReason, invocationArgs?: string[]): Promise<void>;
|
|
@@ -12,6 +12,7 @@ exports.resolveReceiptActor = resolveReceiptActor;
|
|
|
12
12
|
exports.reportAdmissionBlocked = reportAdmissionBlocked;
|
|
13
13
|
exports.extractReceiptFlags = extractReceiptFlags;
|
|
14
14
|
exports.resolveReceiptMode = resolveReceiptMode;
|
|
15
|
+
exports.buildDetachedRunnerArgs = buildDetachedRunnerArgs;
|
|
15
16
|
exports.adoptAssignedTask = adoptAssignedTask;
|
|
16
17
|
exports.readAssignedTaskActor = readAssignedTaskActor;
|
|
17
18
|
exports.readDetachedMiddleHop = readDetachedMiddleHop;
|
|
@@ -26,10 +27,12 @@ const node_1 = require("@crewx/sdk/node");
|
|
|
26
27
|
const repository_1 = require("@crewx/sdk/repository");
|
|
27
28
|
const parse_agent_message_1 = require("./parse-agent-message");
|
|
28
29
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
30
|
+
const resolve_recipient_1 = require("./resolve-recipient");
|
|
29
31
|
const resolve_prompt_1 = require("./resolve-prompt");
|
|
30
32
|
const version_1 = require("../utils/version");
|
|
31
33
|
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
32
34
|
const cal_1 = require("./cal");
|
|
35
|
+
const emit_trailer_1 = require("./emit-trailer");
|
|
33
36
|
function nonEmptyString(value) {
|
|
34
37
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
35
38
|
}
|
|
@@ -73,6 +76,7 @@ function reportAdmissionBlocked(admission) {
|
|
|
73
76
|
const DETACHED_RUNNER_POLL_INTERVAL_MS = 200;
|
|
74
77
|
const DETACHED_RUNNER_ADOPTION_TIMEOUT_MS = 30_000;
|
|
75
78
|
const DETACHED_VALUE_FLAGS = [
|
|
79
|
+
'--to',
|
|
76
80
|
'--thread',
|
|
77
81
|
'--provider',
|
|
78
82
|
'--model',
|
|
@@ -268,6 +272,13 @@ function buildDetachedRunnerArgs(filteredArgs, agentRef, finalMessage) {
|
|
|
268
272
|
forwarded.push(arg);
|
|
269
273
|
continue;
|
|
270
274
|
}
|
|
275
|
+
if (arg === '--to') {
|
|
276
|
+
// The child receives the resolved recipient as a positional @agent.
|
|
277
|
+
i += 1;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (arg.startsWith('--to='))
|
|
281
|
+
continue;
|
|
271
282
|
if (!isDetachedValueFlag(arg))
|
|
272
283
|
continue;
|
|
273
284
|
if (isDetachedPromptFileFlag(arg)) {
|
|
@@ -426,15 +437,32 @@ async function runDetachedMiddle(command, hop) {
|
|
|
426
437
|
* Persist a receipt and launch its detached runner. Unix uses one hop. Windows
|
|
427
438
|
* uses a short-lived middle hop so the final runner has no live parent link.
|
|
428
439
|
*/
|
|
429
|
-
async function runDetached(command, filteredArgs, reason) {
|
|
440
|
+
async function runDetached(command, filteredArgs, reason, invocationArgs = filteredArgs) {
|
|
430
441
|
const parsedFlags = (0, parse_common_flags_1.parseCommonFlags)(filteredArgs);
|
|
431
|
-
const { thread, metadata, promptFile, rest } = parsedFlags;
|
|
442
|
+
const { thread, metadata, promptFile, rest, to } = parsedFlags;
|
|
432
443
|
const { agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest);
|
|
433
444
|
const finalMessage = await (0, resolve_prompt_1.resolvePrompt)(message, promptFile);
|
|
434
|
-
|
|
445
|
+
let agentRef;
|
|
446
|
+
try {
|
|
447
|
+
({ agentRef } = (0, resolve_recipient_1.resolveRecipient)({
|
|
448
|
+
positionalRef: parsedAgentRef,
|
|
449
|
+
toFlag: to,
|
|
450
|
+
agentContext: Boolean(process.env['CREWX_AGENT_ID']),
|
|
451
|
+
bodyForHint: finalMessage,
|
|
452
|
+
command,
|
|
453
|
+
invocationArgs,
|
|
454
|
+
}));
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
const messageText = errorMessage(error);
|
|
458
|
+
process.stderr.write(`Error: ${messageText}\n`);
|
|
459
|
+
(0, emit_trailer_1.emitDelegationResult)({ command, trace: (0, inherited_trace_1.readInheritedTrace)(), isError: true });
|
|
460
|
+
process.exit(2);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
435
463
|
if (!finalMessage) {
|
|
436
|
-
console.error('Usage: crewx
|
|
437
|
-
console.error(' @agent is
|
|
464
|
+
console.error('Usage: crewx q|x --to <agent> <message> [options]');
|
|
465
|
+
console.error(' @agent is a positional shorthand for selecting a recipient.');
|
|
438
466
|
console.error(' Task body can also be supplied via stdin pipe or --prompt-file.');
|
|
439
467
|
process.exit(1);
|
|
440
468
|
return;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Parses args, loads config via Crewx SDK, and executes the task.
|
|
4
4
|
*
|
|
5
5
|
* Flags:
|
|
6
|
+
* --to <agent> Explicit recipient (the positional @agent form is shorthand)
|
|
6
7
|
* --thread <name> Conversation thread name
|
|
7
8
|
* --provider <cli/xxx> Provider override
|
|
8
9
|
* --model <name> Model override (e.g. claude-sonnet-5)
|
package/dist/commands/execute.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Parses args, loads config via Crewx SDK, and executes the task.
|
|
5
5
|
*
|
|
6
6
|
* Flags:
|
|
7
|
+
* --to <agent> Explicit recipient (the positional @agent form is shorthand)
|
|
7
8
|
* --thread <name> Conversation thread name
|
|
8
9
|
* --provider <cli/xxx> Provider override
|
|
9
10
|
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
@@ -27,6 +28,7 @@ const sdk_1 = require("@crewx/sdk");
|
|
|
27
28
|
const repository_1 = require("@crewx/sdk/repository");
|
|
28
29
|
const parse_agent_message_1 = require("./parse-agent-message");
|
|
29
30
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
31
|
+
const resolve_recipient_1 = require("./resolve-recipient");
|
|
30
32
|
const resolve_prompt_1 = require("./resolve-prompt");
|
|
31
33
|
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
32
34
|
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
@@ -59,7 +61,7 @@ async function handleExecute(args, command = 'execute', emitState = (0, emit_tra
|
|
|
59
61
|
agentContext: Boolean(process.env['CREWX_AGENT_ID']),
|
|
60
62
|
});
|
|
61
63
|
if (receiptMode.receipt) {
|
|
62
|
-
await (0, detached_1.runDetached)(command, receiptFlags.rest, receiptMode.reason);
|
|
64
|
+
await (0, detached_1.runDetached)(command, receiptFlags.rest, receiptMode.reason, args);
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
let parsedFlags;
|
|
@@ -70,7 +72,7 @@ async function handleExecute(args, command = 'execute', emitState = (0, emit_tra
|
|
|
70
72
|
(0, emit_trailer_1.emitDelegationResult)({ command, isError: true, state: emitState });
|
|
71
73
|
throw err;
|
|
72
74
|
}
|
|
73
|
-
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = parsedFlags;
|
|
75
|
+
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest, to } = parsedFlags;
|
|
74
76
|
const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
|
|
75
77
|
let parsedAgentRef;
|
|
76
78
|
let message;
|
|
@@ -84,20 +86,40 @@ async function handleExecute(args, command = 'execute', emitState = (0, emit_tra
|
|
|
84
86
|
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
85
87
|
throw err;
|
|
86
88
|
}
|
|
87
|
-
|
|
89
|
+
let agentRef;
|
|
90
|
+
try {
|
|
91
|
+
({ agentRef } = (0, resolve_recipient_1.resolveRecipient)({
|
|
92
|
+
positionalRef: parsedAgentRef,
|
|
93
|
+
toFlag: to,
|
|
94
|
+
agentContext: Boolean(process.env['CREWX_AGENT_ID']),
|
|
95
|
+
bodyForHint: finalMessage,
|
|
96
|
+
command,
|
|
97
|
+
invocationArgs: args,
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
103
|
+
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
104
|
+
process.exit(2);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
88
107
|
if (!finalMessage) {
|
|
89
|
-
console.error('Usage: crewx execute
|
|
90
|
-
console.error(' crewx x
|
|
108
|
+
console.error('Usage: crewx execute --to <agent> <task> [options]');
|
|
109
|
+
console.error(' crewx x --to <agent> <task> [options]');
|
|
110
|
+
console.error(' crewx x @agent <task> [options] (@agent shorthand)');
|
|
91
111
|
console.error('');
|
|
92
|
-
console.error('
|
|
112
|
+
console.error(' Agent calls require --to or a positional @agent recipient.');
|
|
113
|
+
console.error(' Human terminal and cron calls default to @crewx when omitted.');
|
|
93
114
|
console.error(' Task body can also be supplied via stdin pipe or --prompt-file.');
|
|
94
115
|
console.error('');
|
|
95
116
|
console.error('Examples:');
|
|
96
|
-
console.error(' crewx x
|
|
97
|
-
console.error(' cat task.md | crewx x
|
|
98
|
-
console.error(' crewx x
|
|
117
|
+
console.error(' crewx x --to agent do something');
|
|
118
|
+
console.error(' cat task.md | crewx x --to agent');
|
|
119
|
+
console.error(' crewx x @agent label --prompt-file=task.md');
|
|
99
120
|
console.error('');
|
|
100
121
|
console.error('Options:');
|
|
122
|
+
console.error(' --to <agent> Explicit agent recipient');
|
|
101
123
|
console.error(' --thread <name> Conversation thread name');
|
|
102
124
|
console.error(' --provider <cli/xxx> Provider override');
|
|
103
125
|
console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
|
|
@@ -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, --model, --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,6 +12,8 @@
|
|
|
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;
|
|
17
19
|
/** Model override (e.g., claude-sonnet-5). */
|
|
@@ -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, --model, --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,6 +61,7 @@ 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');
|
|
66
67
|
const model = parseFlag(args, '--model');
|
|
@@ -73,7 +74,7 @@ function parseCommonFlags(args) {
|
|
|
73
74
|
const verbose = hasFlag(args, '--verbose');
|
|
74
75
|
const overdrive = hasFlag(args, '--overdrive');
|
|
75
76
|
// Collect consumed positions for known flags
|
|
76
|
-
const consumed = new Set();
|
|
77
|
+
const consumed = new Set(toConsumed);
|
|
77
78
|
const flagPairs = [
|
|
78
79
|
{ names: ['--thread'] },
|
|
79
80
|
{ names: ['--provider'] },
|
|
@@ -149,7 +150,7 @@ function parseCommonFlags(args) {
|
|
|
149
150
|
if (!escapeMode && token.startsWith('--')) {
|
|
150
151
|
throw new UnknownOptionError(`Unknown option: ${token}. Use "--" to pass literal flag-like tokens as message.\n` +
|
|
151
152
|
` Did you mean: crewx serve ${token}\n` +
|
|
152
|
-
` or: crewx q -- ${token} <message
|
|
153
|
+
` or: crewx q --to <agent> -- ${token} <message>`);
|
|
153
154
|
}
|
|
154
155
|
// Reject short -x flags that are not numeric (e.g. -f was consumed above)
|
|
155
156
|
if (!escapeMode && token.startsWith('-') && token.length > 1 && !/^-?\d/.test(token)) {
|
|
@@ -157,7 +158,35 @@ function parseCommonFlags(args) {
|
|
|
157
158
|
}
|
|
158
159
|
rest.push(token);
|
|
159
160
|
}
|
|
160
|
-
return { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, 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 };
|
|
161
190
|
}
|
|
162
191
|
/**
|
|
163
192
|
* Parse metadata JSON string from --metadata flag.
|
package/dist/commands/query.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Parses args, loads config via Crewx SDK, and executes the query.
|
|
4
4
|
*
|
|
5
5
|
* Flags:
|
|
6
|
+
* --to <agent> Explicit recipient (the positional @agent form is shorthand)
|
|
6
7
|
* --thread <name> Conversation thread name
|
|
7
8
|
* --provider <cli/xxx> Provider override
|
|
8
9
|
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
*
|
|
19
20
|
* Stdin support:
|
|
20
21
|
* Pipe or redirect content into crewx q to supply the prompt body via stdin.
|
|
21
|
-
* e.g. cat brief.md | crewx q
|
|
22
|
+
* e.g. cat brief.md | crewx q --to agent label
|
|
22
23
|
* Stdin is ignored when running in an interactive TTY.
|
|
23
24
|
*/
|
|
24
25
|
import { type DelegationEmitState } from './emit-trailer';
|
package/dist/commands/query.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Parses args, loads config via Crewx SDK, and executes the query.
|
|
5
5
|
*
|
|
6
6
|
* Flags:
|
|
7
|
+
* --to <agent> Explicit recipient (the positional @agent form is shorthand)
|
|
7
8
|
* --thread <name> Conversation thread name
|
|
8
9
|
* --provider <cli/xxx> Provider override
|
|
9
10
|
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
*
|
|
20
21
|
* Stdin support:
|
|
21
22
|
* Pipe or redirect content into crewx q to supply the prompt body via stdin.
|
|
22
|
-
* e.g. cat brief.md | crewx q
|
|
23
|
+
* e.g. cat brief.md | crewx q --to agent label
|
|
23
24
|
* Stdin is ignored when running in an interactive TTY.
|
|
24
25
|
*/
|
|
25
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -28,6 +29,7 @@ const sdk_1 = require("@crewx/sdk");
|
|
|
28
29
|
const repository_1 = require("@crewx/sdk/repository");
|
|
29
30
|
const parse_agent_message_1 = require("./parse-agent-message");
|
|
30
31
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
32
|
+
const resolve_recipient_1 = require("./resolve-recipient");
|
|
31
33
|
const resolve_prompt_1 = require("./resolve-prompt");
|
|
32
34
|
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
33
35
|
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
@@ -56,7 +58,7 @@ async function handleQuery(args, command = 'query', emitState = (0, emit_trailer
|
|
|
56
58
|
agentContext: Boolean(process.env['CREWX_AGENT_ID']),
|
|
57
59
|
});
|
|
58
60
|
if (receiptMode.receipt) {
|
|
59
|
-
await (0, detached_1.runDetached)(command, receiptFlags.rest, receiptMode.reason);
|
|
61
|
+
await (0, detached_1.runDetached)(command, receiptFlags.rest, receiptMode.reason, args);
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
let parsedFlags;
|
|
@@ -67,7 +69,7 @@ async function handleQuery(args, command = 'query', emitState = (0, emit_trailer
|
|
|
67
69
|
(0, emit_trailer_1.emitDelegationResult)({ command, isError: true, state: emitState });
|
|
68
70
|
throw err;
|
|
69
71
|
}
|
|
70
|
-
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = parsedFlags;
|
|
72
|
+
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest, to } = parsedFlags;
|
|
71
73
|
const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
|
|
72
74
|
let parsedAgentRef;
|
|
73
75
|
let message;
|
|
@@ -81,20 +83,40 @@ async function handleQuery(args, command = 'query', emitState = (0, emit_trailer
|
|
|
81
83
|
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
82
84
|
throw err;
|
|
83
85
|
}
|
|
84
|
-
|
|
86
|
+
let agentRef;
|
|
87
|
+
try {
|
|
88
|
+
({ agentRef } = (0, resolve_recipient_1.resolveRecipient)({
|
|
89
|
+
positionalRef: parsedAgentRef,
|
|
90
|
+
toFlag: to,
|
|
91
|
+
agentContext: Boolean(process.env['CREWX_AGENT_ID']),
|
|
92
|
+
bodyForHint: finalMessage,
|
|
93
|
+
command,
|
|
94
|
+
invocationArgs: args,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
99
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
100
|
+
(0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
|
|
101
|
+
process.exit(2);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
85
104
|
if (!finalMessage) {
|
|
86
|
-
console.error('Usage: crewx query
|
|
87
|
-
console.error(' crewx q
|
|
105
|
+
console.error('Usage: crewx query --to <agent> <message> [options]');
|
|
106
|
+
console.error(' crewx q --to <agent> <message> [options]');
|
|
107
|
+
console.error(' crewx q @agent <message> [options] (@agent shorthand)');
|
|
88
108
|
console.error('');
|
|
89
|
-
console.error('
|
|
109
|
+
console.error(' Agent calls require --to or a positional @agent recipient.');
|
|
110
|
+
console.error(' Human terminal and cron calls default to @crewx when omitted.');
|
|
90
111
|
console.error(' Prompt can also be supplied via stdin pipe or --prompt-file.');
|
|
91
112
|
console.error('');
|
|
92
113
|
console.error('Examples:');
|
|
93
|
-
console.error(' crewx q
|
|
94
|
-
console.error(' cat brief.md | crewx q
|
|
95
|
-
console.error(' crewx q
|
|
114
|
+
console.error(' crewx q --to agent hello');
|
|
115
|
+
console.error(' cat brief.md | crewx q --to agent');
|
|
116
|
+
console.error(' crewx q @agent label --prompt-file=brief.md');
|
|
96
117
|
console.error('');
|
|
97
118
|
console.error('Options:');
|
|
119
|
+
console.error(' --to <agent> Explicit agent recipient');
|
|
98
120
|
console.error(' --thread <name> Conversation thread name');
|
|
99
121
|
console.error(' --provider <cli/xxx> Provider override');
|
|
100
122
|
console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
|
|
@@ -14,6 +14,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
exports.readStdin = readStdin;
|
|
15
15
|
exports.resolvePrompt = resolvePrompt;
|
|
16
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
|
+
}
|
|
17
39
|
/**
|
|
18
40
|
* Read all bytes from stdin (pipe or redirect).
|
|
19
41
|
* Returns empty string when stdin is a TTY (interactive terminal).
|
|
@@ -43,7 +65,7 @@ async function readStdin() {
|
|
|
43
65
|
async function resolvePrompt(argvPrompt, promptFile, _readStdin = readStdin) {
|
|
44
66
|
let external = '';
|
|
45
67
|
if (promptFile) {
|
|
46
|
-
external = (
|
|
68
|
+
external = decodePromptFile(promptFile).trimEnd();
|
|
47
69
|
}
|
|
48
70
|
else if (!argvPrompt) {
|
|
49
71
|
external = (await _readStdin()).trimEnd();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ResolveRecipientOptions {
|
|
2
|
+
positionalRef?: string;
|
|
3
|
+
toFlag?: string;
|
|
4
|
+
agentContext: boolean;
|
|
5
|
+
bodyForHint?: string;
|
|
6
|
+
command?: string;
|
|
7
|
+
invocationArgs?: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare class RecipientResolutionError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
export declare function resolveRecipient(options: ResolveRecipientOptions): {
|
|
13
|
+
agentRef: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecipientResolutionError = void 0;
|
|
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
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -86,6 +86,7 @@ const db_1 = require("./commands/db");
|
|
|
86
86
|
const parse_common_flags_1 = require("./commands/parse-common-flags");
|
|
87
87
|
const registry_1 = require("./commands/registry");
|
|
88
88
|
const version_1 = require("./utils/version");
|
|
89
|
+
const product_package_root_1 = require("./utils/product-package-root");
|
|
89
90
|
const emit_trailer_1 = require("./commands/emit-trailer");
|
|
90
91
|
/**
|
|
91
92
|
* Dev-only SSOT assertion: bin/cli-commands.js must be the exact union of
|
|
@@ -123,7 +124,10 @@ async function main(emitState) {
|
|
|
123
124
|
}
|
|
124
125
|
// Built-in tools: memory, search, doc, wbs, cron, workflow, skill
|
|
125
126
|
if (builtin_1.BUILTIN_COMMANDS.has(command)) {
|
|
126
|
-
|
|
127
|
+
const productPackageRoot = command === 'skill'
|
|
128
|
+
? (0, product_package_root_1.resolveProductRootFromCliEntry)(process.argv[1])
|
|
129
|
+
: undefined;
|
|
130
|
+
await (0, builtin_1.handleBuiltin)(command, args.slice(1), productPackageRoot);
|
|
127
131
|
return;
|
|
128
132
|
}
|
|
129
133
|
// Core commands
|
|
@@ -276,12 +280,14 @@ UI Modes:
|
|
|
276
280
|
crewx electron [--overlay] Launch Electron (desktop or overlay window)
|
|
277
281
|
|
|
278
282
|
Query / Execute:
|
|
279
|
-
q|query
|
|
280
|
-
x|execute
|
|
283
|
+
q|query --to <agent> <message> Query an agent
|
|
284
|
+
x|execute --to <agent> <task> Execute a task with an agent
|
|
281
285
|
|
|
282
|
-
@agent is
|
|
286
|
+
Positional @agent <message> is shorthand for selecting a recipient.
|
|
287
|
+
Agent calls require a recipient; human terminal and cron calls default to @crewx.
|
|
283
288
|
|
|
284
289
|
Common flags:
|
|
290
|
+
--to <agent> Explicit agent recipient
|
|
285
291
|
--thread <name> Conversation thread
|
|
286
292
|
--provider <cli/xxx> Provider override
|
|
287
293
|
--metadata <json> Extra metadata (JSON object, double-quoted). Propagated to events/hooks/tracing.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the installed product root from the CLI entry file that is running.
|
|
3
|
+
* The real CLI path is walked to the first package named `crewx`, which must
|
|
4
|
+
* contain the compiled bundle helper. cwd and environment are deliberately ignored.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveProductRootFromCliEntry(cliEntryPath: string | undefined): string | undefined;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveProductRootFromCliEntry = resolveProductRootFromCliEntry;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const PRODUCT_BUNDLE_HELPER = (0, node_path_1.join)('dist-server', 'common', 'product-app-bundle.js');
|
|
7
|
+
/**
|
|
8
|
+
* Finds the installed product root from the CLI entry file that is running.
|
|
9
|
+
* The real CLI path is walked to the first package named `crewx`, which must
|
|
10
|
+
* contain the compiled bundle helper. cwd and environment are deliberately ignored.
|
|
11
|
+
*/
|
|
12
|
+
function resolveProductRootFromCliEntry(cliEntryPath) {
|
|
13
|
+
if (typeof cliEntryPath !== 'string' || cliEntryPath.trim().length === 0)
|
|
14
|
+
return undefined;
|
|
15
|
+
let realCliEntryPath;
|
|
16
|
+
try {
|
|
17
|
+
realCliEntryPath = (0, node_fs_1.realpathSync)(cliEntryPath);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
let current = (0, node_path_1.dirname)(realCliEntryPath);
|
|
23
|
+
while (true) {
|
|
24
|
+
try {
|
|
25
|
+
const packageJson = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(current, 'package.json'), 'utf8'));
|
|
26
|
+
if (packageJson.name === 'crewx') {
|
|
27
|
+
return (0, node_fs_1.existsSync)((0, node_path_1.join)(current, PRODUCT_BUNDLE_HELPER)) ? current : undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Continue to the next ancestor when this directory has no valid package manifest.
|
|
32
|
+
}
|
|
33
|
+
const parent = (0, node_path_1.dirname)(current);
|
|
34
|
+
if (parent === current)
|
|
35
|
+
return undefined;
|
|
36
|
+
current = parent;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
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.129",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -25,20 +25,20 @@
|
|
|
25
25
|
"better-sqlite3": "*",
|
|
26
26
|
"dotenv": "17.2.3",
|
|
27
27
|
"isomorphic-git": "1.37.1",
|
|
28
|
-
"@crewx/
|
|
29
|
-
"@crewx/
|
|
30
|
-
"@crewx/
|
|
31
|
-
"@crewx/
|
|
32
|
-
"@crewx/wbs": "0.1.10-rc.
|
|
33
|
-
"@crewx/
|
|
34
|
-
"@crewx/
|
|
35
|
-
"@crewx/
|
|
36
|
-
"@crewx/
|
|
37
|
-
"@crewx/
|
|
38
|
-
"@crewx/
|
|
39
|
-
"@crewx/
|
|
40
|
-
"@crewx/
|
|
41
|
-
"@crewx/
|
|
28
|
+
"@crewx/search": "0.1.10-rc.125",
|
|
29
|
+
"@crewx/sdk": "0.9.0-rc.129",
|
|
30
|
+
"@crewx/memory": "0.1.23-rc.146",
|
|
31
|
+
"@crewx/doc": "0.1.9-rc.122",
|
|
32
|
+
"@crewx/wbs": "0.1.10-rc.155",
|
|
33
|
+
"@crewx/workflow": "0.3.22-rc.175",
|
|
34
|
+
"@crewx/cron": "0.1.10-rc.164",
|
|
35
|
+
"@crewx/skill": "0.1.20-rc.23",
|
|
36
|
+
"@crewx/notify": "0.1.0-rc.100",
|
|
37
|
+
"@crewx/app": "0.1.0-rc.10",
|
|
38
|
+
"@crewx/knowledge-core": "0.1.17-rc.139",
|
|
39
|
+
"@crewx/wi": "0.1.10-rc.149",
|
|
40
|
+
"@crewx/shared": "0.0.6-rc.44",
|
|
41
|
+
"@crewx/chromex": "0.1.0-rc.162"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/better-sqlite3": "*",
|