@mrpatronz/nexusflow 2.4.1 → 2.5.1
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/finish.d.ts.map +1 -1
- package/dist/commands/finish.js +7 -0
- package/dist/commands/finish.js.map +1 -1
- package/dist/commands/isolate.d.ts +12 -0
- package/dist/commands/isolate.d.ts.map +1 -0
- package/dist/commands/isolate.js +78 -0
- package/dist/commands/isolate.js.map +1 -0
- package/dist/commands/isolate.test.d.ts +2 -0
- package/dist/commands/isolate.test.d.ts.map +1 -0
- package/dist/commands/isolate.test.js +59 -0
- package/dist/commands/isolate.test.js.map +1 -0
- package/dist/commands/list.d.ts +3 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +5 -1
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/schedule.d.ts.map +1 -1
- package/dist/commands/schedule.js +6 -0
- package/dist/commands/schedule.js.map +1 -1
- package/dist/commands/ui.d.ts +2 -1
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +27 -7
- package/dist/commands/ui.js.map +1 -1
- package/dist/core/config-schema.d.ts +17 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +24 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +43 -5
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/isolate.d.ts +31 -0
- package/dist/core/isolate.d.ts.map +1 -0
- package/dist/core/isolate.js +175 -0
- package/dist/core/isolate.js.map +1 -0
- package/dist/core/isolate.test.d.ts +2 -0
- package/dist/core/isolate.test.d.ts.map +1 -0
- package/dist/core/isolate.test.js +290 -0
- package/dist/core/isolate.test.js.map +1 -0
- package/dist/core/refresh.d.ts.map +1 -1
- package/dist/core/refresh.js +19 -16
- package/dist/core/refresh.js.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/sync.js +21 -7
- package/dist/core/sync.js.map +1 -1
- package/dist/core/workspace.d.ts +6 -0
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +27 -4
- package/dist/core/workspace.js.map +1 -1
- package/dist/core/worktree.d.ts.map +1 -1
- package/dist/core/worktree.js +7 -0
- package/dist/core/worktree.js.map +1 -1
- package/dist/desktop-server.js +2 -1
- package/dist/desktop-server.js.map +1 -1
- package/dist/generators/base.d.ts.map +1 -1
- package/dist/generators/base.js +13 -5
- package/dist/generators/base.js.map +1 -1
- package/dist/generators/base.test.js +1 -1
- package/dist/generators/base.test.js.map +1 -1
- package/dist/gui/assets/{AgentsPage-BNHR9qux.js → AgentsPage-gHbRof2y.js} +1 -1
- package/dist/gui/assets/{DashboardPage-BScH3Cxp.js → DashboardPage-CkXIpoFX.js} +1 -1
- package/dist/gui/assets/{GettingStartedPage-AWlI-176.js → GettingStartedPage-DRL_nbb6.js} +1 -1
- package/dist/gui/assets/{ProjectsPage-Bojj7gxI.js → ProjectsPage-C8XQ9dRr.js} +1 -1
- package/dist/gui/assets/{ScaffoldRepoInline-DJMbeHVM.js → ScaffoldRepoInline-ys4l8ho4.js} +1 -1
- package/dist/gui/assets/{SettingsPage-BAdXO8X0.js → SettingsPage-CRVDsRwi.js} +1 -1
- package/dist/gui/assets/{SkillsPage-CF6Db1FA.js → SkillsPage-BfQu6PT3.js} +1 -1
- package/dist/gui/assets/StartWorkPage-BNzeMcFc.js +1 -0
- package/dist/gui/assets/{StrategiesPage-nGbR9TAc.js → StrategiesPage-Bh6x7zhl.js} +1 -1
- package/dist/gui/assets/{WorkspacesPage-7XRtVJNF.js → WorkspacesPage-DYQt7CQ8.js} +1 -1
- package/dist/gui/assets/{alert-dialog-67uzXJi4.js → alert-dialog-D7jNzvYQ.js} +1 -1
- package/dist/gui/assets/{index-V1dDX1O_.js → index-C6qbn9Zq.js} +3 -3
- package/dist/gui/assets/{vsc-Di05BTNr.js → vsc-CvlJSs-5.js} +1 -1
- package/dist/gui/index.html +1 -1
- package/dist/index.js +124 -489
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +47 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/tools.test.d.ts +2 -0
- package/dist/mcp/tools.test.d.ts.map +1 -0
- package/dist/mcp/tools.test.js +70 -0
- package/dist/mcp/tools.test.js.map +1 -0
- package/dist/orchestration/orchestrator.js +2 -2
- package/dist/orchestration/orchestrator.js.map +1 -1
- package/dist/orchestration/orchestrator.test.js +1 -1
- package/dist/orchestration/orchestrator.test.js.map +1 -1
- package/dist/orchestration/runner.d.ts +5 -1
- package/dist/orchestration/runner.d.ts.map +1 -1
- package/dist/orchestration/runner.js +14 -4
- package/dist/orchestration/runner.js.map +1 -1
- package/dist/orchestration/runner.test.js +22 -16
- package/dist/orchestration/runner.test.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +110 -11
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +74 -1
- package/dist/server.test.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/feature.d.ts +10 -1
- package/dist/utils/feature.d.ts.map +1 -1
- package/dist/utils/feature.js +36 -4
- package/dist/utils/feature.js.map +1 -1
- package/dist/utils/session-finder.d.ts +2 -0
- package/dist/utils/session-finder.d.ts.map +1 -1
- package/dist/utils/session-finder.js +13 -0
- package/dist/utils/session-finder.js.map +1 -1
- package/package.json +6 -4
- package/dist/gui/assets/StartWorkPage-BQid3uIw.js +0 -1
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import { loadConfig } from './core/config.js';
|
|
|
27
27
|
import { debugLog } from './utils/debug.js';
|
|
28
28
|
import { loadPlugins } from './core/plugins/loader.js';
|
|
29
29
|
import { addRepoCommand } from './commands/add-repo.js';
|
|
30
|
+
import { isolateCommand } from './commands/isolate.js';
|
|
30
31
|
import { mcpRunCommand, mcpSetupCommand } from './commands/mcp.js';
|
|
31
32
|
import { handoffCommand } from './commands/handoff.js';
|
|
32
33
|
import { refreshCommand } from './commands/refresh.js';
|
|
@@ -53,136 +54,83 @@ program.hook('preAction', (thisCommand) => {
|
|
|
53
54
|
process.env.NEXUSFLOW_DEBUG = '1';
|
|
54
55
|
}
|
|
55
56
|
});
|
|
57
|
+
function isDebugMode() {
|
|
58
|
+
return process.argv.includes('--debug') || Boolean(process.env.NEXUSFLOW_DEBUG);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Wraps a command action: clean exit on prompt cancellation (Ctrl+C inside an
|
|
62
|
+
* inquirer prompt), clean red error message by default, and exit code 1.
|
|
63
|
+
* When --debug is provided, prints the full error stack.
|
|
64
|
+
*/
|
|
65
|
+
function runAction(fn) {
|
|
66
|
+
return async (...args) => {
|
|
67
|
+
try {
|
|
68
|
+
await fn(...args);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
72
|
+
console.log('\nCancelled.');
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
+
console.error(chalk.red(`\n✖ ${message}`));
|
|
77
|
+
if (isDebugMode() && error instanceof Error && error.stack) {
|
|
78
|
+
console.error(chalk.dim(error.stack));
|
|
79
|
+
}
|
|
80
|
+
else if (!isDebugMode()) {
|
|
81
|
+
console.error(chalk.dim(' (Run with --debug for details)\n'));
|
|
82
|
+
}
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
56
87
|
program
|
|
57
88
|
.command('create')
|
|
58
89
|
.description('Create a new feature workspace — pick repos, pick AI assistants, generate context')
|
|
59
|
-
.action(
|
|
60
|
-
try {
|
|
61
|
-
await createCommand();
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
65
|
-
console.log('\nCancelled.');
|
|
66
|
-
process.exit(0);
|
|
67
|
-
}
|
|
68
|
-
console.error(error);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
90
|
+
.action(runAction(createCommand));
|
|
72
91
|
program
|
|
73
92
|
.command('list')
|
|
74
93
|
.alias('ls')
|
|
75
94
|
.description('List all existing workspaces')
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
await listCommand();
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
console.error(error);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
95
|
+
.option('--json', 'Output as JSON')
|
|
96
|
+
.action(runAction(listCommand));
|
|
85
97
|
program
|
|
86
98
|
.command('open')
|
|
87
99
|
.description('Re-open an existing workspace in an editor')
|
|
88
|
-
.action(
|
|
89
|
-
try {
|
|
90
|
-
await openCommand();
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
94
|
-
console.log('\nCancelled.');
|
|
95
|
-
process.exit(0);
|
|
96
|
-
}
|
|
97
|
-
console.error(error);
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
100
|
+
.action(runAction(openCommand));
|
|
101
101
|
program
|
|
102
102
|
.command('init')
|
|
103
103
|
.description('Initialize NexusFlow configuration')
|
|
104
|
-
.action(
|
|
105
|
-
try {
|
|
106
|
-
await initCommand();
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
110
|
-
console.log('\nCancelled.');
|
|
111
|
-
process.exit(0);
|
|
112
|
-
}
|
|
113
|
-
console.error(error);
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
104
|
+
.action(runAction(initCommand));
|
|
117
105
|
program
|
|
118
106
|
.command('start')
|
|
119
107
|
.description('Start all services in a workspace')
|
|
120
108
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
121
|
-
.action(async (workspace) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
127
|
-
console.log('\nCancelled.');
|
|
128
|
-
process.exit(0);
|
|
129
|
-
}
|
|
130
|
-
console.error(error);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
109
|
+
.action(runAction(async (workspace) => {
|
|
110
|
+
await startCommand(workspace);
|
|
111
|
+
}));
|
|
134
112
|
program
|
|
135
113
|
.command('stop')
|
|
136
114
|
.description('Stop all running services in a workspace')
|
|
137
115
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
138
|
-
.action(async (workspace) => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
144
|
-
console.log('\nCancelled.');
|
|
145
|
-
process.exit(0);
|
|
146
|
-
}
|
|
147
|
-
console.error(error);
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
116
|
+
.action(runAction(async (workspace) => {
|
|
117
|
+
await stopCommand(workspace);
|
|
118
|
+
}));
|
|
151
119
|
program
|
|
152
120
|
.command('logs')
|
|
153
121
|
.description('Show logs from running services')
|
|
154
122
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
155
123
|
.option('-n, --lines <number>', 'Number of lines per service', '30')
|
|
156
|
-
.action(async (workspace, options) => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
162
|
-
console.log('\nCancelled.');
|
|
163
|
-
process.exit(0);
|
|
164
|
-
}
|
|
165
|
-
console.error(error);
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
124
|
+
.action(runAction(async (workspace, options) => {
|
|
125
|
+
await logsCommand(workspace, parseInt(options.lines, 10));
|
|
126
|
+
}));
|
|
169
127
|
program
|
|
170
128
|
.command('status')
|
|
171
129
|
.description('Show status of running services')
|
|
172
130
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
173
|
-
.action(async (workspace) => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
179
|
-
console.log('\nCancelled.');
|
|
180
|
-
process.exit(0);
|
|
181
|
-
}
|
|
182
|
-
console.error(error);
|
|
183
|
-
process.exit(1);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
131
|
+
.action(runAction(async (workspace) => {
|
|
132
|
+
await statusCommand(workspace);
|
|
133
|
+
}));
|
|
186
134
|
program
|
|
187
135
|
.command('ui')
|
|
188
136
|
.description('Start the NexusFlow dashboard server (the backend the desktop app embeds)')
|
|
@@ -191,15 +139,9 @@ program
|
|
|
191
139
|
.option('--open', 'Also open the dashboard in your default browser')
|
|
192
140
|
.option('--server-only', '(deprecated — server-only is now the default)')
|
|
193
141
|
.option('--strict-port', 'Fail instead of auto-incrementing when the port is in use')
|
|
194
|
-
.action(async (options) => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
console.error(error);
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
});
|
|
142
|
+
.action(runAction(async (options) => {
|
|
143
|
+
await uiCommand(options);
|
|
144
|
+
}));
|
|
203
145
|
program
|
|
204
146
|
.command('dashboard')
|
|
205
147
|
.alias('dash')
|
|
@@ -270,98 +212,61 @@ program
|
|
|
270
212
|
.description('Display a unified summary of changes across all repositories (including unpushed commits)')
|
|
271
213
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
272
214
|
.option('-r, --repo <repos...>', 'Only show the given repositories (by name)')
|
|
273
|
-
.action(async (workspace, options) => {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
catch (error) {
|
|
278
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
279
|
-
console.log('\nCancelled.');
|
|
280
|
-
process.exit(0);
|
|
281
|
-
}
|
|
282
|
-
console.error(error);
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
});
|
|
215
|
+
.action(runAction(async (workspace, options) => {
|
|
216
|
+
await diffCommand(workspace, options);
|
|
217
|
+
}));
|
|
286
218
|
// Pack command removed.
|
|
287
219
|
program
|
|
288
220
|
.command('remove')
|
|
289
221
|
.alias('rm')
|
|
290
222
|
.description('Delete a workspace and cleanly prune/remove its git worktrees')
|
|
291
223
|
.argument('[workspace]', 'Workspace name or path')
|
|
292
|
-
.action(async (workspace) => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
298
|
-
console.log('\nCancelled.');
|
|
299
|
-
process.exit(0);
|
|
300
|
-
}
|
|
301
|
-
console.error(error);
|
|
302
|
-
process.exit(1);
|
|
303
|
-
}
|
|
304
|
-
});
|
|
224
|
+
.action(runAction(async (workspace) => {
|
|
225
|
+
await removeCommand(workspace);
|
|
226
|
+
}));
|
|
305
227
|
program
|
|
306
228
|
.command('add-repo')
|
|
307
229
|
.alias('add')
|
|
308
230
|
.description('Add a repository to an existing workspace and update configurations')
|
|
309
231
|
.argument('[repo-path]', 'Path to the repository to add')
|
|
310
232
|
.argument('[workspace]', 'Workspace name or path')
|
|
311
|
-
.action(async (repoPath, workspace) => {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
233
|
+
.action(runAction(async (repoPath, workspace) => {
|
|
234
|
+
await addRepoCommand(repoPath, workspace);
|
|
235
|
+
}));
|
|
236
|
+
program
|
|
237
|
+
.command('isolate')
|
|
238
|
+
.description('Dynamically isolate a repository in an in-place workspace into a dedicated worktree on demand')
|
|
239
|
+
.argument('[repo]', 'Name or path of the repository to isolate')
|
|
240
|
+
.argument('[branch]', 'Target feature branch name')
|
|
241
|
+
.option('-b, --branch <branch>', 'Target feature branch name')
|
|
242
|
+
.option('--base <base>', 'Base branch to branch off')
|
|
243
|
+
.option('-w, --workspace <workspace>', 'Workspace name or path')
|
|
244
|
+
.action(runAction(async (repo, branchArg, options) => {
|
|
245
|
+
await isolateCommand(repo, branchArg, options);
|
|
246
|
+
}));
|
|
324
247
|
program
|
|
325
248
|
.command('handoff')
|
|
326
249
|
.description('Generate a compact handoff bundle (nexusflow-handoff.md) for session resumption')
|
|
327
250
|
.argument('[workspace]', 'Path to the workspace')
|
|
328
|
-
.action(async (workspace) => {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
console.error(error);
|
|
334
|
-
process.exit(1);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
251
|
+
.action(runAction(async (workspace) => {
|
|
252
|
+
await handoffCommand(workspace);
|
|
253
|
+
}));
|
|
337
254
|
program
|
|
338
255
|
.command('refresh')
|
|
339
256
|
.description('Refresh workspace context, plan and handoff files (re-analyzes only changed repos)')
|
|
340
257
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
341
258
|
.option('-f, --force', 'Ignore the analysis cache and re-analyze every repository')
|
|
342
259
|
.option('-s, --strategy <id>', 'Update the teamwork strategy (use template ID, or "auto" for AI suggestion)')
|
|
343
|
-
.action(async (workspace, options) => {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
catch (error) {
|
|
348
|
-
console.error(error);
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
260
|
+
.action(runAction(async (workspace, options) => {
|
|
261
|
+
await refreshCommand(options, workspace);
|
|
262
|
+
}));
|
|
352
263
|
program
|
|
353
264
|
.command('doctor')
|
|
354
265
|
.description('Run diagnostics to verify workspace health and check for local loop issues')
|
|
355
266
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
356
|
-
.action(async (workspace) => {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
catch (error) {
|
|
361
|
-
console.error(error);
|
|
362
|
-
process.exit(1);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
267
|
+
.action(runAction(async (workspace) => {
|
|
268
|
+
await doctorCommand(workspace);
|
|
269
|
+
}));
|
|
365
270
|
program
|
|
366
271
|
.command('finish')
|
|
367
272
|
.description('Finish a feature — commit & push everything, open PRs, promote learnings, optionally remove the workspace')
|
|
@@ -372,19 +277,9 @@ program
|
|
|
372
277
|
.option('--cleanup', 'Remove the workspace after everything is confirmed pushed (still asks for confirmation)')
|
|
373
278
|
.option('-y, --yes', 'Accept defaults for non-destructive prompts')
|
|
374
279
|
.option('--dry-run', 'Show what finish would do without changing anything')
|
|
375
|
-
.action(async (workspace, options) => {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
381
|
-
console.log('\nCancelled.');
|
|
382
|
-
process.exit(0);
|
|
383
|
-
}
|
|
384
|
-
console.error(error);
|
|
385
|
-
process.exit(1);
|
|
386
|
-
}
|
|
387
|
-
});
|
|
280
|
+
.action(runAction(async (workspace, options) => {
|
|
281
|
+
await finishCommand(workspace, options);
|
|
282
|
+
}));
|
|
388
283
|
// Knowledge command group
|
|
389
284
|
const knowledgeCmd = program
|
|
390
285
|
.command('knowledge')
|
|
@@ -398,38 +293,18 @@ knowledgeCmd
|
|
|
398
293
|
.requiredOption('-m, --message <msg>', 'The learning to record, as a rule plus its reason (max 300 chars)')
|
|
399
294
|
.option('--title <title>', 'Short title (used for decision headings)')
|
|
400
295
|
.option('-r, --repo <repo>', "Write to this repo's persistent base knowledge instead")
|
|
401
|
-
.action(async (workspace, options) => {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
catch (error) {
|
|
406
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
407
|
-
console.log('\nCancelled.');
|
|
408
|
-
process.exit(0);
|
|
409
|
-
}
|
|
410
|
-
console.error(error);
|
|
411
|
-
process.exit(1);
|
|
412
|
-
}
|
|
413
|
-
});
|
|
296
|
+
.action(runAction(async (workspace, options) => {
|
|
297
|
+
await knowledgeAddCommand(workspace, options);
|
|
298
|
+
}));
|
|
414
299
|
knowledgeCmd
|
|
415
300
|
.command('show')
|
|
416
301
|
.description("Print the workspace knowledge file (or a repo's base knowledge)")
|
|
417
302
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
418
303
|
.option('-s, --section <name>', 'Only show one section')
|
|
419
304
|
.option('-r, --repo <repo>', "Show the repo's base knowledge file instead")
|
|
420
|
-
.action(async (workspace, options) => {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
catch (error) {
|
|
425
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
426
|
-
console.log('\nCancelled.');
|
|
427
|
-
process.exit(0);
|
|
428
|
-
}
|
|
429
|
-
console.error(error);
|
|
430
|
-
process.exit(1);
|
|
431
|
-
}
|
|
432
|
-
});
|
|
305
|
+
.action(runAction(async (workspace, options) => {
|
|
306
|
+
await knowledgeShowCommand(workspace, options);
|
|
307
|
+
}));
|
|
433
308
|
knowledgeCmd
|
|
434
309
|
.command('promote')
|
|
435
310
|
.description('Copy workspace learnings into per-repo base knowledge so they persist across features')
|
|
@@ -439,39 +314,9 @@ knowledgeCmd
|
|
|
439
314
|
.option('-m, --message <msg>', 'Promote this text directly (non-interactive)')
|
|
440
315
|
.option('--move', 'Remove the entry from the workspace file after promoting (default: copy)')
|
|
441
316
|
.option('--all', 'Promote all decisions, gotchas and assumptions without prompting')
|
|
442
|
-
.action(async (workspace, options) => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
catch (error) {
|
|
447
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
448
|
-
console.log('\nCancelled.');
|
|
449
|
-
process.exit(0);
|
|
450
|
-
}
|
|
451
|
-
console.error(error);
|
|
452
|
-
process.exit(1);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
/**
|
|
456
|
-
* Wraps a command action: clean exit on prompt cancellation (Ctrl+C inside an
|
|
457
|
-
* inquirer prompt), exit code 1 with the error otherwise. New command
|
|
458
|
-
* registrations should use this instead of copy-pasting the try/catch.
|
|
459
|
-
*/
|
|
460
|
-
function runAction(fn) {
|
|
461
|
-
return async (...args) => {
|
|
462
|
-
try {
|
|
463
|
-
await fn(...args);
|
|
464
|
-
}
|
|
465
|
-
catch (error) {
|
|
466
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
467
|
-
console.log('\nCancelled.');
|
|
468
|
-
process.exit(0);
|
|
469
|
-
}
|
|
470
|
-
console.error(error);
|
|
471
|
-
process.exit(1);
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
}
|
|
317
|
+
.action(runAction(async (workspace, options) => {
|
|
318
|
+
await knowledgePromoteCommand(workspace, options);
|
|
319
|
+
}));
|
|
475
320
|
// Project command group
|
|
476
321
|
const projectCmd = program
|
|
477
322
|
.command('project')
|
|
@@ -510,216 +355,76 @@ strategyCmd
|
|
|
510
355
|
.command('list')
|
|
511
356
|
.alias('ls')
|
|
512
357
|
.description('List all available strategy templates (built-in and custom)')
|
|
513
|
-
.action(
|
|
514
|
-
try {
|
|
515
|
-
await strategyListCommand();
|
|
516
|
-
}
|
|
517
|
-
catch (error) {
|
|
518
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
519
|
-
console.log('\nCancelled.');
|
|
520
|
-
process.exit(0);
|
|
521
|
-
}
|
|
522
|
-
console.error(error);
|
|
523
|
-
process.exit(1);
|
|
524
|
-
}
|
|
525
|
-
});
|
|
358
|
+
.action(runAction(strategyListCommand));
|
|
526
359
|
strategyCmd
|
|
527
360
|
.command('create')
|
|
528
361
|
.description('Create a new custom strategy template')
|
|
529
362
|
.option('-n, --name <name>', 'Strategy name')
|
|
530
363
|
.option('-f, --file <path>', 'Load content from a .md or .txt file')
|
|
531
|
-
.action(
|
|
532
|
-
try {
|
|
533
|
-
await strategyCreateCommand(options);
|
|
534
|
-
}
|
|
535
|
-
catch (error) {
|
|
536
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
537
|
-
console.log('\nCancelled.');
|
|
538
|
-
process.exit(0);
|
|
539
|
-
}
|
|
540
|
-
console.error(error);
|
|
541
|
-
process.exit(1);
|
|
542
|
-
}
|
|
543
|
-
});
|
|
364
|
+
.action(runAction(strategyCreateCommand));
|
|
544
365
|
strategyCmd
|
|
545
366
|
.command('edit')
|
|
546
367
|
.description('Edit an existing custom strategy template')
|
|
547
368
|
.option('--id <id>', 'Template ID to edit (skips the selection prompt)')
|
|
548
|
-
.action(
|
|
549
|
-
try {
|
|
550
|
-
await strategyEditCommand(options);
|
|
551
|
-
}
|
|
552
|
-
catch (error) {
|
|
553
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
554
|
-
console.log('\nCancelled.');
|
|
555
|
-
process.exit(0);
|
|
556
|
-
}
|
|
557
|
-
console.error(error);
|
|
558
|
-
process.exit(1);
|
|
559
|
-
}
|
|
560
|
-
});
|
|
369
|
+
.action(runAction(strategyEditCommand));
|
|
561
370
|
strategyCmd
|
|
562
371
|
.command('delete')
|
|
563
372
|
.alias('rm')
|
|
564
373
|
.description('Delete a custom strategy template')
|
|
565
374
|
.option('--id <id>', 'Template ID to delete (skips the selection prompt)')
|
|
566
375
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
567
|
-
.action(
|
|
568
|
-
try {
|
|
569
|
-
await strategyDeleteCommand(options);
|
|
570
|
-
}
|
|
571
|
-
catch (error) {
|
|
572
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
573
|
-
console.log('\nCancelled.');
|
|
574
|
-
process.exit(0);
|
|
575
|
-
}
|
|
576
|
-
console.error(error);
|
|
577
|
-
process.exit(1);
|
|
578
|
-
}
|
|
579
|
-
});
|
|
376
|
+
.action(runAction(strategyDeleteCommand));
|
|
580
377
|
strategyCmd
|
|
581
378
|
.command('show')
|
|
582
379
|
.description('Display the full content of a strategy template')
|
|
583
380
|
.option('--id <id>', 'Template ID to show (skips the selection prompt)')
|
|
584
|
-
.action(
|
|
585
|
-
try {
|
|
586
|
-
await strategyShowCommand(options);
|
|
587
|
-
}
|
|
588
|
-
catch (error) {
|
|
589
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
590
|
-
console.log('\nCancelled.');
|
|
591
|
-
process.exit(0);
|
|
592
|
-
}
|
|
593
|
-
console.error(error);
|
|
594
|
-
process.exit(1);
|
|
595
|
-
}
|
|
596
|
-
});
|
|
381
|
+
.action(runAction(strategyShowCommand));
|
|
597
382
|
program
|
|
598
383
|
.command('desktop')
|
|
599
384
|
.description('Launch the NexusFlow desktop application')
|
|
600
|
-
.action(
|
|
601
|
-
try {
|
|
602
|
-
await desktopCommand();
|
|
603
|
-
}
|
|
604
|
-
catch (error) {
|
|
605
|
-
console.error(error);
|
|
606
|
-
process.exit(1);
|
|
607
|
-
}
|
|
608
|
-
});
|
|
385
|
+
.action(runAction(desktopCommand));
|
|
609
386
|
// Config command group
|
|
610
387
|
const configCmd = program.command('config').description('View and update NexusFlow configuration');
|
|
611
388
|
configCmd
|
|
612
389
|
.command('show')
|
|
613
390
|
.description('Display the current configuration')
|
|
614
|
-
.action(
|
|
615
|
-
try {
|
|
616
|
-
await configShowCommand();
|
|
617
|
-
}
|
|
618
|
-
catch (error) {
|
|
619
|
-
console.error(error);
|
|
620
|
-
process.exit(1);
|
|
621
|
-
}
|
|
622
|
-
});
|
|
391
|
+
.action(runAction(configShowCommand));
|
|
623
392
|
configCmd
|
|
624
393
|
.command('get')
|
|
625
394
|
.description('Get a specific configuration key')
|
|
626
395
|
.argument('<key>', 'Configuration key to read')
|
|
627
|
-
.action(
|
|
628
|
-
try {
|
|
629
|
-
await configGetCommand(key);
|
|
630
|
-
}
|
|
631
|
-
catch (error) {
|
|
632
|
-
console.error(error);
|
|
633
|
-
process.exit(1);
|
|
634
|
-
}
|
|
635
|
-
});
|
|
396
|
+
.action(runAction(configGetCommand));
|
|
636
397
|
configCmd
|
|
637
398
|
.command('set')
|
|
638
399
|
.description('Set a configuration key to a value')
|
|
639
400
|
.argument('<key>', 'Configuration key to set')
|
|
640
401
|
.argument('<value>', 'Value to assign')
|
|
641
|
-
.action(
|
|
642
|
-
try {
|
|
643
|
-
await configSetCommand(key, value);
|
|
644
|
-
}
|
|
645
|
-
catch (error) {
|
|
646
|
-
console.error(error);
|
|
647
|
-
process.exit(1);
|
|
648
|
-
}
|
|
649
|
-
});
|
|
402
|
+
.action(runAction(configSetCommand));
|
|
650
403
|
// Default action when 'nexusflow config' is run without a subcommand
|
|
651
|
-
configCmd.action(
|
|
652
|
-
try {
|
|
653
|
-
await configShowCommand();
|
|
654
|
-
}
|
|
655
|
-
catch (error) {
|
|
656
|
-
console.error(error);
|
|
657
|
-
process.exit(1);
|
|
658
|
-
}
|
|
659
|
-
});
|
|
404
|
+
configCmd.action(runAction(configShowCommand));
|
|
660
405
|
// Adapter command group
|
|
661
406
|
const adapterCmd = program.command('adapter').description('Manage storage adapters — list, switch, configure, or create new ones');
|
|
662
407
|
adapterCmd
|
|
663
408
|
.command('list')
|
|
664
409
|
.description('List all available storage adapters')
|
|
665
|
-
.action(
|
|
666
|
-
try {
|
|
667
|
-
await adapterListCommand();
|
|
668
|
-
}
|
|
669
|
-
catch (error) {
|
|
670
|
-
console.error(error);
|
|
671
|
-
process.exit(1);
|
|
672
|
-
}
|
|
673
|
-
});
|
|
410
|
+
.action(runAction(adapterListCommand));
|
|
674
411
|
adapterCmd
|
|
675
412
|
.command('use')
|
|
676
413
|
.description('Switch to a different storage adapter (prompts for config if needed)')
|
|
677
414
|
.argument('<name>', 'Adapter name to activate')
|
|
678
|
-
.action(
|
|
679
|
-
try {
|
|
680
|
-
await adapterUseCommand(name);
|
|
681
|
-
}
|
|
682
|
-
catch (error) {
|
|
683
|
-
console.error(error);
|
|
684
|
-
process.exit(1);
|
|
685
|
-
}
|
|
686
|
-
});
|
|
415
|
+
.action(runAction(adapterUseCommand));
|
|
687
416
|
adapterCmd
|
|
688
417
|
.command('info')
|
|
689
418
|
.description('Show detailed information about an adapter')
|
|
690
419
|
.argument('<name>', 'Adapter name to inspect')
|
|
691
|
-
.action(
|
|
692
|
-
try {
|
|
693
|
-
await adapterInfoCommand(name);
|
|
694
|
-
}
|
|
695
|
-
catch (error) {
|
|
696
|
-
console.error(error);
|
|
697
|
-
process.exit(1);
|
|
698
|
-
}
|
|
699
|
-
});
|
|
420
|
+
.action(runAction(adapterInfoCommand));
|
|
700
421
|
adapterCmd
|
|
701
422
|
.command('init')
|
|
702
423
|
.description('Scaffold a new adapter plugin project')
|
|
703
424
|
.argument('<name>', 'Name for the new adapter')
|
|
704
|
-
.action(
|
|
705
|
-
try {
|
|
706
|
-
await adapterInitCommand(name);
|
|
707
|
-
}
|
|
708
|
-
catch (error) {
|
|
709
|
-
console.error(error);
|
|
710
|
-
process.exit(1);
|
|
711
|
-
}
|
|
712
|
-
});
|
|
425
|
+
.action(runAction(adapterInitCommand));
|
|
713
426
|
// Default action when 'nexusflow adapter' is run without a subcommand
|
|
714
|
-
adapterCmd.action(
|
|
715
|
-
try {
|
|
716
|
-
await adapterListCommand();
|
|
717
|
-
}
|
|
718
|
-
catch (error) {
|
|
719
|
-
console.error(error);
|
|
720
|
-
process.exit(1);
|
|
721
|
-
}
|
|
722
|
-
});
|
|
427
|
+
adapterCmd.action(runAction(adapterListCommand));
|
|
723
428
|
// Schedule command group
|
|
724
429
|
const scheduleCmd = program
|
|
725
430
|
.command('schedule')
|
|
@@ -730,124 +435,54 @@ scheduleCmd
|
|
|
730
435
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
731
436
|
.option('-t, --task <task>', 'Job to run: "sync" or "refresh"', 'sync')
|
|
732
437
|
.requiredOption('-e, --every <interval>', 'How often to run, e.g. 30m, 2h, 1d')
|
|
733
|
-
.action(async (workspace, options) => {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
}
|
|
737
|
-
catch (error) {
|
|
738
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
739
|
-
console.log('\nCancelled.');
|
|
740
|
-
process.exit(0);
|
|
741
|
-
}
|
|
742
|
-
console.error(error);
|
|
743
|
-
process.exit(1);
|
|
744
|
-
}
|
|
745
|
-
});
|
|
438
|
+
.action(runAction(async (workspace, options) => {
|
|
439
|
+
await scheduleAddCommand(workspace, options);
|
|
440
|
+
}));
|
|
746
441
|
scheduleCmd
|
|
747
442
|
.command('list')
|
|
748
443
|
.alias('ls')
|
|
749
444
|
.description('List all scheduled jobs')
|
|
750
|
-
.action(
|
|
751
|
-
try {
|
|
752
|
-
await scheduleListCommand();
|
|
753
|
-
}
|
|
754
|
-
catch (error) {
|
|
755
|
-
console.error(error);
|
|
756
|
-
process.exit(1);
|
|
757
|
-
}
|
|
758
|
-
});
|
|
445
|
+
.action(runAction(scheduleListCommand));
|
|
759
446
|
scheduleCmd
|
|
760
447
|
.command('remove')
|
|
761
448
|
.alias('rm')
|
|
762
449
|
.description('Remove a scheduled job')
|
|
763
450
|
.argument('<id>', 'Job id (see "nexusflow schedule list")')
|
|
764
|
-
.action(
|
|
765
|
-
try {
|
|
766
|
-
await scheduleRemoveCommand(id);
|
|
767
|
-
}
|
|
768
|
-
catch (error) {
|
|
769
|
-
console.error(error);
|
|
770
|
-
process.exit(1);
|
|
771
|
-
}
|
|
772
|
-
});
|
|
451
|
+
.action(runAction(scheduleRemoveCommand));
|
|
773
452
|
scheduleCmd
|
|
774
453
|
.command('enable')
|
|
775
454
|
.description('Enable a scheduled job')
|
|
776
455
|
.argument('<id>', 'Job id (see "nexusflow schedule list")')
|
|
777
|
-
.action(async (id) => {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
}
|
|
781
|
-
catch (error) {
|
|
782
|
-
console.error(error);
|
|
783
|
-
process.exit(1);
|
|
784
|
-
}
|
|
785
|
-
});
|
|
456
|
+
.action(runAction(async (id) => {
|
|
457
|
+
await scheduleToggleCommand(id, true);
|
|
458
|
+
}));
|
|
786
459
|
scheduleCmd
|
|
787
460
|
.command('disable')
|
|
788
461
|
.description('Disable a scheduled job without removing it')
|
|
789
462
|
.argument('<id>', 'Job id (see "nexusflow schedule list")')
|
|
790
|
-
.action(async (id) => {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
catch (error) {
|
|
795
|
-
console.error(error);
|
|
796
|
-
process.exit(1);
|
|
797
|
-
}
|
|
798
|
-
});
|
|
463
|
+
.action(runAction(async (id) => {
|
|
464
|
+
await scheduleToggleCommand(id, false);
|
|
465
|
+
}));
|
|
799
466
|
scheduleCmd
|
|
800
467
|
.command('run')
|
|
801
468
|
.description('Run a scheduled job immediately')
|
|
802
469
|
.argument('<id>', 'Job id (see "nexusflow schedule list")')
|
|
803
|
-
.action(
|
|
804
|
-
try {
|
|
805
|
-
await scheduleRunCommand(id);
|
|
806
|
-
}
|
|
807
|
-
catch (error) {
|
|
808
|
-
console.error(error);
|
|
809
|
-
process.exit(1);
|
|
810
|
-
}
|
|
811
|
-
});
|
|
470
|
+
.action(runAction(scheduleRunCommand));
|
|
812
471
|
// Default action when 'nexusflow schedule' is run without a subcommand
|
|
813
|
-
scheduleCmd.action(
|
|
814
|
-
try {
|
|
815
|
-
await scheduleListCommand();
|
|
816
|
-
}
|
|
817
|
-
catch (error) {
|
|
818
|
-
console.error(error);
|
|
819
|
-
process.exit(1);
|
|
820
|
-
}
|
|
821
|
-
});
|
|
472
|
+
scheduleCmd.action(runAction(scheduleListCommand));
|
|
822
473
|
const mcp = program.command('mcp').description('Manage the NexusFlow MCP Server for AI assistants');
|
|
823
474
|
mcp
|
|
824
475
|
.command('run')
|
|
825
476
|
.description('Start the NexusFlow MCP Server (typically called automatically by AI assistants)')
|
|
826
477
|
.argument('[workspace]', 'Path to workspace (auto-detects from CWD)')
|
|
827
|
-
.action(
|
|
828
|
-
try {
|
|
829
|
-
await mcpRunCommand(workspace);
|
|
830
|
-
}
|
|
831
|
-
catch (error) {
|
|
832
|
-
console.error(error);
|
|
833
|
-
process.exit(1);
|
|
834
|
-
}
|
|
835
|
-
});
|
|
478
|
+
.action(runAction(mcpRunCommand));
|
|
836
479
|
mcp
|
|
837
480
|
.command('setup')
|
|
838
481
|
.description('Automatically configure your AI environments (Claude Desktop, Cursor, VS Code) to use the NexusFlow MCP Server')
|
|
839
|
-
.action(
|
|
840
|
-
try {
|
|
841
|
-
await mcpSetupCommand();
|
|
842
|
-
}
|
|
843
|
-
catch (error) {
|
|
844
|
-
console.error(error);
|
|
845
|
-
process.exit(1);
|
|
846
|
-
}
|
|
847
|
-
});
|
|
482
|
+
.action(runAction(mcpSetupCommand));
|
|
848
483
|
program.hook('postAction', async (thisCommand, actionCommand) => {
|
|
849
|
-
// Skip update check for MCP
|
|
850
|
-
if (actionCommand.name() === 'run' && actionCommand.parent?.name() === 'mcp') {
|
|
484
|
+
// Skip update check for non-TTY streams and MCP runs to prevent contaminating stdout stream
|
|
485
|
+
if (!process.stdout.isTTY || (actionCommand.name() === 'run' && actionCommand.parent?.name() === 'mcp')) {
|
|
851
486
|
return;
|
|
852
487
|
}
|
|
853
488
|
try {
|