@crewx/cli 0.9.0-rc.40 → 0.9.0-rc.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init.js +17 -1
- package/dist/commands/registry.js +1 -0
- package/dist/commands/shortcut.d.ts +1 -0
- package/dist/commands/shortcut.js +267 -0
- package/dist/main.js +10 -0
- package/package.json +12 -12
package/dist/commands/init.js
CHANGED
|
@@ -52,6 +52,7 @@ const git = __importStar(require("isomorphic-git"));
|
|
|
52
52
|
const nodeFs = __importStar(require("fs"));
|
|
53
53
|
const os_1 = __importDefault(require("os"));
|
|
54
54
|
const repository_1 = require("@crewx/sdk/repository");
|
|
55
|
+
const sdk_1 = require("@crewx/sdk");
|
|
55
56
|
const install_1 = require("./hook/install");
|
|
56
57
|
const STATUSLINE_SCRIPT_NAME = 'claude-usage-statusline.js';
|
|
57
58
|
const STATUSLINE_SCRIPT_MARKER = 'CrewX claude-usage-statusline';
|
|
@@ -440,7 +441,7 @@ async function handleInit(opts) {
|
|
|
440
441
|
}
|
|
441
442
|
}
|
|
442
443
|
// Always create docs dirs and templates, regardless of whether yaml was skipped
|
|
443
|
-
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']) {
|
|
444
445
|
try {
|
|
445
446
|
(0, fs_1.mkdirSync)((0, path_1.join)(target, dir), { recursive: true });
|
|
446
447
|
}
|
|
@@ -461,6 +462,21 @@ async function handleInit(opts) {
|
|
|
461
462
|
console.log(`✅ ${t.dir}/ ${action} (${t.file})`);
|
|
462
463
|
}
|
|
463
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
|
+
}
|
|
464
480
|
// Always register workspace in ~/.crewx/crewx.db (best-effort, idempotent)
|
|
465
481
|
let workspaceId;
|
|
466
482
|
let slug;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleShortcut(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleShortcut = handleShortcut;
|
|
4
|
+
/**
|
|
5
|
+
* crewx shortcut handler — thin CLI wrapper over @crewx/sdk/desktop.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* crewx shortcut status [--json]
|
|
9
|
+
* crewx shortcut install [--force] [--json]
|
|
10
|
+
* crewx shortcut uninstall [--json]
|
|
11
|
+
*
|
|
12
|
+
* All win32/foreign/superseded/force judgment lives in @crewx/sdk/desktop.
|
|
13
|
+
* This module only parses argv, forwards options, and renders the result.
|
|
14
|
+
*/
|
|
15
|
+
const desktop_1 = require("@crewx/sdk/desktop");
|
|
16
|
+
const parse_common_flags_1 = require("./parse-common-flags");
|
|
17
|
+
const NOT_WINDOWS_MESSAGE = 'NOT_WINDOWS: Desktop shortcuts are only supported on Windows.';
|
|
18
|
+
function parseShortcutFlags(args, allowForce) {
|
|
19
|
+
let json = false;
|
|
20
|
+
let force = false;
|
|
21
|
+
for (const arg of args) {
|
|
22
|
+
if (arg === '--json') {
|
|
23
|
+
json = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === '--force' && allowForce) {
|
|
27
|
+
force = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
throw new parse_common_flags_1.UnknownOptionError(`Unknown option: ${arg}`);
|
|
31
|
+
}
|
|
32
|
+
return { json, force };
|
|
33
|
+
}
|
|
34
|
+
/** Forwarded verbatim to stderr as each SDK phase starts — never buffered. */
|
|
35
|
+
function onProgress(event) {
|
|
36
|
+
process.stderr.write(`[shortcut] ${event.message}\n`);
|
|
37
|
+
}
|
|
38
|
+
function printJson(payload) {
|
|
39
|
+
console.log(JSON.stringify(payload));
|
|
40
|
+
}
|
|
41
|
+
/** Prints the error and exits 1. Never returns (matches `process.exit`'s `never` type). */
|
|
42
|
+
function failWithError(err, json) {
|
|
43
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
44
|
+
if (json) {
|
|
45
|
+
printJson({ success: false, error: message });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error(`✗ ${message}`);
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
/** The SDK returns `supported:false` (no throw) for install/uninstall on non-Windows. */
|
|
53
|
+
function failNotWindows(json) {
|
|
54
|
+
if (json) {
|
|
55
|
+
printJson({ success: false, supported: false, state: 'unsupported', error: NOT_WINDOWS_MESSAGE });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.error(`✗ ${NOT_WINDOWS_MESSAGE}`);
|
|
59
|
+
}
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Detects the two ways a resolved (non-thrown) install result must NOT be
|
|
64
|
+
* read as success: a `superseded` shortcut (checked via both `state` and the
|
|
65
|
+
* `errors[]` entry, since either alone could otherwise be missed) and an
|
|
66
|
+
* unconfirmed global install (`installedGlobal:false` with
|
|
67
|
+
* `GLOBAL_INSTALL_UNCONFIRMED` in errors — npm exited 0 but re-detection
|
|
68
|
+
* could not confirm it).
|
|
69
|
+
*/
|
|
70
|
+
function installFailureReason(result) {
|
|
71
|
+
const supersededError = result.errors.find((e) => e.startsWith('SUPERSEDED:'));
|
|
72
|
+
if (result.state === 'superseded' || supersededError) {
|
|
73
|
+
return supersededError ?? 'Installed shortcut belongs to a newer CrewX version; refusing to modify it.';
|
|
74
|
+
}
|
|
75
|
+
const unconfirmedError = result.errors.find((e) => e.startsWith('GLOBAL_INSTALL_UNCONFIRMED:'));
|
|
76
|
+
if (!result.installedGlobal && unconfirmedError) {
|
|
77
|
+
return unconfirmedError;
|
|
78
|
+
}
|
|
79
|
+
if (result.errors.length > 0) {
|
|
80
|
+
return result.errors[0];
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Only these two re-detected states mean the Desktop truly has no CrewX
|
|
86
|
+
* shortcut left. Everything else — `foreign`/`superseded` (SDK refused to
|
|
87
|
+
* touch it) and `installed`/`stale` (the `.lnk` unlink threw and was
|
|
88
|
+
* swallowed as "already gone" — install.ts `uninstallShortcut`) — means the
|
|
89
|
+
* file is still on disk. A success ALLOWLIST is used instead of enumerating
|
|
90
|
+
* failure states so an unlink failure (EPERM/EBUSY/locked/AV hook) that
|
|
91
|
+
* re-detects back to `installed` fails closed by construction, rather than
|
|
92
|
+
* requiring every new failure path to be added to an exclusion list.
|
|
93
|
+
*/
|
|
94
|
+
const UNINSTALL_SUCCESS_STATES = new Set(['declined', 'not-installed']);
|
|
95
|
+
function uninstallFailureReason(result) {
|
|
96
|
+
if (UNINSTALL_SUCCESS_STATES.has(result.state)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const supersededError = result.errors.find((e) => e.startsWith('SUPERSEDED:'));
|
|
100
|
+
if (result.state === 'superseded' || supersededError) {
|
|
101
|
+
return supersededError ?? 'Installed shortcut belongs to a newer CrewX version; nothing was removed.';
|
|
102
|
+
}
|
|
103
|
+
if (result.state === 'foreign') {
|
|
104
|
+
const nsisError = result.errors.find((e) => e.startsWith('NSIS_PRESENT:'));
|
|
105
|
+
return nsisError ?? 'Existing Desktop shortcut is not managed by CrewX; nothing was removed.';
|
|
106
|
+
}
|
|
107
|
+
if (result.errors.length > 0) {
|
|
108
|
+
return result.errors[0];
|
|
109
|
+
}
|
|
110
|
+
return `CrewX desktop shortcut could not be removed (state: ${result.state}).`;
|
|
111
|
+
}
|
|
112
|
+
function printStatusHuman(status) {
|
|
113
|
+
switch (status.state) {
|
|
114
|
+
case 'unsupported':
|
|
115
|
+
console.log('Desktop shortcuts are only supported on Windows.');
|
|
116
|
+
break;
|
|
117
|
+
case 'not-installed':
|
|
118
|
+
console.log('No CrewX desktop shortcut installed yet.');
|
|
119
|
+
console.log('Run `crewx shortcut install` to create one.');
|
|
120
|
+
break;
|
|
121
|
+
case 'declined':
|
|
122
|
+
console.log('CrewX desktop shortcut setup was previously dismissed.');
|
|
123
|
+
console.log('Run `crewx shortcut install` to create one.');
|
|
124
|
+
break;
|
|
125
|
+
case 'installed':
|
|
126
|
+
console.log('✓ CrewX desktop shortcut is installed and up to date.');
|
|
127
|
+
if (status.shortcutPath)
|
|
128
|
+
console.log(` Shortcut: ${status.shortcutPath}`);
|
|
129
|
+
break;
|
|
130
|
+
case 'stale':
|
|
131
|
+
console.log('⚠ CrewX desktop shortcut needs an update.');
|
|
132
|
+
console.log('Run `crewx shortcut install` to refresh it.');
|
|
133
|
+
break;
|
|
134
|
+
case 'foreign':
|
|
135
|
+
console.log('⚠ A Desktop shortcut exists that CrewX does not manage.');
|
|
136
|
+
console.log('Run `crewx shortcut install --force` to replace it.');
|
|
137
|
+
break;
|
|
138
|
+
case 'superseded':
|
|
139
|
+
console.log('⚠ The installed shortcut belongs to a newer CrewX version than the one running.');
|
|
140
|
+
console.log('Update CrewX before touching the shortcut.');
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
for (const e of status.errors) {
|
|
144
|
+
console.log(` note: ${e}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function runStatus(args) {
|
|
148
|
+
const { json } = parseShortcutFlags(args, false);
|
|
149
|
+
let status;
|
|
150
|
+
try {
|
|
151
|
+
status = await (0, desktop_1.getShortcutStatus)();
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
failWithError(err, json);
|
|
155
|
+
}
|
|
156
|
+
if (json) {
|
|
157
|
+
printJson(status);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
printStatusHuman(status);
|
|
161
|
+
}
|
|
162
|
+
async function runInstall(args) {
|
|
163
|
+
const { json, force } = parseShortcutFlags(args, true);
|
|
164
|
+
let result;
|
|
165
|
+
try {
|
|
166
|
+
result = await (0, desktop_1.installShortcut)({ force, onProgress });
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
failWithError(err, json);
|
|
170
|
+
}
|
|
171
|
+
if (!result.supported) {
|
|
172
|
+
failNotWindows(json);
|
|
173
|
+
}
|
|
174
|
+
const failure = installFailureReason(result);
|
|
175
|
+
if (failure) {
|
|
176
|
+
if (json) {
|
|
177
|
+
printJson({ ...result, success: false });
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.error(`✗ ${failure}`);
|
|
181
|
+
}
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
if (json) {
|
|
185
|
+
printJson({ ...result, success: true });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (result.changed) {
|
|
189
|
+
console.log('✓ CrewX desktop shortcut installed. Double-click "CrewX" on your Desktop to launch it.');
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log('✓ CrewX desktop shortcut is already up to date. Double-click "CrewX" on your Desktop to launch it.');
|
|
193
|
+
}
|
|
194
|
+
if (result.shortcutPath)
|
|
195
|
+
console.log(` Shortcut: ${result.shortcutPath}`);
|
|
196
|
+
}
|
|
197
|
+
async function runUninstall(args) {
|
|
198
|
+
const { json } = parseShortcutFlags(args, false);
|
|
199
|
+
let result;
|
|
200
|
+
try {
|
|
201
|
+
result = await (0, desktop_1.uninstallShortcut)();
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
failWithError(err, json);
|
|
205
|
+
}
|
|
206
|
+
if (!result.supported) {
|
|
207
|
+
failNotWindows(json);
|
|
208
|
+
}
|
|
209
|
+
const failure = uninstallFailureReason(result);
|
|
210
|
+
if (failure) {
|
|
211
|
+
if (json) {
|
|
212
|
+
printJson({ ...result, success: false });
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.error(`✗ ${failure}`);
|
|
216
|
+
for (const e of result.errors) {
|
|
217
|
+
if (e !== failure)
|
|
218
|
+
console.error(` note: ${e}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
if (json) {
|
|
224
|
+
printJson({ ...result, success: true });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
console.log('✓ CrewX desktop shortcut removed.');
|
|
228
|
+
}
|
|
229
|
+
function printHelp() {
|
|
230
|
+
console.log(`
|
|
231
|
+
crewx shortcut — manage the Windows Desktop shortcut for CrewX
|
|
232
|
+
|
|
233
|
+
Usage:
|
|
234
|
+
crewx shortcut status [--json]
|
|
235
|
+
crewx shortcut install [--force] [--json]
|
|
236
|
+
crewx shortcut uninstall [--json]
|
|
237
|
+
|
|
238
|
+
Options:
|
|
239
|
+
--json Print machine-readable JSON to stdout (progress/log always go to stderr)
|
|
240
|
+
--force (install only) Overwrite a Desktop shortcut CrewX does not manage.
|
|
241
|
+
Never overwrites a shortcut created by a newer CrewX version.
|
|
242
|
+
|
|
243
|
+
Notes:
|
|
244
|
+
Windows only. On macOS/Linux, \`status\` reports state "unsupported" (exit 0);
|
|
245
|
+
\`install\`/\`uninstall\` exit 1 with no changes made.
|
|
246
|
+
`.trim());
|
|
247
|
+
}
|
|
248
|
+
async function handleShortcut(args) {
|
|
249
|
+
const subcommand = args[0];
|
|
250
|
+
if (!subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
251
|
+
printHelp();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const rest = args.slice(1);
|
|
255
|
+
switch (subcommand) {
|
|
256
|
+
case 'status':
|
|
257
|
+
return runStatus(rest);
|
|
258
|
+
case 'install':
|
|
259
|
+
return runInstall(rest);
|
|
260
|
+
case 'uninstall':
|
|
261
|
+
return runUninstall(rest);
|
|
262
|
+
default:
|
|
263
|
+
console.error(`Unknown shortcut subcommand: ${subcommand}`);
|
|
264
|
+
console.error('Run `crewx shortcut help` for usage.');
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -73,6 +73,7 @@ const restart_1 = require("./commands/restart");
|
|
|
73
73
|
const log_1 = require("./commands/log");
|
|
74
74
|
const doctor_1 = require("./commands/doctor");
|
|
75
75
|
const init_1 = require("./commands/init");
|
|
76
|
+
const shortcut_1 = require("./commands/shortcut");
|
|
76
77
|
const builtin_1 = require("./builtin");
|
|
77
78
|
const slack_1 = require("./commands/slack");
|
|
78
79
|
const install_1 = require("./commands/hook/install");
|
|
@@ -189,6 +190,10 @@ async function main() {
|
|
|
189
190
|
case 'db':
|
|
190
191
|
await (0, db_1.handleDb)(args.slice(1));
|
|
191
192
|
return;
|
|
193
|
+
// Windows Desktop shortcut: crewx shortcut status|install|uninstall
|
|
194
|
+
case 'shortcut':
|
|
195
|
+
await (0, shortcut_1.handleShortcut)(args.slice(1));
|
|
196
|
+
return;
|
|
192
197
|
// SDK-009: slack / slack:files
|
|
193
198
|
case 'slack':
|
|
194
199
|
case 'slack:files':
|
|
@@ -309,6 +314,11 @@ Database:
|
|
|
309
314
|
--force Reset migration history + skip confirmation
|
|
310
315
|
--dry-run Preview changes without applying
|
|
311
316
|
|
|
317
|
+
Desktop Shortcut (Windows only):
|
|
318
|
+
shortcut status [--json] Show current shortcut status
|
|
319
|
+
shortcut install [--force] [--json] Install/repair the Desktop shortcut
|
|
320
|
+
shortcut uninstall [--json] Remove the Desktop shortcut
|
|
321
|
+
|
|
312
322
|
Built-in Tools:
|
|
313
323
|
memory <args> Memory tool
|
|
314
324
|
search <args> Search tool
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/cli",
|
|
3
|
-
"version": "0.9.0-rc.
|
|
3
|
+
"version": "0.9.0-rc.42",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
"better-sqlite3": "*",
|
|
26
26
|
"dotenv": "17.2.3",
|
|
27
27
|
"isomorphic-git": "1.37.1",
|
|
28
|
-
"@crewx/sdk": "0.9.0-rc.
|
|
29
|
-
"@crewx/memory": "0.1.23-rc.
|
|
30
|
-
"@crewx/search": "0.1.10-rc.
|
|
31
|
-
"@crewx/doc": "0.1.9",
|
|
32
|
-
"@crewx/
|
|
33
|
-
"@crewx/cron": "0.1.10-rc.74",
|
|
34
|
-
"@crewx/workflow": "0.3.22-rc.86",
|
|
28
|
+
"@crewx/sdk": "0.9.0-rc.42",
|
|
29
|
+
"@crewx/memory": "0.1.23-rc.58",
|
|
30
|
+
"@crewx/search": "0.1.10-rc.37",
|
|
31
|
+
"@crewx/doc": "0.1.9-rc.34",
|
|
32
|
+
"@crewx/cron": "0.1.10-rc.76",
|
|
35
33
|
"@crewx/skill": "0.1.20",
|
|
36
|
-
"@crewx/
|
|
37
|
-
"@crewx/
|
|
38
|
-
"@crewx/
|
|
39
|
-
"@crewx/
|
|
34
|
+
"@crewx/workflow": "0.3.22-rc.88",
|
|
35
|
+
"@crewx/shared": "0.0.6",
|
|
36
|
+
"@crewx/wbs": "0.1.10-rc.67",
|
|
37
|
+
"@crewx/notify": "0.1.0-rc.12",
|
|
38
|
+
"@crewx/wi": "0.1.10-rc.62",
|
|
39
|
+
"@crewx/chromex": "0.1.0-rc.74"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/better-sqlite3": "*",
|