@crewx/cli 0.9.0-rc.6 → 0.9.0-rc.60
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 +45 -0
- package/dist/bootstrap/codex-writable-roots.js +88 -0
- package/dist/bootstrap/crewx-cli.js +2 -0
- package/dist/builtin.js +1 -0
- package/dist/commands/doctor.d.ts +17 -0
- package/dist/commands/doctor.js +21 -11
- package/dist/commands/execute.d.ts +4 -0
- package/dist/commands/execute.js +107 -3
- package/dist/commands/init.js +22 -1
- package/dist/commands/log.js +4 -3
- package/dist/commands/parse-common-flags.d.ts +8 -2
- package/dist/commands/parse-common-flags.js +12 -3
- package/dist/commands/ps.js +51 -2
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.js +270 -0
- package/dist/commands/query.d.ts +1 -0
- package/dist/commands/query.js +15 -2
- package/dist/commands/registry.js +3 -1
- package/dist/commands/restart.js +20 -6
- package/dist/commands/result.d.ts +7 -3
- package/dist/commands/result.js +41 -6
- 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/write-output.d.ts +3 -0
- package/dist/commands/write-output.js +24 -0
- package/dist/logging.d.ts +1 -1
- package/dist/logging.js +3 -2
- package/dist/main.d.ts +3 -2
- package/dist/main.js +45 -7
- package/dist/utils/env-defaults.d.ts +2 -5
- package/dist/utils/env-defaults.js +10 -5
- package/dist/utils/sdk-compat.d.ts +21 -0
- package/dist/utils/sdk-compat.js +72 -0
- package/package.json +12 -10
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-layer policy: inject CrewX home as an extra writable root for Codex
|
|
3
|
+
* `workspace-write` sandbox invocations.
|
|
4
|
+
*
|
|
5
|
+
* Why this lives in packages/cli (not packages/sdk):
|
|
6
|
+
* CrewX home (`~/.crewx` by default) is a product-specific path. The SDK's
|
|
7
|
+
* `additionalArgsProvider` extension point (WI-20260703-001) exists precisely
|
|
8
|
+
* so that product layers like this CLI can inject such paths without the SDK
|
|
9
|
+
* knowing about them.
|
|
10
|
+
*
|
|
11
|
+
* Why `-c sandbox_workspace_write.writable_roots=[...]` instead of `--add-dir`:
|
|
12
|
+
* Verified against codex-cli 0.139.0 (`codex exec --help` / `codex exec resume --help`):
|
|
13
|
+
* - `codex exec` supports `--add-dir <DIR>`.
|
|
14
|
+
* - `codex exec resume` does NOT support `--add-dir` (only `-c/--config`).
|
|
15
|
+
* Using the `-c` config-override form works identically for both `exec` and
|
|
16
|
+
* `exec resume`, avoiding a resume-incompatible flag.
|
|
17
|
+
*/
|
|
18
|
+
import type { AdditionalArgsProvider } from '@crewx/sdk';
|
|
19
|
+
/**
|
|
20
|
+
* Resolve CrewX home directory.
|
|
21
|
+
* Priority: `CREWX_HOME` env var → `~/.crewx`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveCrewxHome(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Escape a string for embedding inside a TOML basic string (`"..."`).
|
|
26
|
+
* Sufficient for filesystem paths: handles backslash (Windows paths),
|
|
27
|
+
* double-quote, and control characters that could otherwise break TOML
|
|
28
|
+
* parsing of the `-c key="value"` override.
|
|
29
|
+
*/
|
|
30
|
+
export declare function escapeTomlBasicString(value: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Build the `-c sandbox_workspace_write.writable_roots=["<path>"]` arg pair.
|
|
33
|
+
* Works for both `codex exec` and `codex exec resume` (config-override form).
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildCodexWritableRootArgs(crewxHome: string): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Create an `AdditionalArgsProvider` (SDK extension point, WI-20260703-001)
|
|
38
|
+
* that injects CrewX home as a Codex writable root for `workspace-write`
|
|
39
|
+
* equivalent modes (`agent`, `auto`, `undefined`).
|
|
40
|
+
*
|
|
41
|
+
* No-ops for:
|
|
42
|
+
* - Non-codex providers.
|
|
43
|
+
* - Modes in {@link NO_INJECT_MODES} (read-only/plan/agent-full-access/yolo/danger-full-access).
|
|
44
|
+
*/
|
|
45
|
+
export declare function createCodexWritableRootsProvider(crewxHome?: string): AdditionalArgsProvider;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLI-layer policy: inject CrewX home as an extra writable root for Codex
|
|
4
|
+
* `workspace-write` sandbox invocations.
|
|
5
|
+
*
|
|
6
|
+
* Why this lives in packages/cli (not packages/sdk):
|
|
7
|
+
* CrewX home (`~/.crewx` by default) is a product-specific path. The SDK's
|
|
8
|
+
* `additionalArgsProvider` extension point (WI-20260703-001) exists precisely
|
|
9
|
+
* so that product layers like this CLI can inject such paths without the SDK
|
|
10
|
+
* knowing about them.
|
|
11
|
+
*
|
|
12
|
+
* Why `-c sandbox_workspace_write.writable_roots=[...]` instead of `--add-dir`:
|
|
13
|
+
* Verified against codex-cli 0.139.0 (`codex exec --help` / `codex exec resume --help`):
|
|
14
|
+
* - `codex exec` supports `--add-dir <DIR>`.
|
|
15
|
+
* - `codex exec resume` does NOT support `--add-dir` (only `-c/--config`).
|
|
16
|
+
* Using the `-c` config-override form works identically for both `exec` and
|
|
17
|
+
* `exec resume`, avoiding a resume-incompatible flag.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.resolveCrewxHome = resolveCrewxHome;
|
|
21
|
+
exports.escapeTomlBasicString = escapeTomlBasicString;
|
|
22
|
+
exports.buildCodexWritableRootArgs = buildCodexWritableRootArgs;
|
|
23
|
+
exports.createCodexWritableRootsProvider = createCodexWritableRootsProvider;
|
|
24
|
+
const os_1 = require("os");
|
|
25
|
+
const path_1 = require("path");
|
|
26
|
+
/**
|
|
27
|
+
* crewx.yaml / query-option `mode` values for which Codex is NOT running in
|
|
28
|
+
* (or being pushed into) a `workspace-write`-equivalent sandbox. Injecting an
|
|
29
|
+
* extra writable root is meaningless (read-only/plan) or redundant
|
|
30
|
+
* (full-access variants already allow writes everywhere) in these modes.
|
|
31
|
+
*/
|
|
32
|
+
const NO_INJECT_MODES = new Set([
|
|
33
|
+
'read-only',
|
|
34
|
+
'plan',
|
|
35
|
+
'agent-full-access',
|
|
36
|
+
'yolo',
|
|
37
|
+
'danger-full-access',
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Resolve CrewX home directory.
|
|
41
|
+
* Priority: `CREWX_HOME` env var → `~/.crewx`.
|
|
42
|
+
*/
|
|
43
|
+
function resolveCrewxHome() {
|
|
44
|
+
return process.env.CREWX_HOME ?? (0, path_1.join)((0, os_1.homedir)(), '.crewx');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Escape a string for embedding inside a TOML basic string (`"..."`).
|
|
48
|
+
* Sufficient for filesystem paths: handles backslash (Windows paths),
|
|
49
|
+
* double-quote, and control characters that could otherwise break TOML
|
|
50
|
+
* parsing of the `-c key="value"` override.
|
|
51
|
+
*/
|
|
52
|
+
function escapeTomlBasicString(value) {
|
|
53
|
+
return value
|
|
54
|
+
.replace(/\\/g, '\\\\')
|
|
55
|
+
.replace(/"/g, '\\"')
|
|
56
|
+
.replace(/\n/g, '\\n')
|
|
57
|
+
.replace(/\r/g, '\\r')
|
|
58
|
+
.replace(/\t/g, '\\t');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build the `-c sandbox_workspace_write.writable_roots=["<path>"]` arg pair.
|
|
62
|
+
* Works for both `codex exec` and `codex exec resume` (config-override form).
|
|
63
|
+
*/
|
|
64
|
+
function buildCodexWritableRootArgs(crewxHome) {
|
|
65
|
+
const escaped = escapeTomlBasicString(crewxHome);
|
|
66
|
+
return ['-c', `sandbox_workspace_write.writable_roots=["${escaped}"]`];
|
|
67
|
+
}
|
|
68
|
+
function isCodexProvider(ctx) {
|
|
69
|
+
return ctx.providerId === 'codex' || ctx.providerStr === 'cli/codex';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create an `AdditionalArgsProvider` (SDK extension point, WI-20260703-001)
|
|
73
|
+
* that injects CrewX home as a Codex writable root for `workspace-write`
|
|
74
|
+
* equivalent modes (`agent`, `auto`, `undefined`).
|
|
75
|
+
*
|
|
76
|
+
* No-ops for:
|
|
77
|
+
* - Non-codex providers.
|
|
78
|
+
* - Modes in {@link NO_INJECT_MODES} (read-only/plan/agent-full-access/yolo/danger-full-access).
|
|
79
|
+
*/
|
|
80
|
+
function createCodexWritableRootsProvider(crewxHome = resolveCrewxHome()) {
|
|
81
|
+
return (ctx) => {
|
|
82
|
+
if (!isCodexProvider(ctx))
|
|
83
|
+
return [];
|
|
84
|
+
if (ctx.mode !== undefined && NO_INJECT_MODES.has(ctx.mode))
|
|
85
|
+
return [];
|
|
86
|
+
return buildCodexWritableRootArgs(crewxHome);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -9,6 +9,7 @@ const plugins_1 = require("@crewx/sdk/plugins");
|
|
|
9
9
|
const repository_1 = require("@crewx/sdk/repository");
|
|
10
10
|
const register_builtin_tools_1 = require("../register-builtin-tools");
|
|
11
11
|
const version_1 = require("../utils/version");
|
|
12
|
+
const codex_writable_roots_1 = require("./codex-writable-roots");
|
|
12
13
|
/**
|
|
13
14
|
* Build a Crewx instance with CLI-standard plugins (FileLogger + SqliteTracing)
|
|
14
15
|
* and built-in tools registered. Use this from any CLI command that needs a
|
|
@@ -52,6 +53,7 @@ async function createCliCrewx(configPath = process.env.CREWX_CONFIG ?? 'crewx.ya
|
|
|
52
53
|
}
|
|
53
54
|
const crewx = await sdk_1.Crewx.loadYaml(yamlPath, {
|
|
54
55
|
remoteFactory: createCliCrewx,
|
|
56
|
+
additionalArgsProvider: (0, codex_writable_roots_1.createCodexWritableRootsProvider)(),
|
|
55
57
|
});
|
|
56
58
|
(0, register_builtin_tools_1.registerBuiltinToolsIfNeeded)(crewx);
|
|
57
59
|
await crewx.use(new plugins_1.ConversationPlugin());
|
package/dist/builtin.js
CHANGED
|
@@ -55,6 +55,7 @@ const BUILTIN_MAP = {
|
|
|
55
55
|
dreaming: () => Promise.resolve().then(() => __importStar(require('@crewx/dreaming/cli'))),
|
|
56
56
|
wi: () => Promise.resolve().then(() => __importStar(require('@crewx/wi/cli'))),
|
|
57
57
|
chromex: () => Promise.resolve().then(() => __importStar(require('@crewx/chromex/cli'))),
|
|
58
|
+
notify: () => Promise.resolve().then(() => __importStar(require('@crewx/notify/cli'))),
|
|
58
59
|
};
|
|
59
60
|
exports.BUILTIN_COMMANDS = new Set(Object.keys(BUILTIN_MAP));
|
|
60
61
|
// Load skill-tracer for observability (graceful degradation if unavailable)
|
|
@@ -6,7 +6,24 @@
|
|
|
6
6
|
* crewx doctor Run full diagnosis
|
|
7
7
|
* crewx doctor --config <path> Use specific config file
|
|
8
8
|
*/
|
|
9
|
+
interface DiagnosticResult {
|
|
10
|
+
name: string;
|
|
11
|
+
status: 'success' | 'warning' | 'error';
|
|
12
|
+
message: string;
|
|
13
|
+
details?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CliProviderInfo {
|
|
16
|
+
cmd: string;
|
|
17
|
+
install: string;
|
|
18
|
+
}
|
|
19
|
+
/** CLI diagnostics keyed by the bare provider name used in PROVIDER_ORDER. */
|
|
20
|
+
export declare const CLI_PROVIDER_INFO: Record<string, CliProviderInfo>;
|
|
21
|
+
/**
|
|
22
|
+
* Check CLI provider availability in the canonical PROVIDER_ORDER.
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkCliProviders(): DiagnosticResult[];
|
|
9
25
|
/**
|
|
10
26
|
* Handle `crewx doctor` command.
|
|
11
27
|
*/
|
|
12
28
|
export declare function handleDoctor(args: string[]): Promise<void>;
|
|
29
|
+
export {};
|
package/dist/commands/doctor.js
CHANGED
|
@@ -8,12 +8,23 @@
|
|
|
8
8
|
* crewx doctor --config <path> Use specific config file
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.CLI_PROVIDER_INFO = void 0;
|
|
12
|
+
exports.checkCliProviders = checkCliProviders;
|
|
11
13
|
exports.handleDoctor = handleDoctor;
|
|
12
14
|
const fs_1 = require("fs");
|
|
13
15
|
const path_1 = require("path");
|
|
14
16
|
const child_process_1 = require("child_process");
|
|
15
17
|
const sdk_1 = require("@crewx/sdk");
|
|
16
18
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
19
|
+
/** CLI diagnostics keyed by the bare provider name used in PROVIDER_ORDER. */
|
|
20
|
+
exports.CLI_PROVIDER_INFO = {
|
|
21
|
+
codex: { cmd: 'codex', install: 'npm install -g @openai/codex' },
|
|
22
|
+
claude: { cmd: 'claude', install: 'npm install -g @anthropic-ai/claude-code' },
|
|
23
|
+
grok: { cmd: 'grok', install: 'curl -fsSL https://x.ai/cli/install.sh | bash' },
|
|
24
|
+
opencode: { cmd: 'opencode', install: 'npm install -g opencode' },
|
|
25
|
+
antigravity: { cmd: 'antigravity', install: 'npm install -g antigravity' },
|
|
26
|
+
copilot: { cmd: 'gh', install: 'brew install gh # or visit cli.github.com' },
|
|
27
|
+
};
|
|
17
28
|
function statusIcon(status) {
|
|
18
29
|
switch (status) {
|
|
19
30
|
case 'success': return '✅';
|
|
@@ -99,20 +110,19 @@ function checkLogsDir() {
|
|
|
99
110
|
};
|
|
100
111
|
}
|
|
101
112
|
/**
|
|
102
|
-
* Check CLI provider availability.
|
|
103
|
-
* Providers are checked in PROVIDER_ORDER: codex → claude → opencode → antigravity → copilot.
|
|
113
|
+
* Check CLI provider availability in the canonical PROVIDER_ORDER.
|
|
104
114
|
*/
|
|
105
115
|
function checkCliProviders() {
|
|
106
|
-
// Map each provider (in PROVIDER_ORDER) to its CLI command and install hint.
|
|
107
|
-
const providerInfo = {
|
|
108
|
-
codex: { cmd: 'codex', install: 'npm install -g @openai/codex' },
|
|
109
|
-
claude: { cmd: 'claude', install: 'npm install -g @anthropic-ai/claude-code' },
|
|
110
|
-
opencode: { cmd: 'opencode', install: 'npm install -g opencode' },
|
|
111
|
-
antigravity: { cmd: 'antigravity', install: 'npm install -g antigravity' },
|
|
112
|
-
copilot: { cmd: 'gh', install: 'brew install gh # or visit cli.github.com' },
|
|
113
|
-
};
|
|
114
116
|
return sdk_1.PROVIDER_ORDER.map(provider => {
|
|
115
|
-
const info =
|
|
117
|
+
const info = exports.CLI_PROVIDER_INFO[provider];
|
|
118
|
+
if (!info) {
|
|
119
|
+
return {
|
|
120
|
+
name: `${provider.toUpperCase()} CLI`,
|
|
121
|
+
status: 'error',
|
|
122
|
+
message: 'Diagnostic metadata is missing',
|
|
123
|
+
details: `Add ${provider} to CLI_PROVIDER_INFO.`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
116
126
|
const displayName = provider === 'copilot' ? 'copilot (gh)' : provider;
|
|
117
127
|
const available = isCommandAvailable(info.cmd);
|
|
118
128
|
return {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Flags:
|
|
6
6
|
* --thread <name> Conversation thread name
|
|
7
7
|
* --provider <cli/xxx> Provider override
|
|
8
|
+
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
8
9
|
* --metadata <json> Extra metadata JSON (double-quoted object). Propagated to events/hooks/tracing.
|
|
9
10
|
* e.g. --metadata='{"workflow_id":"wf-1"}'
|
|
10
11
|
* --verbose Debug output mode (default: raw agent response only)
|
|
@@ -12,6 +13,9 @@
|
|
|
12
13
|
* --output-format <fmt> Output format (json|text|stream-json)
|
|
13
14
|
* --effort <level> Model effort (high|medium|low)
|
|
14
15
|
* -f/--prompt-file <path> Read task body from file (bypasses cmd.exe argv truncation)
|
|
16
|
+
* --detach Re-spawn as a detached runner; print task-id and exit 0 immediately.
|
|
17
|
+
* Ignored when CREWX_TRACE_ID is already set (recursive-spawn guard) or
|
|
18
|
+
* on win32 (unsupported — exits with an error).
|
|
15
19
|
*
|
|
16
20
|
* Stdin support:
|
|
17
21
|
* Pipe or redirect content into crewx x to supply the task body via stdin.
|
package/dist/commands/execute.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Flags:
|
|
7
7
|
* --thread <name> Conversation thread name
|
|
8
8
|
* --provider <cli/xxx> Provider override
|
|
9
|
+
* --model <name> Model override (e.g. claude-sonnet-5)
|
|
9
10
|
* --metadata <json> Extra metadata JSON (double-quoted object). Propagated to events/hooks/tracing.
|
|
10
11
|
* e.g. --metadata='{"workflow_id":"wf-1"}'
|
|
11
12
|
* --verbose Debug output mode (default: raw agent response only)
|
|
@@ -13,6 +14,9 @@
|
|
|
13
14
|
* --output-format <fmt> Output format (json|text|stream-json)
|
|
14
15
|
* --effort <level> Model effort (high|medium|low)
|
|
15
16
|
* -f/--prompt-file <path> Read task body from file (bypasses cmd.exe argv truncation)
|
|
17
|
+
* --detach Re-spawn as a detached runner; print task-id and exit 0 immediately.
|
|
18
|
+
* Ignored when CREWX_TRACE_ID is already set (recursive-spawn guard) or
|
|
19
|
+
* on win32 (unsupported — exits with an error).
|
|
16
20
|
*
|
|
17
21
|
* Stdin support:
|
|
18
22
|
* Pipe or redirect content into crewx x to supply the task body via stdin.
|
|
@@ -21,12 +25,72 @@
|
|
|
21
25
|
*/
|
|
22
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
27
|
exports.handleExecute = handleExecute;
|
|
28
|
+
const child_process_1 = require("child_process");
|
|
29
|
+
const fs_1 = require("fs");
|
|
30
|
+
const path_1 = require("path");
|
|
31
|
+
const os_1 = require("os");
|
|
24
32
|
const sdk_1 = require("@crewx/sdk");
|
|
25
33
|
const parse_agent_message_1 = require("./parse-agent-message");
|
|
26
34
|
const parse_common_flags_1 = require("./parse-common-flags");
|
|
27
35
|
const resolve_prompt_1 = require("./resolve-prompt");
|
|
28
36
|
const crewx_cli_1 = require("../bootstrap/crewx-cli");
|
|
29
37
|
const inherited_trace_1 = require("../utils/inherited-trace");
|
|
38
|
+
const write_output_1 = require("./write-output");
|
|
39
|
+
/**
|
|
40
|
+
* Split `--detach` out of argv, respecting the `--` literal-args sentinel
|
|
41
|
+
* (a `--detach` appearing after `--` is message text, not the flag).
|
|
42
|
+
*/
|
|
43
|
+
function extractDetachFlag(args) {
|
|
44
|
+
const rest = [];
|
|
45
|
+
let detach = false;
|
|
46
|
+
let escapeMode = false;
|
|
47
|
+
for (const arg of args) {
|
|
48
|
+
if (!escapeMode && arg === '--') {
|
|
49
|
+
escapeMode = true;
|
|
50
|
+
rest.push(arg);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!escapeMode && arg === '--detach') {
|
|
54
|
+
detach = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
rest.push(arg);
|
|
58
|
+
}
|
|
59
|
+
return { detach, rest };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Double-detach: re-spawn this same CLI entry (minus --detach) as a detached
|
|
63
|
+
* process so it survives the parent's exit. The task-id is pre-generated here
|
|
64
|
+
* and injected as CREWX_TRACE_ID so the runner's own task row is created under
|
|
65
|
+
* this id (see handleExecute's `selfTaskId` derivation below) — it doubles as
|
|
66
|
+
* both this task's row id and the root of any further delegation it spawns.
|
|
67
|
+
*
|
|
68
|
+
* stdout contract (script-parseable): task-id only, on the first line.
|
|
69
|
+
* Everything else goes to stderr.
|
|
70
|
+
*/
|
|
71
|
+
function runDetached(filteredArgs) {
|
|
72
|
+
const taskId = (0, sdk_1.generateId)('tsk');
|
|
73
|
+
const logDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx', 'logs');
|
|
74
|
+
if (!(0, fs_1.existsSync)(logDir))
|
|
75
|
+
(0, fs_1.mkdirSync)(logDir, { recursive: true });
|
|
76
|
+
const logPath = (0, path_1.join)(logDir, `${taskId}.log`);
|
|
77
|
+
const logFd = (0, fs_1.openSync)(logPath, 'a');
|
|
78
|
+
const entry = process.argv[1];
|
|
79
|
+
const child = (0, child_process_1.spawn)(process.execPath, [entry, 'x', ...filteredArgs], {
|
|
80
|
+
detached: true,
|
|
81
|
+
stdio: ['ignore', logFd, logFd],
|
|
82
|
+
env: { ...process.env, CREWX_TRACE_ID: taskId },
|
|
83
|
+
});
|
|
84
|
+
(0, fs_1.closeSync)(logFd);
|
|
85
|
+
child.on('error', (err) => {
|
|
86
|
+
process.stderr.write(`Failed to spawn detached runner: ${err.message}\n`);
|
|
87
|
+
});
|
|
88
|
+
child.unref();
|
|
89
|
+
console.log(taskId);
|
|
90
|
+
process.stderr.write(`Detached task ${taskId} started (log: ${logPath}).\n`);
|
|
91
|
+
process.stderr.write(`Use \`crewx result ${taskId} --wait=N\` to wait for completion.\n`);
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
30
94
|
/**
|
|
31
95
|
* Handle `crewx execute <agentRef> <message>` command.
|
|
32
96
|
*
|
|
@@ -34,7 +98,26 @@ const inherited_trace_1 = require("../utils/inherited-trace");
|
|
|
34
98
|
* --verbose: debug info written to stderr, response to stdout.
|
|
35
99
|
*/
|
|
36
100
|
async function handleExecute(args) {
|
|
37
|
-
const {
|
|
101
|
+
const { detach, rest: detachFilteredArgs } = extractDetachFlag(args);
|
|
102
|
+
if (detach) {
|
|
103
|
+
// Recursive-spawn guard: a CREWX_TRACE_ID already present means this
|
|
104
|
+
// process is itself running inside a traced context (either the
|
|
105
|
+
// respawned runner, or a delegated sub-call) — never chain a second
|
|
106
|
+
// detach off of it. Silently fall through to normal (synchronous) execution.
|
|
107
|
+
if (process.env['CREWX_TRACE_ID']) {
|
|
108
|
+
process.stderr.write('Note: --detach ignored (already running inside a traced context; CREWX_TRACE_ID is set).\n');
|
|
109
|
+
}
|
|
110
|
+
else if (process.platform === 'win32') {
|
|
111
|
+
console.error('Error: --detach is not supported on win32.');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
runDetached(detachFilteredArgs);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = (0, parse_common_flags_1.parseCommonFlags)(detachFilteredArgs);
|
|
38
121
|
const { agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest);
|
|
39
122
|
// No @mention → default to @crewx agent (matches cli-bak behaviour)
|
|
40
123
|
const agentRef = parsedAgentRef || '@crewx';
|
|
@@ -55,6 +138,7 @@ async function handleExecute(args) {
|
|
|
55
138
|
console.error('Options:');
|
|
56
139
|
console.error(' --thread <name> Conversation thread name');
|
|
57
140
|
console.error(' --provider <cli/xxx> Provider override');
|
|
141
|
+
console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
|
|
58
142
|
console.error(' --metadata <json> Extra metadata (JSON object, double-quoted).');
|
|
59
143
|
console.error(' Propagated to events/hooks/tracing.');
|
|
60
144
|
console.error(' Invalid JSON aborts with exit code 2.');
|
|
@@ -62,9 +146,11 @@ async function handleExecute(args) {
|
|
|
62
146
|
console.error(' --verbose Debug output mode');
|
|
63
147
|
console.error(' --config/-c <path> Config file path');
|
|
64
148
|
console.error(' --output-format <fmt> Output format (json|text|stream-json)');
|
|
149
|
+
console.error(' --out/-o <path> Save result to file (stdout suppressed)');
|
|
65
150
|
console.error(' --effort <level> Model effort (high|medium|low)');
|
|
66
151
|
console.error(' -f/--prompt-file <path> Read task body from file');
|
|
67
152
|
console.error(' --var key=value Template variable (repeatable)');
|
|
153
|
+
console.error(' --overdrive Activate overdrive (boost) profile for this request');
|
|
68
154
|
process.exit(1);
|
|
69
155
|
}
|
|
70
156
|
const configPath = config ?? process.env.CREWX_CONFIG ?? 'crewx.yaml';
|
|
@@ -79,10 +165,14 @@ async function handleExecute(args) {
|
|
|
79
165
|
process.stderr.write(`🔗 Thread: ${thread}\n`);
|
|
80
166
|
if (provider)
|
|
81
167
|
process.stderr.write(`🔌 Provider: ${provider}\n`);
|
|
168
|
+
if (model)
|
|
169
|
+
process.stderr.write(`🧠 Model: ${model}\n`);
|
|
82
170
|
if (outputFormat)
|
|
83
171
|
process.stderr.write(`📄 Output-format: ${outputFormat}\n`);
|
|
84
172
|
if (effort)
|
|
85
173
|
process.stderr.write(`⚡ Effort: ${effort}\n`);
|
|
174
|
+
if (overdrive)
|
|
175
|
+
process.stderr.write(`🚀 Overdrive: ON\n`);
|
|
86
176
|
process.stderr.write('─'.repeat(60) + '\n');
|
|
87
177
|
}
|
|
88
178
|
let parsedMetadata = {};
|
|
@@ -94,19 +184,32 @@ async function handleExecute(args) {
|
|
|
94
184
|
process.stderr.write(`Error: ${msg}\n`);
|
|
95
185
|
process.exit(2);
|
|
96
186
|
}
|
|
187
|
+
const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
|
|
188
|
+
// A trace with a rootTraceId but no parentTaskId means the id was pre-assigned
|
|
189
|
+
// to *this* task itself (the detach runner's parent injects only CREWX_TRACE_ID,
|
|
190
|
+
// never CREWX_PARENT_TASK_ID — see execute.ts's runDetached), not inherited from
|
|
191
|
+
// an ancestor task in a delegation chain (which always carries both). It doubles
|
|
192
|
+
// as this task's own row id so `crewx result <task-id>` can find it.
|
|
193
|
+
const selfTaskId = inheritedTrace && !inheritedTrace.parentTaskId
|
|
194
|
+
? (inheritedTrace.rootTraceId || undefined)
|
|
195
|
+
: undefined;
|
|
97
196
|
let exitCode = 0;
|
|
98
197
|
try {
|
|
99
198
|
const result = await crewx.execute(agentRef, finalMessage, {
|
|
100
199
|
provider,
|
|
200
|
+
model,
|
|
101
201
|
effort: effort || undefined,
|
|
202
|
+
overdrive: overdrive || undefined,
|
|
102
203
|
threadId: thread,
|
|
204
|
+
taskId: selfTaskId,
|
|
103
205
|
metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
|
|
104
206
|
vars: Object.keys(vars).length > 0 ? vars : undefined,
|
|
105
|
-
trace:
|
|
207
|
+
trace: inheritedTrace,
|
|
106
208
|
});
|
|
107
209
|
if (!result.ok) {
|
|
108
210
|
const errMsg = result.error?.message ?? 'Execute failed';
|
|
109
211
|
console.error(errMsg);
|
|
212
|
+
(0, write_output_1.appendError)(out, errMsg);
|
|
110
213
|
exitCode = 1;
|
|
111
214
|
}
|
|
112
215
|
else {
|
|
@@ -119,7 +222,7 @@ async function handleExecute(args) {
|
|
|
119
222
|
process.stderr.write('\n📄 Response:\n');
|
|
120
223
|
process.stderr.write('─'.repeat(40) + '\n');
|
|
121
224
|
}
|
|
122
|
-
|
|
225
|
+
(0, write_output_1.writeResult)(out, result.data);
|
|
123
226
|
if (verbose) {
|
|
124
227
|
process.stderr.write('\n✅ Execute completed successfully\n');
|
|
125
228
|
}
|
|
@@ -128,6 +231,7 @@ async function handleExecute(args) {
|
|
|
128
231
|
catch (err) {
|
|
129
232
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
130
233
|
console.error(`Error: ${errMsg}`);
|
|
234
|
+
(0, write_output_1.appendError)(out, `Error: ${errMsg}`);
|
|
131
235
|
exitCode = 1;
|
|
132
236
|
}
|
|
133
237
|
finally {
|
package/dist/commands/init.js
CHANGED
|
@@ -52,6 +52,7 @@ const git = __importStar(require("isomorphic-git"));
|
|
|
52
52
|
const nodeFs = __importStar(require("fs"));
|
|
53
53
|
const os_1 = __importDefault(require("os"));
|
|
54
54
|
const repository_1 = require("@crewx/sdk/repository");
|
|
55
|
+
const sdk_1 = require("@crewx/sdk");
|
|
55
56
|
const install_1 = require("./hook/install");
|
|
56
57
|
const STATUSLINE_SCRIPT_NAME = 'claude-usage-statusline.js';
|
|
57
58
|
const STATUSLINE_SCRIPT_MARKER = 'CrewX claude-usage-statusline';
|
|
@@ -84,6 +85,11 @@ const CREWX_MARKER = '# CrewX runtime';
|
|
|
84
85
|
const CREWX_GITIGNORE = `# CrewX runtime
|
|
85
86
|
.crewx/
|
|
86
87
|
|
|
88
|
+
# Secrets (workspace .env — see docs/manual)
|
|
89
|
+
.env
|
|
90
|
+
.env.*
|
|
91
|
+
!.env.example
|
|
92
|
+
|
|
87
93
|
# Memory runtime state (regenerable from entries/)
|
|
88
94
|
memory/*/.dirty-summary
|
|
89
95
|
memory/*/graph.json
|
|
@@ -435,7 +441,7 @@ async function handleInit(opts) {
|
|
|
435
441
|
}
|
|
436
442
|
}
|
|
437
443
|
// 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']) {
|
|
444
|
+
for (const dir of ['.crewx/logs', '.claude/commands', 'docs/goal', 'docs/daily', 'docs/wi', 'workflows']) {
|
|
439
445
|
try {
|
|
440
446
|
(0, fs_1.mkdirSync)((0, path_1.join)(target, dir), { recursive: true });
|
|
441
447
|
}
|
|
@@ -456,6 +462,21 @@ async function handleInit(opts) {
|
|
|
456
462
|
console.log(`✅ ${t.dir}/ ${action} (${t.file})`);
|
|
457
463
|
}
|
|
458
464
|
}
|
|
465
|
+
try {
|
|
466
|
+
const workflowTemplatesDir = (0, sdk_1.resolveWorkflowTemplatesPath)();
|
|
467
|
+
for (const filename of [sdk_1.WI_DEFAULT_FLOW_FILENAME, sdk_1.WI_PLAN_FLOW_FILENAME]) {
|
|
468
|
+
const sourcePath = (0, path_1.join)(workflowTemplatesDir, filename);
|
|
469
|
+
const targetPath = (0, path_1.join)(target, 'workflows', filename);
|
|
470
|
+
if (force || !(0, fs_1.existsSync)(targetPath)) {
|
|
471
|
+
const action = (0, fs_1.existsSync)(targetPath) ? 'updated' : 'created';
|
|
472
|
+
(0, fs_1.copyFileSync)(sourcePath, targetPath);
|
|
473
|
+
console.log(`✅ workflows/ ${action} (${filename})`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
catch (e) {
|
|
478
|
+
errors.push(`WORKFLOW_TEMPLATE_FAILED:${e.message}`);
|
|
479
|
+
}
|
|
459
480
|
// Always register workspace in ~/.crewx/crewx.db (best-effort, idempotent)
|
|
460
481
|
let workspaceId;
|
|
461
482
|
let slug;
|
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,8 +2,8 @@
|
|
|
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,
|
|
6
|
-
* --output-format, --effort, --prompt-file/-f.
|
|
5
|
+
* Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
|
|
6
|
+
* --output-format, --effort, --prompt-file/-f, --overdrive.
|
|
7
7
|
*
|
|
8
8
|
* Strict mode: unknown --xxx tokens after known flags are consumed throw an
|
|
9
9
|
* error instead of silently leaking into the message prompt.
|
|
@@ -14,6 +14,8 @@ export interface CommonFlags {
|
|
|
14
14
|
thread?: string;
|
|
15
15
|
/** Provider override (e.g., cli/claude). */
|
|
16
16
|
provider?: string;
|
|
17
|
+
/** Model override (e.g., claude-sonnet-5). */
|
|
18
|
+
model?: string;
|
|
17
19
|
/** Raw metadata JSON string. */
|
|
18
20
|
metadata?: string;
|
|
19
21
|
/** Enable verbose/debug output mode. */
|
|
@@ -26,6 +28,10 @@ export interface CommonFlags {
|
|
|
26
28
|
effort?: string;
|
|
27
29
|
/** Path to a file whose content is used as the prompt body (-f/--prompt-file). */
|
|
28
30
|
promptFile?: string;
|
|
31
|
+
/** Whether overdrive (boost) is active for this request. */
|
|
32
|
+
overdrive: boolean;
|
|
33
|
+
/** Output file path for saving result (--out/-o). */
|
|
34
|
+
out?: string;
|
|
29
35
|
/** Template variables from --var key=value flags. */
|
|
30
36
|
vars: Record<string, string>;
|
|
31
37
|
/** Remaining non-flag positional arguments. */
|
|
@@ -3,8 +3,8 @@
|
|
|
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,
|
|
7
|
-
* --output-format, --effort, --prompt-file/-f.
|
|
6
|
+
* Handles: --thread, --provider, --model, --metadata, --verbose, --config/-c,
|
|
7
|
+
* --output-format, --effort, --prompt-file/-f, --overdrive.
|
|
8
8
|
*
|
|
9
9
|
* Strict mode: unknown --xxx tokens after known flags are consumed throw an
|
|
10
10
|
* error instead of silently leaking into the message prompt.
|
|
@@ -63,22 +63,27 @@ exports.UnknownOptionError = UnknownOptionError;
|
|
|
63
63
|
function parseCommonFlags(args) {
|
|
64
64
|
const thread = parseFlag(args, '--thread');
|
|
65
65
|
const provider = parseFlag(args, '--provider');
|
|
66
|
+
const model = parseFlag(args, '--model');
|
|
66
67
|
const metadata = parseFlag(args, '--metadata');
|
|
67
68
|
const config = parseFlag(args, '--config', '-c');
|
|
68
69
|
const outputFormat = parseFlag(args, '--output-format');
|
|
69
70
|
const effort = parseFlag(args, '--effort');
|
|
70
71
|
const promptFile = parseFlag(args, '--prompt-file', '-f');
|
|
72
|
+
const out = parseFlag(args, '--out', '-o');
|
|
71
73
|
const verbose = hasFlag(args, '--verbose');
|
|
74
|
+
const overdrive = hasFlag(args, '--overdrive');
|
|
72
75
|
// Collect consumed positions for known flags
|
|
73
76
|
const consumed = new Set();
|
|
74
77
|
const flagPairs = [
|
|
75
78
|
{ names: ['--thread'] },
|
|
76
79
|
{ names: ['--provider'] },
|
|
80
|
+
{ names: ['--model'] },
|
|
77
81
|
{ names: ['--metadata'] },
|
|
78
82
|
{ names: ['--config', '-c'] },
|
|
79
83
|
{ names: ['--output-format'] },
|
|
80
84
|
{ names: ['--effort'] },
|
|
81
85
|
{ names: ['--prompt-file', '-f'] },
|
|
86
|
+
{ names: ['--out', '-o'] },
|
|
82
87
|
];
|
|
83
88
|
// Parse --var key=value flags (multiple allowed; last value wins on duplicate keys)
|
|
84
89
|
const vars = {};
|
|
@@ -88,6 +93,10 @@ function parseCommonFlags(args) {
|
|
|
88
93
|
consumed.add(i);
|
|
89
94
|
continue;
|
|
90
95
|
}
|
|
96
|
+
if (arg === '--overdrive') {
|
|
97
|
+
consumed.add(i);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
91
100
|
// --var=key=value or --var key=value
|
|
92
101
|
if (arg.startsWith('--var=') || arg === '--var') {
|
|
93
102
|
let kv;
|
|
@@ -148,7 +157,7 @@ function parseCommonFlags(args) {
|
|
|
148
157
|
}
|
|
149
158
|
rest.push(token);
|
|
150
159
|
}
|
|
151
|
-
return { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, vars, rest };
|
|
160
|
+
return { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest };
|
|
152
161
|
}
|
|
153
162
|
/**
|
|
154
163
|
* Parse metadata JSON string from --metadata flag.
|