@crewx/cli 0.9.0-rc.7 → 0.9.0-rc.71

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 (37) hide show
  1. package/dist/bootstrap/codex-writable-roots.d.ts +58 -0
  2. package/dist/bootstrap/codex-writable-roots.js +113 -0
  3. package/dist/bootstrap/crewx-cli.js +3 -0
  4. package/dist/builtin.js +1 -0
  5. package/dist/commands/db.d.ts +1 -0
  6. package/dist/commands/db.js +191 -1
  7. package/dist/commands/doctor.d.ts +17 -0
  8. package/dist/commands/doctor.js +21 -11
  9. package/dist/commands/execute.d.ts +4 -0
  10. package/dist/commands/execute.js +103 -3
  11. package/dist/commands/init.js +22 -1
  12. package/dist/commands/log.js +4 -3
  13. package/dist/commands/parse-common-flags.d.ts +5 -1
  14. package/dist/commands/parse-common-flags.js +6 -2
  15. package/dist/commands/ps.js +53 -4
  16. package/dist/commands/publish.d.ts +1 -0
  17. package/dist/commands/publish.js +270 -0
  18. package/dist/commands/query.d.ts +1 -0
  19. package/dist/commands/query.js +11 -2
  20. package/dist/commands/registry.js +3 -1
  21. package/dist/commands/restart.js +20 -6
  22. package/dist/commands/result.d.ts +7 -3
  23. package/dist/commands/result.js +41 -6
  24. package/dist/commands/shortcut.d.ts +1 -0
  25. package/dist/commands/shortcut.js +267 -0
  26. package/dist/commands/slack.js +2 -1
  27. package/dist/commands/write-output.d.ts +3 -0
  28. package/dist/commands/write-output.js +24 -0
  29. package/dist/logging.d.ts +1 -1
  30. package/dist/logging.js +3 -2
  31. package/dist/main.d.ts +3 -2
  32. package/dist/main.js +49 -7
  33. package/dist/utils/env-defaults.d.ts +2 -5
  34. package/dist/utils/env-defaults.js +10 -5
  35. package/dist/utils/sdk-compat.d.ts +21 -0
  36. package/dist/utils/sdk-compat.js +72 -0
  37. package/package.json +13 -11
@@ -0,0 +1,58 @@
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` that skips Codex's git repository trust
38
+ * check for a resolved workspace.
39
+ *
40
+ * The workspace is resolved by the product layer, so an unavailable workspace
41
+ * must not fall back to the host cwd. The flag is independent of execution
42
+ * mode because it controls repository trust rather than filesystem access.
43
+ */
44
+ export declare function createCodexSkipGitRepoCheckProvider(workspaceRoot: string | undefined): AdditionalArgsProvider;
45
+ /**
46
+ * Compose product-layer argument providers while preserving their order.
47
+ */
48
+ export declare function composeAdditionalArgsProviders(...providers: AdditionalArgsProvider[]): AdditionalArgsProvider;
49
+ /**
50
+ * Create an `AdditionalArgsProvider` (SDK extension point, WI-20260703-001)
51
+ * that injects CrewX home as a Codex writable root for `workspace-write`
52
+ * equivalent modes (`agent`, `auto`, `undefined`).
53
+ *
54
+ * No-ops for:
55
+ * - Non-codex providers.
56
+ * - Modes in {@link NO_INJECT_MODES} (read-only/plan/agent-full-access/yolo/danger-full-access).
57
+ */
58
+ export declare function createCodexWritableRootsProvider(crewxHome?: string): AdditionalArgsProvider;
@@ -0,0 +1,113 @@
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.createCodexSkipGitRepoCheckProvider = createCodexSkipGitRepoCheckProvider;
24
+ exports.composeAdditionalArgsProviders = composeAdditionalArgsProviders;
25
+ exports.createCodexWritableRootsProvider = createCodexWritableRootsProvider;
26
+ const os_1 = require("os");
27
+ const path_1 = require("path");
28
+ /**
29
+ * crewx.yaml / query-option `mode` values for which Codex is NOT running in
30
+ * (or being pushed into) a `workspace-write`-equivalent sandbox. Injecting an
31
+ * extra writable root is meaningless (read-only/plan) or redundant
32
+ * (full-access variants already allow writes everywhere) in these modes.
33
+ */
34
+ const NO_INJECT_MODES = new Set([
35
+ 'read-only',
36
+ 'plan',
37
+ 'agent-full-access',
38
+ 'yolo',
39
+ 'danger-full-access',
40
+ ]);
41
+ /**
42
+ * Resolve CrewX home directory.
43
+ * Priority: `CREWX_HOME` env var → `~/.crewx`.
44
+ */
45
+ function resolveCrewxHome() {
46
+ return process.env.CREWX_HOME ?? (0, path_1.join)((0, os_1.homedir)(), '.crewx');
47
+ }
48
+ /**
49
+ * Escape a string for embedding inside a TOML basic string (`"..."`).
50
+ * Sufficient for filesystem paths: handles backslash (Windows paths),
51
+ * double-quote, and control characters that could otherwise break TOML
52
+ * parsing of the `-c key="value"` override.
53
+ */
54
+ function escapeTomlBasicString(value) {
55
+ return value
56
+ .replace(/\\/g, '\\\\')
57
+ .replace(/"/g, '\\"')
58
+ .replace(/\n/g, '\\n')
59
+ .replace(/\r/g, '\\r')
60
+ .replace(/\t/g, '\\t');
61
+ }
62
+ /**
63
+ * Build the `-c sandbox_workspace_write.writable_roots=["<path>"]` arg pair.
64
+ * Works for both `codex exec` and `codex exec resume` (config-override form).
65
+ */
66
+ function buildCodexWritableRootArgs(crewxHome) {
67
+ const escaped = escapeTomlBasicString(crewxHome);
68
+ return ['-c', `sandbox_workspace_write.writable_roots=["${escaped}"]`];
69
+ }
70
+ function isCodexProvider(ctx) {
71
+ return ctx.providerId === 'codex' || ctx.providerStr === 'cli/codex';
72
+ }
73
+ /**
74
+ * Create an `AdditionalArgsProvider` that skips Codex's git repository trust
75
+ * check for a resolved workspace.
76
+ *
77
+ * The workspace is resolved by the product layer, so an unavailable workspace
78
+ * must not fall back to the host cwd. The flag is independent of execution
79
+ * mode because it controls repository trust rather than filesystem access.
80
+ */
81
+ function createCodexSkipGitRepoCheckProvider(workspaceRoot) {
82
+ return (ctx) => {
83
+ if (!isCodexProvider(ctx))
84
+ return [];
85
+ if (!workspaceRoot)
86
+ return [];
87
+ return ['--skip-git-repo-check'];
88
+ };
89
+ }
90
+ /**
91
+ * Compose product-layer argument providers while preserving their order.
92
+ */
93
+ function composeAdditionalArgsProviders(...providers) {
94
+ return (ctx) => providers.flatMap((provider) => provider(ctx));
95
+ }
96
+ /**
97
+ * Create an `AdditionalArgsProvider` (SDK extension point, WI-20260703-001)
98
+ * that injects CrewX home as a Codex writable root for `workspace-write`
99
+ * equivalent modes (`agent`, `auto`, `undefined`).
100
+ *
101
+ * No-ops for:
102
+ * - Non-codex providers.
103
+ * - Modes in {@link NO_INJECT_MODES} (read-only/plan/agent-full-access/yolo/danger-full-access).
104
+ */
105
+ function createCodexWritableRootsProvider(crewxHome = resolveCrewxHome()) {
106
+ return (ctx) => {
107
+ if (!isCodexProvider(ctx))
108
+ return [];
109
+ if (ctx.mode !== undefined && NO_INJECT_MODES.has(ctx.mode))
110
+ return [];
111
+ return buildCodexWritableRootArgs(crewxHome);
112
+ };
113
+ }
@@ -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
@@ -39,6 +40,7 @@ async function createCliCrewx(configPath = process.env.CREWX_CONFIG ?? 'crewx.ya
39
40
  else {
40
41
  yamlPath = undefined;
41
42
  }
43
+ const skipRoot = yamlPath !== undefined ? (0, path_1.dirname)(absConfigPath) : undefined;
42
44
  // Run drizzle migrations once at bootstrap — plugin relies on this guarantee.
43
45
  const dbDir = (0, path_1.join)((0, os_1.homedir)(), '.crewx');
44
46
  (0, fs_1.mkdirSync)(dbDir, { recursive: true });
@@ -52,6 +54,7 @@ async function createCliCrewx(configPath = process.env.CREWX_CONFIG ?? 'crewx.ya
52
54
  }
53
55
  const crewx = await sdk_1.Crewx.loadYaml(yamlPath, {
54
56
  remoteFactory: createCliCrewx,
57
+ additionalArgsProvider: (0, codex_writable_roots_1.composeAdditionalArgsProviders)((0, codex_writable_roots_1.createCodexWritableRootsProvider)(), (0, codex_writable_roots_1.createCodexSkipGitRepoCheckProvider)(skipRoot)),
55
58
  });
56
59
  (0, register_builtin_tools_1.registerBuiltinToolsIfNeeded)(crewx);
57
60
  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,4 +6,5 @@
6
6
  * crewx db push --force Apply without confirmation + reset migration history
7
7
  * crewx db push --dry-run Show preview only, no changes
8
8
  */
9
+ export declare const TASK_LOG_MIGRATION_HELP = "Usage:\n crewx db migrate-task-logs --dry-run [--db PATH]\n crewx db migrate-task-logs --apply [--db PATH] [--batch-tasks N]\n crewx db migrate-task-logs --verify [--db PATH]\n\nModes:\n --dry-run Read and validate legacy blobs without writing or creating a backup.\n --apply Create a consistent SQLite backup, then migrate one task per transaction.\n --verify Check source invariants, event sequences, counts, and orphan rows.\n\nApply policy:\n Only blob tasks with status success, failed, or completed are migrated.\n pending, running, paused, and unknown statuses are deferred for a later run.\n There is no --force or --include-active option. Apply requires the estimated\n database/event growth plus a 10 GiB free-space reserve.\n\nExit codes:\n 0 Completed with no malformed rows or invariant failures.\n 1 Safe tasks completed but a row/invariant failed, or apply was blocked.\n 2 Invalid command-line arguments.\n\nThe command never runs automatically at server startup and never runs VACUUM.";
9
10
  export declare function handleDb(args: string[]): Promise<void>;
@@ -11,12 +11,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  return (mod && mod.__esModule) ? mod : { "default": mod };
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.TASK_LOG_MIGRATION_HELP = void 0;
14
15
  exports.handleDb = handleDb;
15
16
  const path_1 = __importDefault(require("path"));
16
17
  const os_1 = __importDefault(require("os"));
17
18
  const readline_1 = __importDefault(require("readline"));
18
19
  const repository_1 = require("@crewx/sdk/repository");
19
20
  const repository_2 = require("@crewx/sdk/repository");
21
+ const repository_3 = require("@crewx/sdk/repository");
22
+ exports.TASK_LOG_MIGRATION_HELP = `Usage:
23
+ crewx db migrate-task-logs --dry-run [--db PATH]
24
+ crewx db migrate-task-logs --apply [--db PATH] [--batch-tasks N]
25
+ crewx db migrate-task-logs --verify [--db PATH]
26
+
27
+ Modes:
28
+ --dry-run Read and validate legacy blobs without writing or creating a backup.
29
+ --apply Create a consistent SQLite backup, then migrate one task per transaction.
30
+ --verify Check source invariants, event sequences, counts, and orphan rows.
31
+
32
+ Apply policy:
33
+ Only blob tasks with status success, failed, or completed are migrated.
34
+ pending, running, paused, and unknown statuses are deferred for a later run.
35
+ There is no --force or --include-active option. Apply requires the estimated
36
+ database/event growth plus a 10 GiB free-space reserve.
37
+
38
+ Exit codes:
39
+ 0 Completed with no malformed rows or invariant failures.
40
+ 1 Safe tasks completed but a row/invariant failed, or apply was blocked.
41
+ 2 Invalid command-line arguments.
42
+
43
+ The command never runs automatically at server startup and never runs VACUUM.`;
20
44
  function defaultDbPath() {
21
45
  return path_1.default.join(os_1.default.homedir(), '.crewx', 'crewx.db');
22
46
  }
@@ -57,6 +81,12 @@ function formatPreview(result, dbPath) {
57
81
  function hasChanges(result) {
58
82
  return result.created.length > 0 || result.altered.length > 0;
59
83
  }
84
+ function formatStatusCounts(counts) {
85
+ const entries = Object.entries(counts ?? {});
86
+ return entries.length > 0
87
+ ? entries.map(([status, count]) => `${status}=${count}`).join(', ')
88
+ : '(none)';
89
+ }
60
90
  function prompt(question) {
61
91
  const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
62
92
  return new Promise((resolve) => {
@@ -68,13 +98,173 @@ function prompt(question) {
68
98
  }
69
99
  async function handleDb(args) {
70
100
  const subcommand = args[0];
101
+ if (subcommand === 'migrate-task-logs') {
102
+ await handleTaskLogMigration(args.slice(1));
103
+ return;
104
+ }
105
+ if (subcommand === '--help' || subcommand === '-h') {
106
+ console.log('Usage: crewx db push [--force] [--dry-run]');
107
+ console.log(exports.TASK_LOG_MIGRATION_HELP);
108
+ return;
109
+ }
71
110
  if (!subcommand || subcommand === 'push') {
72
111
  await handleDbPush(args.slice(subcommand === 'push' ? 1 : 0));
73
112
  return;
74
113
  }
75
114
  console.error(`Unknown db subcommand: ${subcommand}`);
76
115
  console.error('Usage: crewx db push [--force] [--dry-run]');
77
- process.exit(1);
116
+ console.error(exports.TASK_LOG_MIGRATION_HELP);
117
+ process.exitCode = 2;
118
+ }
119
+ class TaskLogMigrationUsageError extends Error {
120
+ }
121
+ function parseTaskLogMigrationArgs(args) {
122
+ let mode;
123
+ let dbPath;
124
+ let batchTasks;
125
+ const setMode = (next) => {
126
+ if (mode)
127
+ throw new TaskLogMigrationUsageError('Choose exactly one of --dry-run, --apply, or --verify.');
128
+ mode = next;
129
+ };
130
+ const requireValue = (args, index, flag) => {
131
+ const value = args[index + 1];
132
+ if (!value || value.startsWith('--'))
133
+ throw new TaskLogMigrationUsageError(`${flag} requires a value.`);
134
+ return value;
135
+ };
136
+ for (let index = 0; index < args.length; index += 1) {
137
+ const arg = args[index];
138
+ if (arg === '--help' || arg === '-h') {
139
+ throw new TaskLogMigrationUsageError(exports.TASK_LOG_MIGRATION_HELP);
140
+ }
141
+ if (arg === '--dry-run') {
142
+ setMode('dry-run');
143
+ continue;
144
+ }
145
+ if (arg === '--apply') {
146
+ setMode('apply');
147
+ continue;
148
+ }
149
+ if (arg === '--verify') {
150
+ setMode('verify');
151
+ continue;
152
+ }
153
+ if (arg === '--db') {
154
+ dbPath = requireValue(args, index, '--db');
155
+ index += 1;
156
+ continue;
157
+ }
158
+ if (arg.startsWith('--db=')) {
159
+ dbPath = arg.slice('--db='.length);
160
+ if (!dbPath)
161
+ throw new TaskLogMigrationUsageError('--db requires a value.');
162
+ continue;
163
+ }
164
+ if (arg === '--batch-tasks') {
165
+ const value = requireValue(args, index, '--batch-tasks');
166
+ const parsed = Number(value);
167
+ if (!Number.isSafeInteger(parsed) || parsed < 1) {
168
+ throw new TaskLogMigrationUsageError('--batch-tasks must be a positive integer.');
169
+ }
170
+ batchTasks = parsed;
171
+ index += 1;
172
+ continue;
173
+ }
174
+ if (arg.startsWith('--batch-tasks=')) {
175
+ const value = arg.slice('--batch-tasks='.length);
176
+ const parsed = Number(value);
177
+ if (!Number.isSafeInteger(parsed) || parsed < 1) {
178
+ throw new TaskLogMigrationUsageError('--batch-tasks must be a positive integer.');
179
+ }
180
+ batchTasks = parsed;
181
+ continue;
182
+ }
183
+ throw new TaskLogMigrationUsageError(`Unknown option: ${arg}`);
184
+ }
185
+ if (!mode)
186
+ throw new TaskLogMigrationUsageError('Choose one of --dry-run, --apply, or --verify.');
187
+ if (batchTasks !== undefined && mode !== 'apply') {
188
+ throw new TaskLogMigrationUsageError('--batch-tasks is only valid with --apply.');
189
+ }
190
+ return { mode, dbPath, batchTasks };
191
+ }
192
+ function formatMigrationReport(report) {
193
+ const modeLabel = report.mode === 'dry-run' ? 'Dry-run' : report.mode === 'apply' ? 'Apply' : 'Verify';
194
+ const lines = [
195
+ `[crewx] Task-log migration — ${modeLabel}`,
196
+ ` Database: ${report.dbPath}`,
197
+ ` Tasks scanned: ${report.taskCount}`,
198
+ ` Blob candidates: ${report.candidateTaskCount}`,
199
+ ` Eligible terminal blobs: ${report.eligibleTaskCount}`,
200
+ ` Status counts: ${formatStatusCounts(report.statusCounts)}`,
201
+ ` Deferred blob tasks: ${report.deferredTaskCount}`,
202
+ ` Deferred statuses: ${formatStatusCounts(report.deferredStatusCounts)}`,
203
+ ` Entries: ${report.entryCount}`,
204
+ ` Source bytes: ${report.sourceBytes}`,
205
+ ` Estimated free-space need: ${report.estimatedFreeSpaceBytes}`,
206
+ ` Required free space (with reserve): ${report.requiredFreeSpaceBytes}`,
207
+ ` Available free space: ${report.availableFreeSpaceBytes}`,
208
+ ` Free-space gate: ${report.freeSpaceGatePassed ? 'PASS' : 'FAIL'}`,
209
+ ` Migrated: ${report.migratedTasks} task(s), ${report.migratedEntries} entr${report.migratedEntries === 1 ? 'y' : 'ies'}`,
210
+ ` Skipped event-source tasks: ${report.skippedTasks}`,
211
+ ` Failed tasks: ${report.failedTasks}`,
212
+ ` Logical source bytes removed: ${report.logicalSourceBytesRemoved}`,
213
+ ];
214
+ if (report.remainingTaskCount !== undefined)
215
+ lines.push(` Remaining blob tasks: ${report.remainingTaskCount}`);
216
+ if (report.backupPath) {
217
+ lines.push(` Backup: ${report.backupPath}`);
218
+ if (report.backupMethod)
219
+ lines.push(` Backup method: ${report.backupMethod}`);
220
+ }
221
+ if (report.verification) {
222
+ lines.push(` Event rows checked: ${report.verification.eventCount}`);
223
+ lines.push(` Verification issues: ${report.verification.issues.length}`);
224
+ }
225
+ if (report.blockedReason)
226
+ lines.push(` Blocked: ${report.blockedReason}`);
227
+ for (const warning of report.warnings ?? [])
228
+ lines.push(` Warning: ${warning}`);
229
+ return lines.join('\n');
230
+ }
231
+ async function handleTaskLogMigration(args) {
232
+ let parsed;
233
+ try {
234
+ parsed = parseTaskLogMigrationArgs(args);
235
+ }
236
+ catch (error) {
237
+ const message = error instanceof Error ? error.message : String(error);
238
+ if (message === exports.TASK_LOG_MIGRATION_HELP) {
239
+ console.log(message);
240
+ }
241
+ else {
242
+ console.error(message);
243
+ console.error(exports.TASK_LOG_MIGRATION_HELP);
244
+ process.exitCode = 2;
245
+ }
246
+ return;
247
+ }
248
+ try {
249
+ const report = await (0, repository_3.runTaskLogMigration)(parsed);
250
+ console.log(formatMigrationReport(report));
251
+ if (!report.ok) {
252
+ if (report.blockedReason)
253
+ console.error(report.blockedReason);
254
+ const failures = report.failures ?? report.malformedRows ?? [];
255
+ for (const failure of failures) {
256
+ console.error(` ${failure.taskId}: ${failure.reason}`);
257
+ }
258
+ process.exitCode = 1;
259
+ }
260
+ else {
261
+ process.exitCode = 0;
262
+ }
263
+ }
264
+ catch (error) {
265
+ console.error(error instanceof Error ? error.message : String(error));
266
+ process.exitCode = 1;
267
+ }
78
268
  }
79
269
  async function handleDbPush(args) {
80
270
  const force = args.includes('--force');
@@ -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 {};
@@ -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 = providerInfo[provider];
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.