@crewx/cli 0.9.0-rc.16 → 0.9.0-rc.161

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 (73) hide show
  1. package/dist/bootstrap/codex-writable-roots.d.ts +20 -1
  2. package/dist/bootstrap/codex-writable-roots.js +1 -88
  3. package/dist/bootstrap/crewx-cli.js +1 -63
  4. package/dist/builtin.d.ts +1 -1
  5. package/dist/builtin.js +5 -127
  6. package/dist/commands/agent.js +4 -224
  7. package/dist/commands/cal.d.ts +15 -0
  8. package/dist/commands/cal.js +2 -0
  9. package/dist/commands/db.d.ts +3 -0
  10. package/dist/commands/db.js +59 -125
  11. package/dist/commands/detached.d.ts +95 -0
  12. package/dist/commands/detached.js +15 -0
  13. package/dist/commands/doctor.d.ts +77 -0
  14. package/dist/commands/doctor.js +4 -196
  15. package/dist/commands/emit-trailer.d.ts +25 -0
  16. package/dist/commands/emit-trailer.js +2 -0
  17. package/dist/commands/execute.d.ts +8 -4
  18. package/dist/commands/execute.js +15 -146
  19. package/dist/commands/hook/command-marker.d.ts +2 -0
  20. package/dist/commands/hook/command-marker.js +1 -0
  21. package/dist/commands/hook/install.d.ts +0 -1
  22. package/dist/commands/hook/install.js +8 -175
  23. package/dist/commands/hook/paths.js +1 -94
  24. package/dist/commands/hook/status.js +1 -86
  25. package/dist/commands/hook/uninstall.js +1 -71
  26. package/dist/commands/hook-dispatch.js +2 -180
  27. package/dist/commands/init.d.ts +34 -0
  28. package/dist/commands/init.js +37 -370
  29. package/dist/commands/kill.d.ts +2 -8
  30. package/dist/commands/kill.js +1 -52
  31. package/dist/commands/log.js +3 -95
  32. package/dist/commands/parse-agent-message.js +1 -52
  33. package/dist/commands/parse-common-flags.d.ts +5 -1
  34. package/dist/commands/parse-common-flags.js +3 -181
  35. package/dist/commands/ps.d.ts +2 -2
  36. package/dist/commands/ps.js +2 -107
  37. package/dist/commands/publish.d.ts +1 -0
  38. package/dist/commands/publish.js +27 -0
  39. package/dist/commands/query.d.ts +7 -2
  40. package/dist/commands/query.js +16 -146
  41. package/dist/commands/registry.js +1 -31
  42. package/dist/commands/resolve-prompt.js +3 -54
  43. package/dist/commands/resolve-recipient.d.ts +14 -0
  44. package/dist/commands/resolve-recipient.js +3 -0
  45. package/dist/commands/restart.d.ts +3 -1
  46. package/dist/commands/restart.js +18 -162
  47. package/dist/commands/result.d.ts +8 -3
  48. package/dist/commands/result.js +1 -70
  49. package/dist/commands/shortcut.d.ts +1 -0
  50. package/dist/commands/shortcut.js +18 -0
  51. package/dist/commands/slack.js +16 -559
  52. package/dist/commands/stop.d.ts +8 -0
  53. package/dist/commands/stop.js +8 -0
  54. package/dist/commands/write-output.js +1 -24
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.js +1 -5
  57. package/dist/logging.d.ts +1 -1
  58. package/dist/logging.js +10 -86
  59. package/dist/main.d.ts +3 -2
  60. package/dist/main.js +44 -253
  61. package/dist/register-builtin-tools.js +1 -9
  62. package/dist/slack/file-download.js +1 -134
  63. package/dist/slack/markdown.js +1 -33
  64. package/dist/utils/env-defaults.d.ts +2 -5
  65. package/dist/utils/env-defaults.js +1 -10
  66. package/dist/utils/inherited-trace.d.ts +24 -0
  67. package/dist/utils/inherited-trace.js +1 -25
  68. package/dist/utils/product-package-root.d.ts +6 -0
  69. package/dist/utils/product-package-root.js +1 -0
  70. package/dist/utils/sdk-compat.d.ts +24 -0
  71. package/dist/utils/sdk-compat.js +1 -0
  72. package/dist/utils/version.js +1 -28
  73. package/package.json +16 -12
@@ -1,125 +1,59 @@
1
- "use strict";
2
- /**
3
- * crewx db push handler.
4
- *
5
- * Usage:
6
- * crewx db push Preview changes → confirm → apply
7
- * crewx db push --force Apply without confirmation + reset migration history
8
- * crewx db push --dry-run Show preview only, no changes
9
- */
10
- var __importDefault = (this && this.__importDefault) || function (mod) {
11
- return (mod && mod.__esModule) ? mod : { "default": mod };
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.handleDb = handleDb;
15
- const path_1 = __importDefault(require("path"));
16
- const os_1 = __importDefault(require("os"));
17
- const readline_1 = __importDefault(require("readline"));
18
- const repository_1 = require("@crewx/sdk/repository");
19
- const repository_2 = require("@crewx/sdk/repository");
20
- function defaultDbPath() {
21
- return path_1.default.join(os_1.default.homedir(), '.crewx', 'crewx.db');
22
- }
23
- function formatPreview(result, dbPath) {
24
- const lines = [];
25
- lines.push(`[crewx] Database push — comparing schema vs ${dbPath}`);
26
- lines.push('');
27
- if (result.created.length > 0) {
28
- lines.push(` Tables to create:`);
29
- for (const t of result.created) {
30
- lines.push(` → ${t}`);
31
- }
32
- }
33
- else {
34
- lines.push(' Tables to create: (none)');
35
- }
36
- if (result.altered.length > 0) {
37
- lines.push(' Columns to add:');
38
- for (const { table, column } of result.altered) {
39
- lines.push(` → ${table}.${column}`);
40
- }
41
- }
42
- else {
43
- lines.push(' Columns to add: (none)');
44
- }
45
- if (result.warnings.length > 0) {
46
- lines.push(' Warnings:');
47
- for (const w of result.warnings) {
48
- lines.push(` ⚠ ${w}`);
49
- }
50
- }
51
- if (result.backupPath) {
52
- lines.push('');
53
- lines.push(` Backup: ${result.backupPath}`);
54
- }
55
- return lines.join('\n');
56
- }
57
- function hasChanges(result) {
58
- return result.created.length > 0 || result.altered.length > 0;
59
- }
60
- function prompt(question) {
61
- const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
62
- return new Promise((resolve) => {
63
- rl.question(question, (answer) => {
64
- rl.close();
65
- resolve(answer);
66
- });
67
- });
68
- }
69
- async function handleDb(args) {
70
- const subcommand = args[0];
71
- if (!subcommand || subcommand === 'push') {
72
- await handleDbPush(args.slice(subcommand === 'push' ? 1 : 0));
73
- return;
74
- }
75
- console.error(`Unknown db subcommand: ${subcommand}`);
76
- console.error('Usage: crewx db push [--force] [--dry-run]');
77
- process.exit(1);
78
- }
79
- async function handleDbPush(args) {
80
- const force = args.includes('--force');
81
- const dryRun = args.includes('--dry-run');
82
- const dbPath = defaultDbPath();
83
- const handle = (0, repository_1.openDrizzleDb)(dbPath);
84
- try {
85
- // 1. Compute preview (dry-run pass — no changes yet)
86
- const preview = (0, repository_2.pushSchema)(handle.db, { force, dbPath, dryRun: true });
87
- console.log(formatPreview(preview, dbPath));
88
- console.log('');
89
- if (dryRun) {
90
- console.log('[crewx] Dry-run mode — no changes applied.');
91
- return;
92
- }
93
- if (!hasChanges(preview)) {
94
- console.log('[crewx] No changes needed. Database is up to date.');
95
- return;
96
- }
97
- // 2. Confirm unless --force
98
- if (!force) {
99
- const answer = await prompt('Apply changes? (y/N): ');
100
- if (answer.trim().toLowerCase() !== 'y') {
101
- console.log('[crewx] Aborted.');
102
- return;
103
- }
104
- }
105
- // 3. Apply
106
- const result = (0, repository_2.pushSchema)(handle.db, { force, dbPath });
107
- console.log('');
108
- console.log('[crewx] Push complete.');
109
- if (result.created.length > 0) {
110
- console.log(` Tables created: ${result.created.join(', ')}`);
111
- }
112
- if (result.altered.length > 0) {
113
- console.log(` Columns added: ${result.altered.map((a) => `${a.table}.${a.column}`).join(', ')}`);
114
- }
115
- if (result.backupPath) {
116
- console.log(` Backup: ${result.backupPath}`);
117
- }
118
- if (result.created.length === 0 && result.altered.length === 0) {
119
- console.log(' No changes applied.');
120
- }
121
- }
122
- finally {
123
- handle.close();
124
- }
125
- }
1
+ "use strict";var g=exports&&exports.__importDefault||function(e){return e&&e.__esModule?e:{"default":e}};Object.defineProperty(exports,"__esModule",{value:true});exports.USAGE_BACKFILL_HELP=exports.REQUEST_LOG_MIGRATION_HELP=exports.TASK_LOG_MIGRATION_HELP=void 0;exports.handleDb=P;const $=g(require("path"));const v=g(require("os"));const R=g(require("readline"));const T=require("@crewx/sdk/repository");const m=require("@crewx/sdk/repository");const x=require("@crewx/sdk/repository");const p=require("@crewx/sdk/repository");const _=require("@crewx/sdk/repository");exports.TASK_LOG_MIGRATION_HELP=`Usage:
2
+ crewx db migrate-task-logs --dry-run [--db PATH]
3
+ crewx db migrate-task-logs --apply [--db PATH] [--batch-tasks N]
4
+ crewx db migrate-task-logs --verify [--db PATH]
5
+
6
+ Modes:
7
+ --dry-run Read and validate legacy blobs without writing or creating a backup.
8
+ --apply Create a consistent SQLite backup, then migrate one task per transaction.
9
+ --verify Check source invariants, event sequences, counts, and orphan rows.
10
+
11
+ Apply policy:
12
+ Only blob tasks with status success, failed, or completed are migrated.
13
+ pending, running, paused, and unknown statuses are deferred for a later run.
14
+ There is no --force or --include-active option. Apply requires the estimated
15
+ database/event growth plus a 10 GiB free-space reserve.
16
+
17
+ Exit codes:
18
+ 0 Completed with no malformed rows or invariant failures.
19
+ 1 Safe tasks completed but a row/invariant failed, or apply was blocked.
20
+ 2 Invalid command-line arguments.
21
+
22
+ The command never runs automatically at server startup and never runs VACUUM.`;exports.REQUEST_LOG_MIGRATION_HELP=`Usage:
23
+ crewx db migrate-request-logs [--batch N] [--dry-run]
24
+
25
+ Moves the request log rows still stored in crewx.db into logs.db, the file next
26
+ to it. Each distinct request/response body is stored once in logs.db, keyed by
27
+ its SHA-256; a row points to its bodies by hash, so nothing is dropped.
28
+
29
+ Options:
30
+ --batch N Rows per batch (default 250; a batch is also capped at about 8 MB).
31
+ --dry-run Count rows and distinct bodies without writing anything (logs.db is not created).
32
+
33
+ Safe while crewx is running: each batch is committed to logs.db, verified there,
34
+ and only then deleted from crewx.db in one short transaction. Interrupt it and run
35
+ it again at any time. The database is chosen like everywhere else (CREWX_DB, else
36
+ ~/.crewx/crewx.db). No VACUUM and no DROP: crewx.db keeps its size until a later compaction.
37
+
38
+ Exit codes:
39
+ 0 Every row is in logs.db and none is left in crewx.db (or the dry run finished).
40
+ 1 Rows are still in crewx.db, or an error stopped the move (progress is kept).
41
+ 2 Invalid command-line arguments.`;exports.USAGE_BACKFILL_HELP=`Usage:
42
+ crewx db backfill-usage [--dry-run|--apply|--verify] [--db PATH] [--backup PATH]
43
+ crewx db backfill-usage --restore SNAPSHOT [--db PATH]
44
+
45
+ Modes:
46
+ --dry-run Show provider/reason recovery plans without changing the database (default).
47
+ --apply Create a row-level undo snapshot, then account one task per transaction.
48
+ --verify Recheck remaining targets and usageAccounting markers without changing the database.
49
+ --restore Restore rows from SNAPSHOT when their current values still match the snapshot after-state.
50
+
51
+ Apply policy:
52
+ Only success, failed, and completed tasks with zero recorded usage are considered.
53
+ Workflow/MCP anchors and plugin/mock rows are excluded. Rows completed within 24 hours
54
+ are not marked unavailable when their logs do not contain usage.
55
+
56
+ Exit codes:
57
+ 0 Completed successfully.
58
+ 1 Apply was blocked or one or more task updates failed.
59
+ 2 Invalid command-line arguments.`;function E(){return $.default.join(v.default.homedir(),".crewx","crewx.db")}function S(e,o){const s=[];s.push(`[crewx] Database push \u2014 comparing schema vs ${o}`);s.push("");if(e.created.length>0){s.push(` Tables to create:`);for(const n of e.created){s.push(` \u2192 ${n}`)}}else{s.push(" Tables to create: (none)")}if(e.altered.length>0){s.push(" Columns to add:");for(const{table:n,column:r}of e.altered){s.push(` \u2192 ${n}.${r}`)}}else{s.push(" Columns to add: (none)")}if(e.warnings.length>0){s.push(" Warnings:");for(const n of e.warnings){s.push(` \u26A0 ${n}`)}}if(e.backupPath){s.push("");s.push(` Backup: ${e.backupPath}`)}return s.join("\n")}function L(e){return e.created.length>0||e.altered.length>0}function y(e){const o=Object.entries(e??{});return o.length>0?o.map(([s,n])=>`${s}=${n}`).join(", "):"(none)"}function A(e){const o=R.default.createInterface({input:process.stdin,output:process.stdout});return new Promise(s=>{o.question(e,n=>{o.close();s(n)})})}async function P(e){const o=e[0];if(o==="migrate-task-logs"){await B(e.slice(1));return}if(o==="migrate-request-logs"){await G(e.slice(1));return}if(o==="backfill-usage"){await N(e.slice(1));return}if(o==="--help"||o==="-h"){console.log("Usage: crewx db push [--force] [--dry-run]");console.log(exports.TASK_LOG_MIGRATION_HELP);console.log(exports.REQUEST_LOG_MIGRATION_HELP);return}if(!o||o==="push"){await H(e.slice(o==="push"?1:0));return}console.error(`Unknown db subcommand: ${o}`);console.error("Usage: crewx db push [--force] [--dry-run]");console.error(exports.TASK_LOG_MIGRATION_HELP);process.exitCode=2}class d extends Error{}class u extends Error{}function M(e){let o;let s;let n;const r=a=>{if(o)throw new d("Choose exactly one of --dry-run, --apply, or --verify.");o=a};const t=(a,c,l)=>{const i=a[c+1];if(!i||i.startsWith("--"))throw new d(`${l} requires a value.`);return i};for(let a=0;a<e.length;a+=1){const c=e[a];if(c==="--help"||c==="-h"){throw new d(exports.TASK_LOG_MIGRATION_HELP)}if(c==="--dry-run"){r("dry-run");continue}if(c==="--apply"){r("apply");continue}if(c==="--verify"){r("verify");continue}if(c==="--db"){s=t(e,a,"--db");a+=1;continue}if(c.startsWith("--db=")){s=c.slice("--db=".length);if(!s)throw new d("--db requires a value.");continue}if(c==="--batch-tasks"){const l=t(e,a,"--batch-tasks");const i=Number(l);if(!Number.isSafeInteger(i)||i<1){throw new d("--batch-tasks must be a positive integer.")}n=i;a+=1;continue}if(c.startsWith("--batch-tasks=")){const l=c.slice("--batch-tasks=".length);const i=Number(l);if(!Number.isSafeInteger(i)||i<1){throw new d("--batch-tasks must be a positive integer.")}n=i;continue}throw new d(`Unknown option: ${c}`)}if(!o)throw new d("Choose one of --dry-run, --apply, or --verify.");if(n!==void 0&&o!=="apply"){throw new d("--batch-tasks is only valid with --apply.")}return{mode:o,dbPath:s,batchTasks:n}}function C(e){const o=e.mode==="dry-run"?"Dry-run":e.mode==="apply"?"Apply":"Verify";const s=[`[crewx] Task-log migration \u2014 ${o}`,` Database: ${e.dbPath}`,` Tasks scanned: ${e.taskCount}`,` Blob candidates: ${e.candidateTaskCount}`,` Eligible terminal blobs: ${e.eligibleTaskCount}`,` Status counts: ${y(e.statusCounts)}`,` Deferred blob tasks: ${e.deferredTaskCount}`,` Deferred statuses: ${y(e.deferredStatusCounts)}`,` Entries: ${e.entryCount}`,` Source bytes: ${e.sourceBytes}`,` Estimated free-space need: ${e.estimatedFreeSpaceBytes}`,` Required free space (with reserve): ${e.requiredFreeSpaceBytes}`,` Available free space: ${e.availableFreeSpaceBytes}`,` Free-space gate: ${e.freeSpaceGatePassed?"PASS":"FAIL"}`,` Migrated: ${e.migratedTasks} task(s), ${e.migratedEntries} entr${e.migratedEntries===1?"y":"ies"}`,` Skipped event-source tasks: ${e.skippedTasks}`,` Failed tasks: ${e.failedTasks}`,` Logical source bytes removed: ${e.logicalSourceBytesRemoved}`];if(e.remainingTaskCount!==void 0)s.push(` Remaining blob tasks: ${e.remainingTaskCount}`);if(e.backupPath){s.push(` Backup: ${e.backupPath}`);if(e.backupMethod)s.push(` Backup method: ${e.backupMethod}`)}if(e.verification){s.push(` Event rows checked: ${e.verification.eventCount}`);s.push(` Verification issues: ${e.verification.issues.length}`)}if(e.blockedReason)s.push(` Blocked: ${e.blockedReason}`);for(const n of e.warnings??[])s.push(` Warning: ${n}`);return s.join("\n")}async function B(e){let o;try{o=M(e)}catch(s){const n=s instanceof Error?s.message:String(s);if(n===exports.TASK_LOG_MIGRATION_HELP){console.log(n)}else{console.error(n);console.error(exports.TASK_LOG_MIGRATION_HELP);process.exitCode=2}return}try{const s=await(0,x.runTaskLogMigration)(o);console.log(C(s));if(!s.ok){if(s.blockedReason)console.error(s.blockedReason);const n=s.failures??s.malformedRows??[];for(const r of n){console.error(` ${r.taskId}: ${r.reason}`)}process.exitCode=1}else{process.exitCode=0}}catch(s){console.error(s instanceof Error?s.message:String(s));process.exitCode=1}}class b extends Error{}function I(e){let o;let s=false;const n=r=>{const t=Number(r);if(!r||!Number.isSafeInteger(t)||t<1){throw new b("--batch must be a positive integer.")}return t};for(let r=0;r<e.length;r+=1){const t=e[r];if(t==="--help"||t==="-h")throw new b(exports.REQUEST_LOG_MIGRATION_HELP);if(t==="--dry-run"){s=true;continue}if(t==="--batch"){o=n(e[r+1]);r+=1;continue}if(t.startsWith("--batch=")){o=n(t.slice("--batch=".length));continue}throw new b(`Unknown option: ${t}`)}return{batchRows:o,dryRun:s}}function h(e){if(e<1024)return`${e} B`;const o=["KiB","MiB","GiB","TiB"];let s=e;let n=-1;while(s>=1024&&n<o.length-1){s/=1024;n+=1}return`${s.toFixed(s>=100?0:1)} ${o[n]} (${e} bytes)`}function k(e,o){const s=[...e].sort((n,r)=>n-r);return s[Math.min(s.length-1,Math.floor(o/100*s.length))]}function w(e){return`${(e/1e3).toFixed(1)}s`}const q=1e4;function O(e,o){if(e.dryRun){const s=e.scan;console.log("[crewx] Dry run finished \u2014 nothing was written.");console.log(` Rows scanned: ${s?.rows??0}`);console.log(` Bodies: ${s?.bodies??0} (${h(s?.bodyBytes??0)})`);console.log(` Distinct bodies: ${s?.distinctBodies??0} (${h(s?.distinctBodyBytes??0)}) \u2014 what logs.db would store`);console.log(` Elapsed: ${w(e.elapsedMs)}`);return}console.log("[crewx] Request-log move finished.");console.log(` Moved rows: ${e.movedRows}`);console.log(` Remaining rows in crewx.db: ${o.crewxRows}`);console.log(` logs.db request_logs: ${o.logsRows??0}`);console.log(` logs.db request_log_bodies: ${o.logsBodies??0}`);console.log(` logs.db size: ${h(o.logsFileBytes)} (+ wal ${h(o.logsWalBytes)})`);console.log(` crewx.db freelist pages: ${o.crewxFreelistPages}`);console.log(` Batches: ${e.batches}, bodies added: ${e.bodiesAdded}`);if(e.deleteTxMs.length>0){console.log(` crewx.db delete transaction per batch: p50 ${k(e.deleteTxMs,50).toFixed(1)} ms, p90 ${k(e.deleteTxMs,90).toFixed(1)} ms, max ${e.maxDeleteTxMs.toFixed(1)} ms`);console.log(` Largest crewx.db -wal seen after a batch: ${h(e.maxWalBytes)}`)}console.log(` Elapsed: ${w(e.elapsedMs)}`);if(o.crewxRows>0){console.log(` ${o.crewxRows} row(s) are still in crewx.db (new rows arrived or the run stopped early). Run it again.`)}}async function G(e){let o;try{o=I(e)}catch(s){const n=s instanceof Error?s.message:String(s);if(n===exports.REQUEST_LOG_MIGRATION_HELP){console.log(n)}else{console.error(n);console.error(exports.REQUEST_LOG_MIGRATION_HELP);process.exitCode=2}return}try{const s=(0,p.inspectRequestLogsMove)();console.log(`[crewx] Request logs \u2192 logs.db${o.dryRun?" (dry run)":""}`);console.log(` crewx.db: ${s.crewxDbPath}`);console.log(` logs.db: ${s.logsDbPath}`);console.log(` Rows to move: ${s.crewxRows}`);let n=Date.now();const r=a=>{const c=Date.now();if(c-n<q)return;n=c;const l=o.dryRun?a.scannedRows:a.movedRows;const i=Math.max(0,s.crewxRows-l);console.log(` ${o.dryRun?"scanned":"moved"} ${l} | remaining ~${i} | elapsed ${w(a.elapsedMs)}`)};const t=(0,p.moveRequestLogsToLogsDb)({batchRows:o.batchRows,dryRun:o.dryRun,onProgress:r});O(t,(0,p.inspectRequestLogsMove)());process.exitCode=o.dryRun||t.remainingRows===0?0:1}catch(s){console.error(s instanceof Error?s.message:String(s));process.exitCode=1}}function U(e){let o;let s;let n;let r;const t=l=>{if(o)throw new u("Choose exactly one of --dry-run, --apply, --verify, or --restore.");o=l};const a=(l,i)=>{const f=e[l+1];if(!f||f.startsWith("--"))throw new u(`${i} requires a value.`);return f};for(let l=0;l<e.length;l+=1){const i=e[l];if(i==="--help"||i==="-h")throw new u(exports.USAGE_BACKFILL_HELP);if(i==="--dry-run"){t("dry-run");continue}if(i==="--apply"){t("apply");continue}if(i==="--verify"){t("verify");continue}if(i==="--restore"){t("restore");r=a(l,"--restore");l+=1;continue}if(i.startsWith("--restore=")){t("restore");r=i.slice("--restore=".length);if(!r)throw new u("--restore requires a value.");continue}if(i==="--db"){s=a(l,"--db");l+=1;continue}if(i.startsWith("--db=")){s=i.slice("--db=".length);if(!s)throw new u("--db requires a value.");continue}if(i==="--backup"){n=a(l,"--backup");l+=1;continue}if(i.startsWith("--backup=")){n=i.slice("--backup=".length);if(!n)throw new u("--backup requires a value.");continue}throw new u(`Unknown option: ${i}`)}const c=o??"dry-run";if(n&&c!=="apply"){throw new u("--backup is only valid with --apply.")}if(r&&c!=="restore"){throw new u("--restore is only valid with restore mode.")}return{mode:c,dbPath:s,backupPath:n,restorePath:r}}function D(e){const o=e.mode==="dry-run"?"Dry-run":e.mode==="apply"?"Apply":e.mode==="restore"?"Restore":"Verify";const s=[`[crewx] Usage backfill \u2014 ${o}`,` Database: ${e.dbPath}`,` Tasks scanned: ${e.scannedTasks}`,` Terminal tasks: ${e.terminalTasks}`,` Raw target tasks: ${e.rawTargetTasks}`,` Candidate tasks: ${e.candidateTasks}`,` Recovered: ${e.recoveredTasks}`,` Unavailable: ${e.unavailableTasks}`,` Deferred (within 24h): ${e.deferredTasks}`,` Changed: ${e.changedTasks}`,` Would change: ${e.wouldChangeTasks}`,` Restored: ${e.restored}`,` Skipped conflicts: ${e.skippedConflict}`,` Remaining target tasks: ${e.remainingTargetTasks}`,` Tasks with usageAccounting: ${e.accountingTasks}`," Provider distribution:"];const n=Object.entries(e.providerDistribution);if(n.length===0){s.push(" (none)")}else{for(const[t,a]of n){s.push(` ${t}: candidates=${a.candidates}, recovered=${a.recovered}, unavailable=${a.unavailable}, deferred=${a.deferred}`)}}s.push(" Reason counts:");for(const[t,a]of Object.entries(e.reasonCounts))s.push(` ${t}: ${a}`);s.push(` Estimated free-space need: ${e.estimatedFreeSpaceBytes}`);s.push(` Required free space (with reserve): ${e.requiredFreeSpaceBytes}`);s.push(` Available free space: ${e.availableFreeSpaceBytes}`);s.push(` Free-space gate: ${e.freeSpaceGatePassed?"PASS":"FAIL"}`);const r=e.snapshotPath??e.backupPath;if(r){s.push(` Undo snapshot: ${r}`);if(e.backupMethod)s.push(` Snapshot method: ${e.backupMethod}`)}if(e.blockedReason)s.push(` Blocked: ${e.blockedReason}`);for(const t of e.conflictSamples){s.push(` Conflict sample: ${t.taskId}: ${t.fields.join(", ")}`)}for(const t of e.failures)s.push(` Failure: ${t.taskId}: ${t.reason}`);for(const t of e.warnings)s.push(` Warning: ${t}`);return s.join("\n")}async function N(e){let o;try{o=U(e)}catch(s){const n=s instanceof Error?s.message:String(s);if(n===exports.USAGE_BACKFILL_HELP){console.log(n)}else{console.error(n);console.error(exports.USAGE_BACKFILL_HELP);process.exitCode=2}return}try{const s=await(0,_.runUsageBackfill)(o);console.log(D(s));process.exitCode=s.ok?0:1}catch(s){console.error(s instanceof Error?s.message:String(s));process.exitCode=1}}async function H(e){const o=e.includes("--force");const s=e.includes("--dry-run");const n=E();const r=(0,T.openDrizzleDb)(n);try{const t=(0,m.pushSchema)(r.db,{force:o,dbPath:n,dryRun:true});console.log(S(t,n));console.log("");if(s){console.log("[crewx] Dry-run mode \u2014 no changes applied.");return}if(!L(t)){console.log("[crewx] No changes needed. Database is up to date.");return}if(!o){const c=await A("Apply changes? (y/N): ");if(c.trim().toLowerCase()!=="y"){console.log("[crewx] Aborted.");return}}const a=(0,m.pushSchema)(r.db,{force:o,dbPath:n});console.log("");console.log("[crewx] Push complete.");if(a.created.length>0){console.log(` Tables created: ${a.created.join(", ")}`)}if(a.altered.length>0){console.log(` Columns added: ${a.altered.map(c=>`${c.table}.${c.column}`).join(", ")}`)}if(a.backupPath){console.log(` Backup: ${a.backupPath}`)}if(a.created.length===0&&a.altered.length===0){console.log(" No changes applied.")}}finally{r.close()}}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Shared receipt-mode implementation for the query and execute commands.
3
+ *
4
+ * A receipt is persisted before a detached runner is started. The runner gets
5
+ * its own identity variables, while the trace variables remain the caller's
6
+ * trace context and are never repurposed as the runner assignment.
7
+ */
8
+ import { TaskRepository } from '@crewx/sdk/repository';
9
+ import type { DurableTaskAdmission, TaskActor } from '@crewx/sdk';
10
+ export type ReceiptActorKind = 'human' | 'agent' | 'system' | 'unknown';
11
+ export interface ReceiptActor {
12
+ kind: ReceiptActorKind;
13
+ id: string | null;
14
+ }
15
+ /** Resolve the CLI actor from metadata and the caller's current environment. */
16
+ export declare function resolveCliTaskActor(metadata: Record<string, unknown>, agentId?: string | undefined): TaskActor;
17
+ /**
18
+ * Resolve the actor at the receipt boundary while the caller's environment is
19
+ * still available. The receipt and synchronous paths share one predicate so
20
+ * cron runners cannot diverge after root context is stripped.
21
+ */
22
+ export declare function resolveReceiptActor(metadata: Record<string, unknown>, agentId?: string | undefined): ReceiptActor;
23
+ /**
24
+ * Report a blocked direct admission (WI-CTO-20260919-004 R2 finding #1) to
25
+ * the operator. Never called for an adopted (already pending) receipt — see
26
+ * admitDurableTask()'s own doc comment.
27
+ */
28
+ export declare function reportAdmissionBlocked(admission: Extract<DurableTaskAdmission, {
29
+ ok: false;
30
+ }>): void;
31
+ /**
32
+ * Remove receipt-selection flags, respecting the `--` literal-args sentinel.
33
+ */
34
+ export declare function extractReceiptFlags(args: string[]): {
35
+ detach: boolean;
36
+ wait: boolean;
37
+ rest: string[];
38
+ };
39
+ export type ReceiptModeReason = 'explicit-detach' | 'agent-context' | 'detached-runner' | 'wait' | 'default';
40
+ export interface ReceiptModeDecision {
41
+ receipt: boolean;
42
+ reason: ReceiptModeReason;
43
+ }
44
+ /** Resolve the receipt/synchronous mode contract shared by q and x. */
45
+ export declare function resolveReceiptMode(options: {
46
+ detach: boolean;
47
+ wait: boolean;
48
+ detachedRunner: boolean;
49
+ agentContext: boolean;
50
+ }): ReceiptModeDecision;
51
+ /**
52
+ * Rebuild runner argv from the parsed request. The resolved prompt is passed
53
+ * as one argv value after `--`, so stdin is never needed by the detached
54
+ * child and prompt text beginning with a dash remains positional text.
55
+ */
56
+ export declare function buildDetachedRunnerArgs(filteredArgs: string[], agentRef: string, finalMessage: string): string[];
57
+ export type AssignedTaskAdoption = {
58
+ kind: 'adopted';
59
+ taskId: string;
60
+ } | {
61
+ kind: 'stale';
62
+ } | {
63
+ kind: 'failed';
64
+ };
65
+ /**
66
+ * Claim a pre-issued receipt without overwriting an already-owned row.
67
+ * Assignment-only leakage is recoverable: discard the stale id and let the
68
+ * normal SDK path create a fresh task. A real detached runner must fail loud
69
+ * because its receipt would otherwise point at no execution row.
70
+ */
71
+ export declare function adoptAssignedTask(taskRepo: Pick<TaskRepository, 'adoptPendingTask'>, taskId: string, detachedRunner: boolean): AssignedTaskAdoption;
72
+ /** Read the actor persisted on the receipt after the runner adopts it. */
73
+ export declare function readAssignedTaskActor(taskRepo: Pick<TaskRepository, 'getTask'>, taskId: string): TaskActor;
74
+ export interface DetachedMiddleHop {
75
+ taskId: string;
76
+ logPath: string;
77
+ runnerArgs: string[];
78
+ }
79
+ /**
80
+ * Read the private Windows middle-hop contract. Invalid direct invocations
81
+ * are left untouched and therefore fail through the normal unknown-option
82
+ * path instead of becoming an undocumented public command.
83
+ */
84
+ export declare function readDetachedMiddleHop(args: string[]): DetachedMiddleHop | undefined;
85
+ /**
86
+ * Windows middle hop: transfer a transient log handle to the final runner,
87
+ * close the middle process's copy, and exit immediately. The parent treats a
88
+ * successful middle-hop exit as normal and makes adoption a database decision.
89
+ */
90
+ export declare function runDetachedMiddle(command: string, hop: DetachedMiddleHop): Promise<void>;
91
+ /**
92
+ * Persist a receipt and launch its detached runner. Unix uses one hop. Windows
93
+ * uses a short-lived middle hop so the final runner has no live parent link.
94
+ */
95
+ export declare function runDetached(command: string, filteredArgs: string[], reason: ReceiptModeReason, invocationArgs?: string[]): Promise<void>;
@@ -0,0 +1,15 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.resolveCliTaskActor=V;exports.resolveReceiptActor=X;exports.reportAdmissionBlocked=B;exports.extractReceiptFlags=he;exports.resolveReceiptMode=_e;exports.buildDetachedRunnerArgs=Y;exports.adoptAssignedTask=we;exports.readAssignedTaskActor=me;exports.readDetachedMiddleHop=Ee;exports.runDetachedMiddle=xe;exports.runDetached=ve;const F=require("child_process");const l=require("fs");const A=require("path");const ne=require("os");const y=require("@crewx/sdk");const se=require("@crewx/sdk/node");const oe=require("@crewx/sdk/repository");const ie=require("./parse-agent-message");const j=require("./parse-common-flags");const ce=require("./resolve-recipient");const ae=require("./resolve-prompt");const de=require("../utils/version");const G=require("../utils/inherited-trace");const U=require("./cal");const ue=require("./emit-trailer");function q(e){return typeof e==="string"&&e.trim().length>0?e.trim():void 0}function V(e,t=process.env["CREWX_AGENT_ID"]){const r=q(e.schedule_id);if(r)return{actorKind:"system",actorId:`cron:${r}`};const n=e.workflow;const s=n!==null&&typeof n==="object"&&!Array.isArray(n)?n:void 0;const o=q(s?.exec_id);if(o)return{actorKind:"system",actorId:`workflow:${o}`};const i=q(t);if(i)return{actorKind:"agent",actorId:i};if(process.stdin.isTTY===true||process.stderr.isTTY===true){return{actorKind:"human",actorId:(0,se.getLocalActorId)()}}return{actorKind:"unknown",actorId:null}}function X(e,t=process.env["CREWX_AGENT_ID"]){const r=V(e,t);return{kind:r.actorKind,id:r.actorId}}function B(e){process.stderr.write(`${e.message}
2
+ `)}const le=200;const z=3e4;const pe=["--to","--thread","--provider","--model","--metadata","--config","-c","--output-format","--effort","--prompt-file","-f","--out","-o"];const J="--__crewx-detached-middle";const C="--__crewx-detached-task";const L="--__crewx-detached-log";const M="--__crewx-detached-token";const b="CREWX_DETACHED_HOP_TOKEN";function fe(e){return pe.some(t=>e===t||e.startsWith(`${t}=`))}function ge(e){return e==="--prompt-file"||e==="-f"||e.startsWith("--prompt-file=")||e.startsWith("-f=")}function he(e){const t=[];let r=false;let n=false;let s=false;for(const o of e){if(!s&&o==="--"){s=true;t.push(o);continue}if(!s&&(o==="--detach"||o==="--async")){r=true;continue}if(!s&&(o==="--wait"||o.startsWith("--wait="))){n=true;continue}t.push(o)}return{detach:r,wait:n,rest:t}}function _e(e){if(e.wait)return{receipt:false,reason:"wait"};if(e.detachedRunner)return{receipt:false,reason:"detached-runner"};if(e.detach)return{receipt:true,reason:"explicit-detach"};if(e.agentContext)return{receipt:true,reason:"agent-context"};return{receipt:false,reason:"default"}}function h(e){return e instanceof Error?e.message:String(e)}function ke(e,t,r,n={}){return new Promise((s,o)=>{let i=false;let c;let _;const T=()=>{if(c!==void 0)clearInterval(c);if(_!==void 0)clearTimeout(_)};const E=a=>{if(i)return;i=true;T();s(a)};const k=(a,g=false)=>{try{const p=e.getTask(t);if(p&&p.status!=="pending"){E({kind:"adopted"});return}if(a!==void 0){E({kind:"exited",reason:a});return}if(g)E({kind:"timeout"})}catch(p){if(i)return;i=true;T();o(p)}};r.on("error",a=>{k(`Runner failed before adopting task: ${h(a)}`)});r.on("exit",(a,g)=>{if(n.ignoreSuccessfulExit&&a===0&&g===null)return;const p=g?`signal ${g}`:`exit ${a??"unknown"}`;k(`Runner exited before adopting task (${p})`)});c=setInterval(()=>k(),le);_=setTimeout(()=>k(void 0,true),z);k()})}function W(e,t,r){try{const n=e.failPendingTask(t,r);if(n){process.stderr.write(`Detached task ${t} failed: ${r}
3
+ `);return false}const s=e.getTask(t);if(s&&s.status!=="pending")return true}catch(n){r+=`; could not persist failure: ${h(n)}`}process.stderr.write(`Detached task ${t} failed: ${r}
4
+ `);return false}function R(e,t,r,n,s,o,i){let c="pending";try{const T=e.getTask(t);c=T?.status==="pending"?"pending":"running"}catch{}if(o==="json"){process.stdout.write(`${JSON.stringify({taskId:t,status:c,mode:"receipt",logPath:r})}
5
+ `);return}if(s)process.stderr.write(`mode=receipt reason=${n}
6
+ `);process.stdout.write(`${t}
7
+ `);process.stderr.write(`Task ${t} accepted. This ID is the handle (not a PID).
8
+ `);if(i&&s)process.stderr.write(`${i}
9
+ `);const _=(0,U.suggestWaitSeconds)({startedAt:null});(0,U.writeCalFooter)({commandId:"crewx.receipt",params:{taskId:t,wait:String(_)}})}function Y(e,t,r){const n=[];for(let s=0;s<e.length;s+=1){const o=e[s];if(o==="--")break;if(o==="--verbose"||o==="--overdrive"){n.push(o);continue}if(o==="--var"){const i=e[s+1];if(i!==void 0){n.push(o,i);s+=1}continue}if(o.startsWith("--var=")){n.push(o);continue}if(o==="--to"){s+=1;continue}if(o.startsWith("--to="))continue;if(!fe(o))continue;if(ge(o)){if(!o.includes("="))s+=1;continue}n.push(o);if(!o.includes("=")){const i=e[s+1];if(i!==void 0){n.push(i);s+=1}}}return[...n,...t?[t]:[],"--",r]}function Q(e){if(e==="execute")return"x";if(e==="query")return"q";return e}function Z(e){const t={...process.env};delete t[b];if(process.versions.electron){t.ELECTRON_RUN_AS_NODE="1"}t.CREWX_DETACHED_RUNNER="1";t.CREWX_ASSIGNED_TASK_ID=e;return t}function we(e,t,r){if(e.adoptPendingTask(t)){return{kind:"adopted",taskId:t}}const n=`stale assigned id ${t}: expected pending task with pid NULL`;if(r){process.stderr.write(`Detached runner failed to adopt task ${t}: ${n}
10
+ `);return{kind:"failed"}}process.stderr.write(`${n}
11
+ `);return{kind:"stale"}}function me(e,t){const r=e.getTask(t);const n=r?.actor_kind;if(n===null||n===void 0){return{actorKind:"unknown",actorId:null}}if(n==="human"||n==="agent"||n==="system"||n==="unknown"){return{actorKind:n,actorId:r?.actor_id??null}}return{actorKind:"unknown",actorId:r?.actor_id??null}}function Te(e){const t={...process.env};if(process.versions.electron){t.ELECTRON_RUN_AS_NODE="1"}t[b]=e;return t}function Ee(e){let t=false;let r;let n;let s;let o=false;const i=[];for(const c of e){if(!o&&c==="--"){o=true;i.push(c);continue}if(!o&&c===J){t=true;continue}if(!o&&c.startsWith(`${C}=`)){r=c.slice(`${C}=`.length);continue}if(!o&&c.startsWith(`${L}=`)){n=c.slice(`${L}=`.length);continue}if(!o&&c.startsWith(`${M}=`)){s=c.slice(`${M}=`.length);continue}i.push(c)}if(!t||!r||!n||!s||s!==process.env[b]){return void 0}return{taskId:r,logPath:n,runnerArgs:i}}async function xe(e,t){let r;try{const n=(0,A.dirname)(t.logPath);if(!(0,l.existsSync)(n))(0,l.mkdirSync)(n,{recursive:true});r=(0,l.openSync)(t.logPath,"a");const s=process.argv[1];const o=(0,F.spawn)(process.execPath,[s,Q(e),...t.runnerArgs],{detached:true,windowsHide:true,stdio:["ignore",r,r],env:Z(t.taskId)});(0,l.closeSync)(r);r=void 0;o.unref()}catch(n){if(r!==void 0)(0,l.closeSync)(r);process.stderr.write(`Runner failed before adopting task: ${h(n)}
12
+ `);process.exit(1);return}process.exit(0)}async function ve(e,t,r,n=t){const s=(0,j.parseCommonFlags)(t);const{thread:o,metadata:i,promptFile:c,rest:_,to:T}=s;const{agentRef:E,message:k}=(0,ie.parseAgentMessage)(_);const a=await(0,ae.resolvePrompt)(k,c);let g;try{({agentRef:g}=(0,ce.resolveRecipient)({positionalRef:E,toFlag:T,agentContext:Boolean(process.env["CREWX_AGENT_ID"]),bodyForHint:a,command:e,invocationArgs:n}))}catch(u){const v=h(u);process.stderr.write(`Error: ${v}
13
+ `);(0,ue.emitDelegationResult)({command:e,trace:(0,G.readInheritedTrace)(),isError:true});process.exit(2);return}if(!a){console.error("Usage: crewx q|x --to <agent> <message> [options]");console.error(" @agent is a positional shorthand for selecting a recipient.");console.error(" Task body can also be supplied via stdin pipe or --prompt-file.");process.exit(1);return}let p;try{p=(0,j.parseMetadata)(i)}catch(u){process.stderr.write(`Error: ${h(u)}
14
+ `);process.exit(2);return}const x=(0,y.admitDurableTask)(`direct-cli:${e}`);if(!x.ok){B(x);process.exit(1);return}const d=x.taskId;const ee=new Date().toISOString();const I=process.cwd();const te=(0,l.existsSync)((0,A.join)(I,"crewx.yaml"))||(0,l.existsSync)((0,A.join)(I,"crewx.yml"));const N=(0,G.readInheritedTrace)();const re=N?.rootTraceId||d;const f=new oe.TaskRepository;const O=X(p);try{f.startTask({id:d,agentId:g.replace(/^@/,""),actorKind:O.kind,actorId:O.id,prompt:a,mode:e==="q"||e==="query"?"query":"execute",status:"pending",startedAt:ee,pid:null,parentTaskId:N?.parentTaskId??null,callerAgentId:N?.callerAgentId??null,traceId:re,command:process.argv.join(" "),metadata:Object.keys(p).length>0?JSON.stringify(p):null,workspaceId:te?(0,y.hashWorkspaceId)((0,y.resolveWorkspaceOwnerPath)(I)):null,cwd:(0,y.normalizeWorkspacePath)(I),projectId:null,platform:"cli",crewxVersion:de.CLI_VERSION,threadId:o??null})}catch(u){x.release();process.stderr.write(`Failed to create detached task receipt: ${h(u)}
15
+ `);process.exit(1);return}x.release();const P=Y(t,g,a);const K=Q(e);const S=(0,A.join)((0,ne.homedir)(),".crewx","logs");const w=(0,A.join)(S,`${d}.log`);let m;let D;let H=false;try{if(!(0,l.existsSync)(S))(0,l.mkdirSync)(S,{recursive:true});if(process.platform==="win32"){H=true;const u=(0,y.generateId)("req");D=(0,F.spawn)(process.execPath,[process.argv[1],K,J,`${C}=${d}`,`${L}=${w}`,`${M}=${u}`,...P],{detached:true,windowsHide:true,stdio:"ignore",env:Te(u)})}else{m=(0,l.openSync)(w,"a");D=(0,F.spawn)(process.execPath,[process.argv[1],K,...P],{detached:true,windowsHide:true,stdio:["ignore",m,m],env:Z(d)});(0,l.closeSync)(m);m=void 0}D.unref()}catch(u){if(m!==void 0)(0,l.closeSync)(m);const v=`Runner failed before adopting task: ${h(u)}`;if(!W(f,d,v))process.exit(1);else{R(f,d,w,r,s.verbose,s.outputFormat);process.exit(0)}return}let $;try{$=await ke(f,d,D,{ignoreSuccessfulExit:H})}catch(u){const v=`Runner adoption check failed: ${h(u)}`;if(!W(f,d,v))process.exit(1);else{R(f,d,w,r,s.verbose,s.outputFormat);process.exit(0)}return}if($.kind==="adopted"){R(f,d,w,r,s.verbose,s.outputFormat);process.exit(0);return}if($.kind==="timeout"){R(f,d,w,r,s.verbose,s.outputFormat,`Warning: runner alive, row not yet adopted after ${z/1e3}s.`);process.exit(0);return}if(!W(f,d,$.reason))process.exit(1);else{R(f,d,w,r,s.verbose,s.outputFormat);process.exit(0)}}
@@ -6,7 +6,84 @@
6
6
  * crewx doctor Run full diagnosis
7
7
  * crewx doctor --config <path> Use specific config file
8
8
  */
9
+ import type { CrewxExecutableResolution, CrewxExecutableStage } from '@crewx/sdk';
10
+ interface DiagnosticResult {
11
+ name: string;
12
+ status: 'success' | 'warning' | 'error';
13
+ message: string;
14
+ details?: string;
15
+ }
16
+ export interface CliProviderInfo {
17
+ cmd: string;
18
+ install: string;
19
+ }
20
+ export interface DoctorArtifact {
21
+ directory: string;
22
+ sizeBytes: number;
23
+ details: string[];
24
+ }
25
+ export interface NpxCacheReport {
26
+ cacheRoot: string;
27
+ zeroByteLockfileDirectories: DoctorArtifact[];
28
+ staleFileCacheDirectories: DoctorArtifact[];
29
+ cleanableDirectories: DoctorArtifact[];
30
+ }
31
+ export interface HookCommandIssue {
32
+ provider: 'claude' | 'codex';
33
+ settingsPath: string;
34
+ command: string;
35
+ reason: 'launcher' | 'non-absolute';
36
+ }
37
+ export interface HookCommandReport {
38
+ inspectedFiles: string[];
39
+ issues: HookCommandIssue[];
40
+ }
41
+ export interface CrewxShimReport {
42
+ shimRoot: string;
43
+ currentFingerprint?: string;
44
+ staleDirectories: Array<DoctorArtifact & {
45
+ fingerprint: string;
46
+ }>;
47
+ }
48
+ export interface CrewxExecutableReport {
49
+ platform: NodeJS.Platform;
50
+ pathCandidates: string[];
51
+ stage?: CrewxExecutableStage;
52
+ argv?: string[];
53
+ electron: boolean;
54
+ requiredEnvKeys: string[];
55
+ binResolution: 'global_first' | 'local_first';
56
+ adoptedPath?: string;
57
+ resolutionError?: string;
58
+ }
59
+ export interface CrewxExecutableInspectionOptions {
60
+ platform?: NodeJS.Platform;
61
+ cwd?: string;
62
+ env?: NodeJS.ProcessEnv;
63
+ binResolution?: 'global_first' | 'local_first';
64
+ pathCandidates?: readonly string[];
65
+ resolution?: CrewxExecutableResolution;
66
+ }
67
+ /** CLI diagnostics keyed by the bare provider name used in PROVIDER_ORDER. */
68
+ export declare const CLI_PROVIDER_INFO: Record<string, CliProviderInfo>;
69
+ /** Format a byte count for diagnostic output. */
70
+ export declare function formatBytes(bytes: number): string;
71
+ /** Inspect npm's persistent `_npx` cache without modifying it. */
72
+ export declare function inspectNpxCache(cacheRoot?: string): NpxCacheReport;
73
+ /** Inspect installed CrewX hooks without rewriting provider settings. */
74
+ export declare function inspectHookCommands(projectRoot: string): HookCommandReport;
75
+ /** Inspect the SDK-selected CrewX executable without printing environment values. */
76
+ export declare function inspectCrewxExecutable(options?: CrewxExecutableInspectionOptions & {
77
+ configPath?: string;
78
+ }): CrewxExecutableReport;
79
+ /** Inspect orphaned CrewX PATH shim directories without modifying them. */
80
+ export declare function inspectCrewxShims(crewxHome?: string, resolvedFingerprint?: string | undefined): CrewxShimReport;
81
+ /**
82
+ * Check CLI provider availability in the canonical PROVIDER_ORDER.
83
+ */
84
+ export declare function checkCliProviders(): DiagnosticResult[];
9
85
  /**
10
86
  * Handle `crewx doctor` command.
11
87
  */
12
88
  export declare function handleDoctor(args: string[]): Promise<void>;
89
+ export {};