@crewx/cli 0.9.0-rc.10 → 0.9.0-rc.100

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.
Files changed (56) hide show
  1. package/dist/bootstrap/codex-writable-roots.d.ts +13 -0
  2. package/dist/bootstrap/codex-writable-roots.js +25 -0
  3. package/dist/bootstrap/crewx-cli.js +7 -2
  4. package/dist/builtin.js +1 -0
  5. package/dist/commands/agent.js +0 -58
  6. package/dist/commands/cal.d.ts +15 -0
  7. package/dist/commands/cal.js +44 -0
  8. package/dist/commands/db.d.ts +2 -0
  9. package/dist/commands/db.js +381 -1
  10. package/dist/commands/detached.d.ts +65 -0
  11. package/dist/commands/detached.js +507 -0
  12. package/dist/commands/doctor.d.ts +53 -0
  13. package/dist/commands/doctor.js +391 -21
  14. package/dist/commands/emit-trailer.d.ts +25 -0
  15. package/dist/commands/emit-trailer.js +33 -0
  16. package/dist/commands/execute.d.ts +7 -4
  17. package/dist/commands/execute.js +118 -17
  18. package/dist/commands/hook/command-marker.d.ts +2 -0
  19. package/dist/commands/hook/command-marker.js +5 -0
  20. package/dist/commands/hook/install.d.ts +0 -1
  21. package/dist/commands/hook/install.js +60 -63
  22. package/dist/commands/hook/status.js +3 -3
  23. package/dist/commands/hook/uninstall.js +2 -2
  24. package/dist/commands/init.js +22 -1
  25. package/dist/commands/kill.d.ts +2 -8
  26. package/dist/commands/kill.js +6 -47
  27. package/dist/commands/log.js +4 -3
  28. package/dist/commands/parse-common-flags.d.ts +5 -1
  29. package/dist/commands/parse-common-flags.js +6 -2
  30. package/dist/commands/ps.d.ts +2 -2
  31. package/dist/commands/ps.js +25 -15
  32. package/dist/commands/publish.d.ts +1 -0
  33. package/dist/commands/publish.js +303 -0
  34. package/dist/commands/query.d.ts +5 -1
  35. package/dist/commands/query.js +110 -11
  36. package/dist/commands/registry.js +4 -2
  37. package/dist/commands/result.d.ts +8 -3
  38. package/dist/commands/result.js +139 -7
  39. package/dist/commands/shortcut.d.ts +1 -0
  40. package/dist/commands/shortcut.js +267 -0
  41. package/dist/commands/slack.js +2 -1
  42. package/dist/commands/stop.d.ts +8 -0
  43. package/dist/commands/stop.js +119 -0
  44. package/dist/commands/write-output.d.ts +3 -0
  45. package/dist/commands/write-output.js +24 -0
  46. package/dist/logging.d.ts +1 -1
  47. package/dist/logging.js +3 -2
  48. package/dist/main.d.ts +3 -2
  49. package/dist/main.js +66 -16
  50. package/dist/utils/env-defaults.d.ts +2 -5
  51. package/dist/utils/env-defaults.js +10 -5
  52. package/dist/utils/inherited-trace.d.ts +24 -0
  53. package/dist/utils/inherited-trace.js +40 -0
  54. package/dist/utils/sdk-compat.d.ts +24 -0
  55. package/dist/utils/sdk-compat.js +120 -0
  56. package/package.json +14 -11
@@ -6,40 +6,85 @@
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
- * e.g. --metadata='{"workflow_id":"wf-1"}'
11
11
  * --verbose Debug output mode (default: raw agent response only)
12
12
  * --config/-c <path> Config file path override
13
13
  * --output-format <fmt> Output format (json|text|stream-json)
14
14
  * --effort <level> Model effort (high|medium|low)
15
- * -f/--prompt-file <path> Read task body from file (bypasses cmd.exe argv truncation)
15
+ * -f/--prompt-file <path> Read task body from file
16
+ * --detach/--async Persist a receipt and launch a detached runner
17
+ * --wait Force synchronous execution
16
18
  *
17
19
  * Stdin support:
18
20
  * Pipe or redirect content into crewx x to supply the task body via stdin.
19
- * e.g. cat task.md | crewx x "@agent label"
20
21
  * Stdin is ignored when running in an interactive TTY.
21
22
  */
22
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.runDetachedMiddle = void 0;
23
25
  exports.handleExecute = handleExecute;
24
26
  const sdk_1 = require("@crewx/sdk");
27
+ const repository_1 = require("@crewx/sdk/repository");
25
28
  const parse_agent_message_1 = require("./parse-agent-message");
26
29
  const parse_common_flags_1 = require("./parse-common-flags");
27
30
  const resolve_prompt_1 = require("./resolve-prompt");
28
31
  const crewx_cli_1 = require("../bootstrap/crewx-cli");
29
32
  const inherited_trace_1 = require("../utils/inherited-trace");
33
+ const write_output_1 = require("./write-output");
34
+ const detached_1 = require("./detached");
35
+ const emit_trailer_1 = require("./emit-trailer");
36
+ // Exported for platform-focused tests; the middle hop remains an internal CLI
37
+ // contract and is not routed through the public command registry.
38
+ var detached_2 = require("./detached");
39
+ Object.defineProperty(exports, "runDetachedMiddle", { enumerable: true, get: function () { return detached_2.runDetachedMiddle; } });
30
40
  /**
31
41
  * Handle `crewx execute <agentRef> <message>` command.
32
42
  *
33
43
  * Default output: raw agent response only (stdout).
34
44
  * --verbose: debug info written to stderr, response to stdout.
35
45
  */
36
- async function handleExecute(args) {
37
- const { thread, provider, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, rest } = (0, parse_common_flags_1.parseCommonFlags)(args);
38
- const { agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest);
39
- // No @mention → default to @crewx agent (matches cli-bak behaviour)
46
+ async function handleExecute(args, command = 'execute', emitState = (0, emit_trailer_1.createDelegationEmitState)()) {
47
+ // The private middle-hop marker is consumed before public flag parsing. An
48
+ // invalid direct use remains an unknown option and is rejected normally.
49
+ const middleHop = (0, detached_1.readDetachedMiddleHop)(args);
50
+ if (middleHop) {
51
+ await (0, detached_1.runDetachedMiddle)(command, middleHop);
52
+ return;
53
+ }
54
+ const receiptFlags = (0, detached_1.extractReceiptFlags)(args);
55
+ const receiptMode = (0, detached_1.resolveReceiptMode)({
56
+ detach: receiptFlags.detach,
57
+ wait: receiptFlags.wait,
58
+ detachedRunner: (0, inherited_trace_1.isDetachedRunner)(),
59
+ agentContext: Boolean(process.env['CREWX_AGENT_ID']),
60
+ });
61
+ if (receiptMode.receipt) {
62
+ await (0, detached_1.runDetached)(command, receiptFlags.rest, receiptMode.reason);
63
+ return;
64
+ }
65
+ let parsedFlags;
66
+ try {
67
+ parsedFlags = (0, parse_common_flags_1.parseCommonFlags)(receiptFlags.rest);
68
+ }
69
+ catch (err) {
70
+ (0, emit_trailer_1.emitDelegationResult)({ command, isError: true, state: emitState });
71
+ throw err;
72
+ }
73
+ const { thread, provider, model, metadata, verbose, config, outputFormat, effort, promptFile, overdrive, vars, out, rest } = parsedFlags;
74
+ const inheritedTrace = (0, inherited_trace_1.readInheritedTrace)();
75
+ let parsedAgentRef;
76
+ let message;
77
+ let finalMessage;
78
+ try {
79
+ ({ agentRef: parsedAgentRef, message } = (0, parse_agent_message_1.parseAgentMessage)(rest));
80
+ // Resolve final prompt: argv | stdin pipe | --prompt-file (or combination)
81
+ finalMessage = await (0, resolve_prompt_1.resolvePrompt)(message, promptFile);
82
+ }
83
+ catch (err) {
84
+ (0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
85
+ throw err;
86
+ }
40
87
  const agentRef = parsedAgentRef || '@crewx';
41
- // Resolve final prompt: argv | stdin pipe | --prompt-file (or combination)
42
- const finalMessage = await (0, resolve_prompt_1.resolvePrompt)(message, promptFile);
43
88
  if (!finalMessage) {
44
89
  console.error('Usage: crewx execute [@agent] <task> [options]');
45
90
  console.error(' crewx x [@agent] <task> [options]');
@@ -55,6 +100,7 @@ async function handleExecute(args) {
55
100
  console.error('Options:');
56
101
  console.error(' --thread <name> Conversation thread name');
57
102
  console.error(' --provider <cli/xxx> Provider override');
103
+ console.error(' --model <name> Model override (e.g. claude-sonnet-5)');
58
104
  console.error(' --metadata <json> Extra metadata (JSON object, double-quoted).');
59
105
  console.error(' Propagated to events/hooks/tracing.');
60
106
  console.error(' Invalid JSON aborts with exit code 2.');
@@ -62,30 +108,43 @@ async function handleExecute(args) {
62
108
  console.error(' --verbose Debug output mode');
63
109
  console.error(' --config/-c <path> Config file path');
64
110
  console.error(' --output-format <fmt> Output format (json|text|stream-json)');
111
+ console.error(' --out/-o <path> Save result to file (stdout suppressed)');
65
112
  console.error(' --effort <level> Model effort (high|medium|low)');
66
113
  console.error(' -f/--prompt-file <path> Read task body from file');
67
114
  console.error(' --var key=value Template variable (repeatable)');
68
115
  console.error(' --overdrive Activate overdrive (boost) profile for this request');
116
+ (0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
69
117
  process.exit(1);
118
+ return;
70
119
  }
71
120
  const configPath = config ?? process.env.CREWX_CONFIG ?? 'crewx.yaml';
72
121
  // Only show exec audit span JSON in verbose mode
73
122
  (0, sdk_1.setAuditVerbose)(verbose);
74
- const crewx = await (0, crewx_cli_1.createCliCrewx)(configPath);
123
+ let crewx;
124
+ try {
125
+ crewx = await (0, crewx_cli_1.createCliCrewx)(configPath);
126
+ }
127
+ catch (err) {
128
+ (0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
129
+ throw err;
130
+ }
75
131
  // file:// remote agent delegation is handled transparently inside Crewx.query/execute.
76
132
  if (verbose) {
133
+ process.stderr.write(`mode=sync reason=${receiptMode.reason}\n`);
77
134
  process.stderr.write(`📋 Task: ${finalMessage}\n`);
78
135
  process.stderr.write(`🤖 Agent: ${agentRef}\n`);
79
136
  if (thread)
80
137
  process.stderr.write(`🔗 Thread: ${thread}\n`);
81
138
  if (provider)
82
139
  process.stderr.write(`🔌 Provider: ${provider}\n`);
140
+ if (model)
141
+ process.stderr.write(`🧠 Model: ${model}\n`);
83
142
  if (outputFormat)
84
143
  process.stderr.write(`📄 Output-format: ${outputFormat}\n`);
85
144
  if (effort)
86
145
  process.stderr.write(`⚡ Effort: ${effort}\n`);
87
146
  if (overdrive)
88
- process.stderr.write(`🚀 Overdrive: ON\n`);
147
+ process.stderr.write('🚀 Overdrive: ON\n');
89
148
  process.stderr.write('─'.repeat(60) + '\n');
90
149
  }
91
150
  let parsedMetadata = {};
@@ -95,22 +154,43 @@ async function handleExecute(args) {
95
154
  catch (err) {
96
155
  const msg = err instanceof Error ? err.message : String(err);
97
156
  process.stderr.write(`Error: ${msg}\n`);
157
+ (0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
98
158
  process.exit(2);
159
+ return;
160
+ }
161
+ // Only the detached runner may adopt a pre-issued task row. Trace variables
162
+ // describe the caller chain and are never used as this task's identity.
163
+ const detachedRunner = (0, inherited_trace_1.isDetachedRunner)();
164
+ const assignedTaskId = (0, inherited_trace_1.readRunnerAssignment)();
165
+ let selfTaskId;
166
+ if (assignedTaskId !== undefined) {
167
+ const adoption = (0, detached_1.adoptAssignedTask)(new repository_1.TaskRepository(), assignedTaskId, detachedRunner);
168
+ if (adoption.kind === 'failed') {
169
+ (0, emit_trailer_1.emitDelegationResult)({ command, trace: inheritedTrace, isError: true, state: emitState });
170
+ process.exit(1);
171
+ return;
172
+ }
173
+ if (adoption.kind === 'adopted')
174
+ selfTaskId = adoption.taskId;
99
175
  }
100
176
  let exitCode = 0;
177
+ let result;
101
178
  try {
102
- const result = await crewx.execute(agentRef, finalMessage, {
179
+ result = await crewx.execute(agentRef, finalMessage, {
103
180
  provider,
181
+ model,
104
182
  effort: effort || undefined,
105
183
  overdrive: overdrive || undefined,
106
184
  threadId: thread,
185
+ taskId: selfTaskId,
107
186
  metadata: Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined,
108
187
  vars: Object.keys(vars).length > 0 ? vars : undefined,
109
- trace: (0, inherited_trace_1.readInheritedTrace)(),
188
+ trace: inheritedTrace,
110
189
  });
111
190
  if (!result.ok) {
112
191
  const errMsg = result.error?.message ?? 'Execute failed';
113
192
  console.error(errMsg);
193
+ (0, write_output_1.appendError)(out, errMsg);
114
194
  exitCode = 1;
115
195
  }
116
196
  else {
@@ -123,20 +203,41 @@ async function handleExecute(args) {
123
203
  process.stderr.write('\n📄 Response:\n');
124
204
  process.stderr.write('─'.repeat(40) + '\n');
125
205
  }
126
- console.log(result.data);
127
- if (verbose) {
206
+ (0, write_output_1.writeResult)(out, result.data);
207
+ if (verbose)
128
208
  process.stderr.write('\n✅ Execute completed successfully\n');
129
- }
130
209
  }
131
210
  }
132
211
  catch (err) {
133
212
  const errMsg = err instanceof Error ? err.message : String(err);
134
213
  console.error(`Error: ${errMsg}`);
214
+ (0, write_output_1.appendError)(out, `Error: ${errMsg}`);
135
215
  exitCode = 1;
136
216
  }
137
217
  finally {
138
- await crewx.close();
218
+ try {
219
+ await crewx.close();
220
+ }
221
+ catch (err) {
222
+ (0, emit_trailer_1.emitDelegationResult)({
223
+ command,
224
+ trace: inheritedTrace,
225
+ taskId: result?.meta.taskId,
226
+ agentId: result?.meta.agentId,
227
+ isError: true,
228
+ state: emitState,
229
+ });
230
+ throw err;
231
+ }
139
232
  }
233
+ (0, emit_trailer_1.emitDelegationResult)({
234
+ command,
235
+ trace: inheritedTrace,
236
+ taskId: result?.meta.taskId,
237
+ agentId: result?.meta.agentId,
238
+ isError: exitCode !== 0 || result?.ok === false,
239
+ state: emitState,
240
+ });
140
241
  if (exitCode !== 0)
141
242
  process.exit(exitCode);
142
243
  }
@@ -0,0 +1,2 @@
1
+ /** Match only commands that invoke CrewX's hook-dispatch subcommand. */
2
+ export declare const CREWX_HOOK_COMMAND_RE: RegExp;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CREWX_HOOK_COMMAND_RE = void 0;
4
+ /** Match only commands that invoke CrewX's hook-dispatch subcommand. */
5
+ exports.CREWX_HOOK_COMMAND_RE = /crewx(?:\.js|\.cmd|\.exe)?['"]?\s+hook-dispatch\b/i;
@@ -10,7 +10,6 @@
10
10
  * - Never traverses parent directories — project root determined by crewx.yaml
11
11
  */
12
12
  import { type HookProvider } from './paths';
13
- export declare const CREWX_HOOK_COMMAND_MARKER = "crewx hook-dispatch";
14
13
  export declare function resolveCrewxBinary(): string;
15
14
  export interface HookInstallOpts {
16
15
  projectRoot: string;
@@ -10,49 +10,14 @@
10
10
  * - Preserves existing user hooks
11
11
  * - Never traverses parent directories — project root determined by crewx.yaml
12
12
  */
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || (function () {
30
- var ownKeys = function(o) {
31
- ownKeys = Object.getOwnPropertyNames || function (o) {
32
- var ar = [];
33
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
- return ar;
35
- };
36
- return ownKeys(o);
37
- };
38
- return function (mod) {
39
- if (mod && mod.__esModule) return mod;
40
- var result = {};
41
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
- __setModuleDefault(result, mod);
43
- return result;
44
- };
45
- })();
46
13
  Object.defineProperty(exports, "__esModule", { value: true });
47
- exports.CREWX_HOOK_COMMAND_MARKER = void 0;
48
14
  exports.resolveCrewxBinary = resolveCrewxBinary;
49
15
  exports.handleHookInstall = handleHookInstall;
50
16
  const fs_1 = require("fs");
51
- const path_1 = require("path");
52
- const cp = __importStar(require("child_process"));
17
+ const sdk_1 = require("@crewx/sdk");
53
18
  const paths_1 = require("./paths");
54
- exports.CREWX_HOOK_COMMAND_MARKER = 'crewx hook-dispatch';
55
- function getProviderConfigs(projectRoot, providers, crewxBin) {
19
+ const command_marker_1 = require("./command-marker");
20
+ function getProviderConfigs(projectRoot, providers) {
56
21
  return providers.map((provider) => ({
57
22
  settingsPath: provider === 'claude'
58
23
  ? (0, paths_1.getClaudeSettingsPath)(projectRoot)
@@ -63,24 +28,13 @@ function getProviderConfigs(projectRoot, providers, crewxBin) {
63
28
  }));
64
29
  }
65
30
  function resolveCrewxBinary() {
66
- if (process.env.CREWX_CLI)
67
- return process.env.CREWX_CLI;
68
- try {
69
- const which = cp.execSync('which crewx 2>/dev/null', { encoding: 'utf8' }).trim();
70
- const isTmpProxy = which.includes('/T/crewx-proxy-') ||
71
- which.includes('/tmp/crewx-proxy-') ||
72
- /\/[Tt]e?mp\//.test(which);
73
- if (which && !isTmpProxy)
74
- return which;
31
+ const resolution = (0, sdk_1.resolveCrewxExecutable)();
32
+ if (!resolution.ok) {
33
+ throw new Error((0, sdk_1.formatCrewxExecutableFailure)(resolution));
75
34
  }
76
- catch { }
77
- if (process.argv[1]) {
78
- const scriptPath = (0, path_1.resolve)(process.argv[1]);
79
- if ((0, fs_1.existsSync)(scriptPath)) {
80
- return `${process.execPath} ${scriptPath}`;
81
- }
82
- }
83
- return 'crewx';
35
+ const stableEntrypoint = (0, sdk_1.materializeCrewxStableEntrypoint)(resolution);
36
+ const useStable = stableEntrypoint && resolution.argv.some(sdk_1.isRotatingInstallPath);
37
+ return (0, sdk_1.formatCrewxExecutableArgv)(useStable ? [stableEntrypoint] : resolution.argv);
84
38
  }
85
39
  function readSettingsTyped(settingsPath) {
86
40
  return (0, paths_1.readSettings)(settingsPath);
@@ -88,10 +42,19 @@ function readSettingsTyped(settingsPath) {
88
42
  function findCrewxEntry(preToolUse) {
89
43
  if (!preToolUse)
90
44
  return -1;
91
- return preToolUse.findIndex((entry) => entry.hooks?.some((h) => h.command?.includes(exports.CREWX_HOOK_COMMAND_MARKER)));
45
+ return preToolUse.findIndex((entry) => entry.hooks?.some((h) => command_marker_1.CREWX_HOOK_COMMAND_RE.test(h.command)));
46
+ }
47
+ function findCrewxHook(entry) {
48
+ if (!entry.hooks)
49
+ return undefined;
50
+ const index = entry.hooks.findIndex((hook) => command_marker_1.CREWX_HOOK_COMMAND_RE.test(hook.command));
51
+ if (index < 0)
52
+ return undefined;
53
+ return { index, command: entry.hooks[index].command };
92
54
  }
93
55
  function installForProvider(projectRoot, config, crewxBin, yes) {
94
56
  const { settingsPath, provider, matcher, commandArg } = config;
57
+ const command = `${crewxBin} hook-dispatch ${commandArg}`;
95
58
  const settings = readSettingsTyped(settingsPath);
96
59
  if (!settings.hooks)
97
60
  settings.hooks = {};
@@ -99,8 +62,28 @@ function installForProvider(projectRoot, config, crewxBin, yes) {
99
62
  settings.hooks.PreToolUse = [];
100
63
  const existingIdx = findCrewxEntry(settings.hooks.PreToolUse);
101
64
  if (existingIdx >= 0) {
102
- console.log(`[crewx] Hook already installed in ${settingsPath} (${provider})`);
103
- return false;
65
+ const existingEntry = settings.hooks.PreToolUse[existingIdx];
66
+ const existingHook = findCrewxHook(existingEntry);
67
+ if (existingHook?.command === command) {
68
+ console.log(`[crewx] Hook already installed in ${settingsPath} (${provider})`);
69
+ return false;
70
+ }
71
+ if (!yes) {
72
+ console.log(`[crewx] Existing CrewX hook needs an install-path refresh in ${settingsPath} (${provider})`);
73
+ return false;
74
+ }
75
+ if ((0, fs_1.existsSync)(settingsPath)) {
76
+ const backupPath = settingsPath + '.crewx-backup';
77
+ (0, fs_1.copyFileSync)(settingsPath, backupPath);
78
+ console.log(`[crewx] Backup created: ${backupPath}`);
79
+ }
80
+ if (existingHook) {
81
+ existingEntry.hooks[existingHook.index] = { ...existingEntry.hooks[existingHook.index], command };
82
+ }
83
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
84
+ console.log(`[crewx] Hook updated (${provider}): ${command}`);
85
+ console.log(`[crewx] Settings: ${settingsPath}`);
86
+ return true;
104
87
  }
105
88
  if (!yes) {
106
89
  console.log(`⚠️ crewx hook install will register crewx-hook-dispatch as a PreToolUse hook.\n` +
@@ -119,7 +102,6 @@ function installForProvider(projectRoot, config, crewxBin, yes) {
119
102
  else {
120
103
  (0, paths_1.ensureCodexHooks)(projectRoot);
121
104
  }
122
- const command = `${crewxBin} hook-dispatch ${commandArg}`;
123
105
  settings.hooks.PreToolUse.push({
124
106
  matcher,
125
107
  hooks: [{ type: 'command', command }],
@@ -133,8 +115,15 @@ async function handleHookInstall(argsOrOpts) {
133
115
  if (!Array.isArray(argsOrOpts)) {
134
116
  const { projectRoot, yes, provider } = argsOrOpts;
135
117
  const providers = (0, paths_1.providersFromFilter)(provider ?? 'all');
136
- const crewxBin = resolveCrewxBinary();
137
- const configs = getProviderConfigs(projectRoot, providers, crewxBin);
118
+ let crewxBin;
119
+ try {
120
+ crewxBin = resolveCrewxBinary();
121
+ }
122
+ catch (error) {
123
+ console.error(`[crewx] ${error instanceof Error ? error.message : String(error)}`);
124
+ return;
125
+ }
126
+ const configs = getProviderConfigs(projectRoot, providers);
138
127
  for (const config of configs) {
139
128
  installForProvider(projectRoot, config, crewxBin, yes);
140
129
  }
@@ -152,8 +141,16 @@ async function handleHookInstall(argsOrOpts) {
152
141
  }
153
142
  const providerFilter = (0, paths_1.parseProviderArg)(args);
154
143
  const providers = (0, paths_1.providersFromFilter)(providerFilter);
155
- const crewxBin = resolveCrewxBinary();
156
- const configs = getProviderConfigs(projectRoot, providers, crewxBin);
144
+ let crewxBin;
145
+ try {
146
+ crewxBin = resolveCrewxBinary();
147
+ }
148
+ catch (error) {
149
+ console.error(`[crewx] ${error instanceof Error ? error.message : String(error)}`);
150
+ process.exitCode = 1;
151
+ return;
152
+ }
153
+ const configs = getProviderConfigs(projectRoot, providers);
157
154
  if (!yes) {
158
155
  const targets = configs.map((c) => ` - ${c.provider}: ${c.settingsPath}`).join('\n');
159
156
  console.log(`⚠️ crewx hook install will register crewx-hook-dispatch as a PreToolUse hook.\n` +
@@ -11,7 +11,7 @@ const fs_1 = require("fs");
11
11
  const path_1 = require("path");
12
12
  const sdk_1 = require("@crewx/sdk");
13
13
  const paths_1 = require("./paths");
14
- const CREWX_HOOK_COMMAND_MARKER = 'crewx hook-dispatch';
14
+ const command_marker_1 = require("./command-marker");
15
15
  function showProviderStatus(projectRoot, provider) {
16
16
  const settingsPath = provider === 'claude'
17
17
  ? (0, paths_1.getClaudeSettingsPath)(projectRoot)
@@ -26,9 +26,9 @@ function showProviderStatus(projectRoot, provider) {
26
26
  try {
27
27
  const settings = JSON.parse((0, fs_1.readFileSync)(settingsPath, 'utf8'));
28
28
  const preHooks = settings.hooks?.PreToolUse ?? [];
29
- const crewxEntry = preHooks.find((entry) => entry.hooks?.some((h) => h.command?.includes(CREWX_HOOK_COMMAND_MARKER)));
29
+ const crewxEntry = preHooks.find((entry) => entry.hooks?.some((h) => command_marker_1.CREWX_HOOK_COMMAND_RE.test(h.command ?? '')));
30
30
  if (crewxEntry) {
31
- const command = crewxEntry.hooks.find((h) => h.command?.includes(CREWX_HOOK_COMMAND_MARKER))?.command;
31
+ const command = crewxEntry.hooks.find((h) => command_marker_1.CREWX_HOOK_COMMAND_RE.test(h.command ?? ''))?.command;
32
32
  console.log(` Status: INSTALLED`);
33
33
  console.log(` Command: ${command}`);
34
34
  }
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.handleHookUninstall = handleHookUninstall;
11
11
  const fs_1 = require("fs");
12
12
  const paths_1 = require("./paths");
13
- const CREWX_HOOK_COMMAND_MARKER = 'crewx hook-dispatch';
13
+ const command_marker_1 = require("./command-marker");
14
14
  function getSettingsPath(projectRoot, provider) {
15
15
  return provider === 'claude'
16
16
  ? (0, paths_1.getClaudeSettingsPath)(projectRoot)
@@ -35,7 +35,7 @@ function uninstallFromProvider(projectRoot, provider) {
35
35
  return;
36
36
  }
37
37
  const before = settings.hooks.PreToolUse.length;
38
- settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter((entry) => !entry.hooks?.some((h) => h.command?.includes(CREWX_HOOK_COMMAND_MARKER)));
38
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter((entry) => !entry.hooks?.some((h) => command_marker_1.CREWX_HOOK_COMMAND_RE.test(h.command)));
39
39
  const removed = settings.hooks.PreToolUse.length < before;
40
40
  if (settings.hooks.PreToolUse.length === 0) {
41
41
  delete settings.hooks.PreToolUse;
@@ -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;
@@ -1,9 +1,3 @@
1
- /**
2
- * crewx kill handler.
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>;
@@ -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
- const repository_1 = require("@crewx/sdk/repository");
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
- const killAll = args.includes('--all');
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
  }
@@ -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).toLocaleString()}`);
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).toLocaleString()} (${duration}ms)`);
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).toLocaleString()}`);
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: --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
@@ -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. */
@@ -28,6 +30,8 @@ export interface CommonFlags {
28
30
  promptFile?: string;
29
31
  /** Whether overdrive (boost) is active for this request. */
30
32
  overdrive: boolean;
33
+ /** Output file path for saving result (--out/-o). */
34
+ out?: string;
31
35
  /** Template variables from --var key=value flags. */
32
36
  vars: Record<string, string>;
33
37
  /** Remaining non-flag positional arguments. */