@lumenflow/mcp 2.21.0 → 3.0.0

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 (79) hide show
  1. package/LICENSE +661 -190
  2. package/dist/mcp-constants.d.ts +173 -0
  3. package/dist/mcp-constants.d.ts.map +1 -0
  4. package/dist/mcp-constants.js +191 -0
  5. package/dist/mcp-constants.js.map +1 -0
  6. package/dist/runtime-cache.d.ts +7 -0
  7. package/dist/runtime-cache.d.ts.map +1 -0
  8. package/dist/runtime-cache.js +26 -0
  9. package/dist/runtime-cache.js.map +1 -0
  10. package/dist/runtime-tool-resolver.constants.d.ts +33 -0
  11. package/dist/runtime-tool-resolver.constants.d.ts.map +1 -0
  12. package/dist/runtime-tool-resolver.constants.js +33 -0
  13. package/dist/runtime-tool-resolver.constants.js.map +1 -0
  14. package/dist/runtime-tool-resolver.d.ts +5 -0
  15. package/dist/runtime-tool-resolver.d.ts.map +1 -0
  16. package/dist/runtime-tool-resolver.js +2028 -0
  17. package/dist/runtime-tool-resolver.js.map +1 -0
  18. package/dist/server.d.ts.map +1 -1
  19. package/dist/server.js +30 -4
  20. package/dist/server.js.map +1 -1
  21. package/dist/tools/agent-tools.d.ts +1 -0
  22. package/dist/tools/agent-tools.d.ts.map +1 -1
  23. package/dist/tools/agent-tools.js +113 -41
  24. package/dist/tools/agent-tools.js.map +1 -1
  25. package/dist/tools/context-tools.d.ts +2 -1
  26. package/dist/tools/context-tools.d.ts.map +1 -1
  27. package/dist/tools/context-tools.js +23 -40
  28. package/dist/tools/context-tools.js.map +1 -1
  29. package/dist/tools/flow-tools.d.ts +1 -0
  30. package/dist/tools/flow-tools.d.ts.map +1 -1
  31. package/dist/tools/flow-tools.js +51 -64
  32. package/dist/tools/flow-tools.js.map +1 -1
  33. package/dist/tools/initiative-tools.d.ts.map +1 -1
  34. package/dist/tools/initiative-tools.js +198 -84
  35. package/dist/tools/initiative-tools.js.map +1 -1
  36. package/dist/tools/memory-tools.d.ts +2 -0
  37. package/dist/tools/memory-tools.d.ts.map +1 -1
  38. package/dist/tools/memory-tools.js +268 -166
  39. package/dist/tools/memory-tools.js.map +1 -1
  40. package/dist/tools/orchestration-tools.d.ts.map +1 -1
  41. package/dist/tools/orchestration-tools.js +99 -57
  42. package/dist/tools/orchestration-tools.js.map +1 -1
  43. package/dist/tools/parity-tools.d.ts +12 -0
  44. package/dist/tools/parity-tools.d.ts.map +1 -1
  45. package/dist/tools/parity-tools.js +776 -193
  46. package/dist/tools/parity-tools.js.map +1 -1
  47. package/dist/tools/runtime-task-constants.d.ts +19 -0
  48. package/dist/tools/runtime-task-constants.d.ts.map +1 -0
  49. package/dist/tools/runtime-task-constants.js +19 -0
  50. package/dist/tools/runtime-task-constants.js.map +1 -0
  51. package/dist/tools/runtime-task-tools.d.ts +10 -0
  52. package/dist/tools/runtime-task-tools.d.ts.map +1 -0
  53. package/dist/tools/runtime-task-tools.js +114 -0
  54. package/dist/tools/runtime-task-tools.js.map +1 -0
  55. package/dist/tools/setup-tools.d.ts +1 -0
  56. package/dist/tools/setup-tools.d.ts.map +1 -1
  57. package/dist/tools/setup-tools.js +150 -65
  58. package/dist/tools/setup-tools.js.map +1 -1
  59. package/dist/tools/validation-tools.d.ts +2 -0
  60. package/dist/tools/validation-tools.d.ts.map +1 -1
  61. package/dist/tools/validation-tools.js +98 -54
  62. package/dist/tools/validation-tools.js.map +1 -1
  63. package/dist/tools/wu-tools.d.ts +1 -1
  64. package/dist/tools/wu-tools.d.ts.map +1 -1
  65. package/dist/tools/wu-tools.js +444 -250
  66. package/dist/tools/wu-tools.js.map +1 -1
  67. package/dist/tools-shared.d.ts +81 -1
  68. package/dist/tools-shared.d.ts.map +1 -1
  69. package/dist/tools-shared.js +199 -1
  70. package/dist/tools-shared.js.map +1 -1
  71. package/dist/tools.d.ts +28 -2
  72. package/dist/tools.d.ts.map +1 -1
  73. package/dist/tools.js +59 -3
  74. package/dist/tools.js.map +1 -1
  75. package/dist/worktree-enforcement.d.ts +47 -0
  76. package/dist/worktree-enforcement.d.ts.map +1 -0
  77. package/dist/worktree-enforcement.js +152 -0
  78. package/dist/worktree-enforcement.js.map +1 -0
  79. package/package.json +5 -2
@@ -6,9 +6,12 @@
6
6
  * WU-1482: Wave-1 public parity tools
7
7
  * WU-1483: Wave-2 public parity tools (file, git, plan, signal, wu:proto)
8
8
  */
9
+ import path from 'node:path';
9
10
  import { z } from 'zod';
10
11
  import { gatesSchema, lumenflowInitSchema, initiativePlanSchema } from '@lumenflow/core';
11
- import { ErrorCodes, ErrorMessages, CliArgs, SharedErrorMessages, SuccessMessages, success, error, buildGatesArgs, runCliCommand, } from '../tools-shared.js';
12
+ import { ErrorCodes, ErrorMessages, CliArgs, SharedErrorMessages, SuccessMessages, success, error, buildGatesArgs, executeViaPack, } from '../tools-shared.js';
13
+ import { CliCommands, MetadataKeys } from '../mcp-constants.js';
14
+ import { checkWorktreeEnforcement } from '../worktree-enforcement.js';
12
15
  // WU-1482: Schemas for wave-1 parity commands not yet modeled in @lumenflow/core
13
16
  const backlogPruneSchema = z.object({
14
17
  execute: z.boolean().optional(),
@@ -34,6 +37,32 @@ const laneSuggestSchema = z.object({
34
37
  no_llm: z.boolean().optional(),
35
38
  include_git: z.boolean().optional(),
36
39
  });
40
+ /**
41
+ * WU-1802: Fallback messages for lane tools migrated to executeViaPack.
42
+ */
43
+ const LaneMessages = {
44
+ HEALTH_PASSED: 'Lane health check complete',
45
+ HEALTH_FAILED: 'lane:health failed',
46
+ SUGGEST_GENERATED: 'Lane suggestions generated',
47
+ SUGGEST_FAILED: 'lane:suggest failed',
48
+ };
49
+ const LaneFlags = {
50
+ NO_COVERAGE: '--no-coverage',
51
+ DRY_RUN: '--dry-run',
52
+ INTERACTIVE: '--interactive',
53
+ OUTPUT: '--output',
54
+ NO_LLM: '--no-llm',
55
+ INCLUDE_GIT: '--include-git',
56
+ };
57
+ const GatesRuntimeMessages = {
58
+ GATES_FAILED: 'gates failed',
59
+ GATES_DOCS_PASSED: 'Docs-only gates passed',
60
+ GATES_DOCS_FAILED: 'gates:docs failed',
61
+ LUMENFLOW_GATES_FAILED: 'lumenflow-gates failed',
62
+ };
63
+ const GatesRuntimeConstants = {
64
+ FALLBACK_TIMEOUT_MS: 600000,
65
+ };
37
66
  const stateBootstrapSchema = z.object({
38
67
  execute: z.boolean().optional(),
39
68
  dry_run: z.boolean().optional(),
@@ -146,6 +175,14 @@ const signalCleanupSchema = z.object({
146
175
  quiet: z.boolean().optional(),
147
176
  base_dir: z.string().optional(),
148
177
  });
178
+ // WU-1902: Schemas for config:set and config:get commands
179
+ const configSetSchema = z.object({
180
+ key: z.string().optional(),
181
+ value: z.string().optional(),
182
+ });
183
+ const configGetSchema = z.object({
184
+ key: z.string().optional(),
185
+ });
149
186
  const wuProtoSchema = z.object({
150
187
  lane: z.string().optional(),
151
188
  title: z.string().optional(),
@@ -154,6 +191,48 @@ const wuProtoSchema = z.object({
154
191
  labels: z.array(z.string()).optional(),
155
192
  assigned_to: z.string().optional(),
156
193
  });
194
+ const GIT_RUNTIME_TOOL_NAME = CliCommands.GIT_STATUS;
195
+ const GIT_BINARY = 'git';
196
+ const RUNTIME_PROJECT_ROOT_KEY = MetadataKeys.PROJECT_ROOT;
197
+ const GIT_COMMAND_RESULT_STDOUT_KEY = 'stdout';
198
+ const GIT_COMMAND_RESULTS_KEY = 'command_results';
199
+ const GIT_OUTPUT_KEY = 'output';
200
+ function unwrapExecuteViaPackData(data) {
201
+ if (!data || typeof data !== 'object') {
202
+ return data;
203
+ }
204
+ if (!('success' in data)) {
205
+ return data;
206
+ }
207
+ const output = data;
208
+ if (!output.success) {
209
+ return data;
210
+ }
211
+ return output.data ?? {};
212
+ }
213
+ function resolveRuntimeProjectRoot(baseDir, projectRoot) {
214
+ if (typeof baseDir !== 'string' || baseDir.trim().length === 0) {
215
+ return projectRoot ?? process.cwd();
216
+ }
217
+ return path.resolve(projectRoot ?? process.cwd(), baseDir);
218
+ }
219
+ function extractGitOutput(data) {
220
+ if (!data || typeof data !== 'object') {
221
+ return '';
222
+ }
223
+ const runtimeData = data;
224
+ if (typeof runtimeData[GIT_OUTPUT_KEY] === 'string') {
225
+ return runtimeData[GIT_OUTPUT_KEY];
226
+ }
227
+ const commandResults = runtimeData[GIT_COMMAND_RESULTS_KEY];
228
+ if (!Array.isArray(commandResults) || commandResults.length === 0) {
229
+ return '';
230
+ }
231
+ const lastCommandResult = commandResults[commandResults.length - 1];
232
+ return typeof lastCommandResult[GIT_COMMAND_RESULT_STDOUT_KEY] === 'string'
233
+ ? lastCommandResult[GIT_COMMAND_RESULT_STDOUT_KEY]
234
+ : '';
235
+ }
157
236
  // ============================================================================
158
237
  // Wave-1 Public Parity Operations (WU-1482)
159
238
  // ============================================================================
@@ -167,7 +246,7 @@ export const backlogPruneTool = {
167
246
  async execute(input, options) {
168
247
  const args = [];
169
248
  if (input.execute)
170
- args.push('--execute');
249
+ args.push(CliArgs.EXECUTE);
171
250
  if (input.dry_run)
172
251
  args.push('--dry-run');
173
252
  if (input.stale_days_in_progress !== undefined) {
@@ -179,12 +258,29 @@ export const backlogPruneTool = {
179
258
  if (input.archive_days !== undefined) {
180
259
  args.push('--archive-days', String(input.archive_days));
181
260
  }
182
- const cliOptions = { projectRoot: options?.projectRoot };
183
- const result = await runCliCommand('backlog:prune', args, cliOptions);
184
- if (result.success) {
185
- return success({ message: result.stdout || 'Backlog prune complete' });
261
+ const execution = await executeViaPack(CliCommands.BACKLOG_PRUNE, {
262
+ execute: input.execute,
263
+ dry_run: input.dry_run,
264
+ stale_days_in_progress: input.stale_days_in_progress,
265
+ stale_days_ready: input.stale_days_ready,
266
+ archive_days: input.archive_days,
267
+ }, {
268
+ projectRoot: options?.projectRoot,
269
+ contextInput: {
270
+ metadata: {
271
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
272
+ },
273
+ },
274
+ fallback: {
275
+ command: CliCommands.BACKLOG_PRUNE,
276
+ args,
277
+ errorCode: ErrorCodes.BACKLOG_PRUNE_ERROR,
278
+ },
279
+ });
280
+ if (!execution.success) {
281
+ return execution;
186
282
  }
187
- return error(result.stderr || result.error?.message || 'backlog:prune failed', ErrorCodes.BACKLOG_PRUNE_ERROR);
283
+ return success(unwrapExecuteViaPackData(execution.data));
188
284
  },
189
285
  };
190
286
  /**
@@ -199,13 +295,27 @@ export const docsSyncTool = {
199
295
  if (input.vendor)
200
296
  args.push('--vendor', input.vendor);
201
297
  if (input.force)
202
- args.push('--force');
203
- const cliOptions = { projectRoot: options?.projectRoot };
204
- const result = await runCliCommand('docs:sync', args, cliOptions);
205
- if (result.success) {
206
- return success({ message: result.stdout || 'Docs sync complete' });
298
+ args.push(CliArgs.FORCE);
299
+ const execution = await executeViaPack(CliCommands.DOCS_SYNC, {
300
+ vendor: input.vendor,
301
+ force: input.force,
302
+ }, {
303
+ projectRoot: options?.projectRoot,
304
+ contextInput: {
305
+ metadata: {
306
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
307
+ },
308
+ },
309
+ fallback: {
310
+ command: CliCommands.DOCS_SYNC,
311
+ args,
312
+ errorCode: ErrorCodes.DOCS_SYNC_ERROR,
313
+ },
314
+ });
315
+ if (!execution.success) {
316
+ return execution;
207
317
  }
208
- return error(result.stderr || result.error?.message || 'docs:sync failed', ErrorCodes.DOCS_SYNC_ERROR);
318
+ return success(unwrapExecuteViaPackData(execution.data));
209
319
  },
210
320
  };
211
321
  /**
@@ -217,15 +327,25 @@ export const gatesTool = {
217
327
  inputSchema: gatesSchema,
218
328
  async execute(input, options) {
219
329
  const args = buildGatesArgs(input);
220
- const cliOptions = {
330
+ const result = await executeViaPack(CliCommands.GATES, input, {
221
331
  projectRoot: options?.projectRoot,
222
- timeout: 600000,
223
- };
224
- const result = await runCliCommand('gates', args, cliOptions);
225
- if (result.success) {
226
- return success({ message: result.stdout || SuccessMessages.ALL_GATES_PASSED });
227
- }
228
- return error(result.stderr || result.error?.message || 'gates failed', ErrorCodes.GATES_ALIAS_ERROR);
332
+ contextInput: {
333
+ metadata: {
334
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
335
+ },
336
+ },
337
+ fallback: {
338
+ command: CliCommands.GATES,
339
+ args,
340
+ errorCode: ErrorCodes.GATES_ALIAS_ERROR,
341
+ },
342
+ fallbackCliOptions: {
343
+ timeout: GatesRuntimeConstants.FALLBACK_TIMEOUT_MS,
344
+ },
345
+ });
346
+ return result.success
347
+ ? success(result.data ?? { message: SuccessMessages.ALL_GATES_PASSED })
348
+ : error(result.error?.message ?? GatesRuntimeMessages.GATES_FAILED, ErrorCodes.GATES_ALIAS_ERROR);
229
349
  },
230
350
  };
231
351
  /**
@@ -237,19 +357,30 @@ export const gatesDocsTool = {
237
357
  inputSchema: gatesSchema,
238
358
  async execute(input, options) {
239
359
  const args = buildGatesArgs(input, { forceDocsOnly: true });
240
- const cliOptions = {
360
+ const result = await executeViaPack(CliCommands.GATES, input, {
241
361
  projectRoot: options?.projectRoot,
242
- timeout: 600000,
243
- };
244
- const result = await runCliCommand('gates', args, cliOptions);
245
- if (result.success) {
246
- return success({ message: result.stdout || 'Docs-only gates passed' });
247
- }
248
- return error(result.stderr || result.error?.message || 'gates:docs failed', ErrorCodes.GATES_ALIAS_ERROR);
362
+ contextInput: {
363
+ metadata: {
364
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
365
+ },
366
+ },
367
+ fallback: {
368
+ command: CliCommands.GATES,
369
+ args,
370
+ errorCode: ErrorCodes.GATES_ALIAS_ERROR,
371
+ },
372
+ fallbackCliOptions: {
373
+ timeout: GatesRuntimeConstants.FALLBACK_TIMEOUT_MS,
374
+ },
375
+ });
376
+ return result.success
377
+ ? success(result.data ?? { message: GatesRuntimeMessages.GATES_DOCS_PASSED })
378
+ : error(result.error?.message ?? GatesRuntimeMessages.GATES_DOCS_FAILED, ErrorCodes.GATES_ALIAS_ERROR);
249
379
  },
250
380
  };
251
381
  /**
252
382
  * lane_health - Diagnose lane configuration issues
383
+ * WU-1802: Migrated from CLI shell-out to executeViaPack (runtime-first)
253
384
  */
254
385
  export const laneHealthTool = {
255
386
  name: 'lane_health',
@@ -258,27 +389,27 @@ export const laneHealthTool = {
258
389
  async execute(input, options) {
259
390
  const args = [];
260
391
  if (input.json)
261
- args.push('--json');
392
+ args.push(CliArgs.JSON);
262
393
  if (input.verbose)
263
- args.push('--verbose');
394
+ args.push(CliArgs.VERBOSE);
264
395
  if (input.no_coverage)
265
- args.push('--no-coverage');
266
- const cliOptions = { projectRoot: options?.projectRoot };
267
- const result = await runCliCommand('lane:health', args, cliOptions);
268
- if (result.success) {
269
- try {
270
- const data = JSON.parse(result.stdout);
271
- return success(data);
272
- }
273
- catch {
274
- return success({ message: result.stdout || 'Lane health check complete' });
275
- }
276
- }
277
- return error(result.stderr || result.error?.message || 'lane:health failed', ErrorCodes.LANE_HEALTH_ERROR);
396
+ args.push(LaneFlags.NO_COVERAGE);
397
+ const result = await executeViaPack(CliCommands.LANE_HEALTH, input, {
398
+ projectRoot: options?.projectRoot,
399
+ fallback: {
400
+ command: CliCommands.LANE_HEALTH,
401
+ args,
402
+ errorCode: ErrorCodes.LANE_HEALTH_ERROR,
403
+ },
404
+ });
405
+ return result.success
406
+ ? success(result.data ?? { message: LaneMessages.HEALTH_PASSED })
407
+ : error(result.error?.message ?? LaneMessages.HEALTH_FAILED, ErrorCodes.LANE_HEALTH_ERROR);
278
408
  },
279
409
  };
280
410
  /**
281
411
  * lane_suggest - Suggest lane definitions from project context
412
+ * WU-1802: Migrated from CLI shell-out to executeViaPack (runtime-first)
282
413
  */
283
414
  export const laneSuggestTool = {
284
415
  name: 'lane_suggest',
@@ -287,29 +418,28 @@ export const laneSuggestTool = {
287
418
  async execute(input, options) {
288
419
  const args = [];
289
420
  if (input.dry_run)
290
- args.push('--dry-run');
421
+ args.push(LaneFlags.DRY_RUN);
291
422
  if (input.interactive)
292
- args.push('--interactive');
423
+ args.push(LaneFlags.INTERACTIVE);
293
424
  if (input.output)
294
- args.push('--output', input.output);
425
+ args.push(LaneFlags.OUTPUT, input.output);
295
426
  if (input.json)
296
- args.push('--json');
427
+ args.push(CliArgs.JSON);
297
428
  if (input.no_llm)
298
- args.push('--no-llm');
429
+ args.push(LaneFlags.NO_LLM);
299
430
  if (input.include_git)
300
- args.push('--include-git');
301
- const cliOptions = { projectRoot: options?.projectRoot };
302
- const result = await runCliCommand('lane:suggest', args, cliOptions);
303
- if (result.success) {
304
- try {
305
- const data = JSON.parse(result.stdout);
306
- return success(data);
307
- }
308
- catch {
309
- return success({ message: result.stdout || 'Lane suggestions generated' });
310
- }
311
- }
312
- return error(result.stderr || result.error?.message || 'lane:suggest failed', ErrorCodes.LANE_SUGGEST_ERROR);
431
+ args.push(LaneFlags.INCLUDE_GIT);
432
+ const result = await executeViaPack(CliCommands.LANE_SUGGEST, input, {
433
+ projectRoot: options?.projectRoot,
434
+ fallback: {
435
+ command: CliCommands.LANE_SUGGEST,
436
+ args,
437
+ errorCode: ErrorCodes.LANE_SUGGEST_ERROR,
438
+ },
439
+ });
440
+ return result.success
441
+ ? success(result.data ?? { message: LaneMessages.SUGGEST_GENERATED })
442
+ : error(result.error?.message ?? LaneMessages.SUGGEST_FAILED, ErrorCodes.LANE_SUGGEST_ERROR);
313
443
  },
314
444
  };
315
445
  /**
@@ -331,12 +461,29 @@ export const lumenflowTool = {
331
461
  args.push('--minimal');
332
462
  if (input.framework)
333
463
  args.push('--framework', input.framework);
334
- const cliOptions = { projectRoot: options?.projectRoot };
335
- const result = await runCliCommand('lumenflow', args, cliOptions);
336
- if (result.success) {
337
- return success({ message: result.stdout || 'LumenFlow initialized' });
464
+ const execution = await executeViaPack(CliCommands.LUMENFLOW, {
465
+ client: input.client,
466
+ merge: input.merge,
467
+ full: input.full,
468
+ minimal: input.minimal,
469
+ framework: input.framework,
470
+ }, {
471
+ projectRoot: options?.projectRoot,
472
+ contextInput: {
473
+ metadata: {
474
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
475
+ },
476
+ },
477
+ fallback: {
478
+ command: CliCommands.LUMENFLOW,
479
+ args,
480
+ errorCode: ErrorCodes.LUMENFLOW_ALIAS_ERROR,
481
+ },
482
+ });
483
+ if (!execution.success) {
484
+ return execution;
338
485
  }
339
- return error(result.stderr || result.error?.message || 'lumenflow failed', ErrorCodes.LUMENFLOW_ALIAS_ERROR);
486
+ return success(unwrapExecuteViaPackData(execution.data));
340
487
  },
341
488
  };
342
489
  /**
@@ -348,15 +495,25 @@ export const lumenflowGatesTool = {
348
495
  inputSchema: gatesSchema,
349
496
  async execute(input, options) {
350
497
  const args = buildGatesArgs(input);
351
- const cliOptions = {
498
+ const result = await executeViaPack(CliCommands.GATES, input, {
352
499
  projectRoot: options?.projectRoot,
353
- timeout: 600000,
354
- };
355
- const result = await runCliCommand('gates', args, cliOptions);
356
- if (result.success) {
357
- return success({ message: result.stdout || SuccessMessages.ALL_GATES_PASSED });
358
- }
359
- return error(result.stderr || result.error?.message || 'lumenflow-gates failed', ErrorCodes.LUMENFLOW_GATES_ERROR);
500
+ contextInput: {
501
+ metadata: {
502
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
503
+ },
504
+ },
505
+ fallback: {
506
+ command: CliCommands.GATES,
507
+ args,
508
+ errorCode: ErrorCodes.LUMENFLOW_GATES_ERROR,
509
+ },
510
+ fallbackCliOptions: {
511
+ timeout: GatesRuntimeConstants.FALLBACK_TIMEOUT_MS,
512
+ },
513
+ });
514
+ return result.success
515
+ ? success(result.data ?? { message: SuccessMessages.ALL_GATES_PASSED })
516
+ : error(result.error?.message ?? GatesRuntimeMessages.LUMENFLOW_GATES_FAILED, ErrorCodes.LUMENFLOW_GATES_ERROR);
360
517
  },
361
518
  };
362
519
  /**
@@ -369,21 +526,38 @@ export const stateBootstrapTool = {
369
526
  async execute(input, options) {
370
527
  const args = [];
371
528
  if (input.execute)
372
- args.push('--execute');
529
+ args.push(CliArgs.EXECUTE);
373
530
  if (input.dry_run)
374
531
  args.push('--dry-run');
375
532
  if (input.force)
376
- args.push('--force');
533
+ args.push(CliArgs.FORCE);
377
534
  if (input.wu_dir)
378
535
  args.push('--wu-dir', input.wu_dir);
379
536
  if (input.state_dir)
380
537
  args.push('--state-dir', input.state_dir);
381
- const cliOptions = { projectRoot: options?.projectRoot };
382
- const result = await runCliCommand('state:bootstrap', args, cliOptions);
383
- if (result.success) {
384
- return success({ message: result.stdout || 'State bootstrap complete' });
538
+ const execution = await executeViaPack(CliCommands.STATE_BOOTSTRAP, {
539
+ execute: input.execute,
540
+ dry_run: input.dry_run,
541
+ force: input.force,
542
+ wu_dir: input.wu_dir,
543
+ state_dir: input.state_dir,
544
+ }, {
545
+ projectRoot: options?.projectRoot,
546
+ contextInput: {
547
+ metadata: {
548
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
549
+ },
550
+ },
551
+ fallback: {
552
+ command: CliCommands.STATE_BOOTSTRAP,
553
+ args,
554
+ errorCode: ErrorCodes.STATE_BOOTSTRAP_ERROR,
555
+ },
556
+ });
557
+ if (!execution.success) {
558
+ return execution;
385
559
  }
386
- return error(result.stderr || result.error?.message || 'state:bootstrap failed', ErrorCodes.STATE_BOOTSTRAP_ERROR);
560
+ return success(unwrapExecuteViaPackData(execution.data));
387
561
  },
388
562
  };
389
563
  /**
@@ -404,17 +578,36 @@ export const stateCleanupTool = {
404
578
  if (input.events_only)
405
579
  args.push('--events-only');
406
580
  if (input.json)
407
- args.push('--json');
581
+ args.push(CliArgs.JSON);
408
582
  if (input.quiet)
409
- args.push('--quiet');
583
+ args.push(CliArgs.QUIET);
410
584
  if (input.base_dir)
411
585
  args.push(CliArgs.BASE_DIR, input.base_dir);
412
- const cliOptions = { projectRoot: options?.projectRoot };
413
- const result = await runCliCommand('state:cleanup', args, cliOptions);
414
- if (result.success) {
415
- return success({ message: result.stdout || 'State cleanup complete' });
586
+ const execution = await executeViaPack(CliCommands.STATE_CLEANUP, {
587
+ dry_run: input.dry_run,
588
+ signals_only: input.signals_only,
589
+ memory_only: input.memory_only,
590
+ events_only: input.events_only,
591
+ json: input.json,
592
+ quiet: input.quiet,
593
+ base_dir: input.base_dir,
594
+ }, {
595
+ projectRoot: options?.projectRoot,
596
+ contextInput: {
597
+ metadata: {
598
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
599
+ },
600
+ },
601
+ fallback: {
602
+ command: CliCommands.STATE_CLEANUP,
603
+ args,
604
+ errorCode: ErrorCodes.STATE_CLEANUP_ERROR,
605
+ },
606
+ });
607
+ if (!execution.success) {
608
+ return execution;
416
609
  }
417
- return error(result.stderr || result.error?.message || 'state:cleanup failed', ErrorCodes.STATE_CLEANUP_ERROR);
610
+ return success(unwrapExecuteViaPackData(execution.data));
418
611
  },
419
612
  };
420
613
  /**
@@ -431,17 +624,34 @@ export const stateDoctorTool = {
431
624
  if (input.dry_run)
432
625
  args.push('--dry-run');
433
626
  if (input.json)
434
- args.push('--json');
627
+ args.push(CliArgs.JSON);
435
628
  if (input.quiet)
436
- args.push('--quiet');
629
+ args.push(CliArgs.QUIET);
437
630
  if (input.base_dir)
438
631
  args.push(CliArgs.BASE_DIR, input.base_dir);
439
- const cliOptions = { projectRoot: options?.projectRoot };
440
- const result = await runCliCommand('state:doctor', args, cliOptions);
441
- if (result.success) {
442
- return success({ message: result.stdout || 'State doctor complete' });
632
+ const execution = await executeViaPack(CliCommands.STATE_DOCTOR, {
633
+ fix: input.fix,
634
+ dry_run: input.dry_run,
635
+ json: input.json,
636
+ quiet: input.quiet,
637
+ base_dir: input.base_dir,
638
+ }, {
639
+ projectRoot: options?.projectRoot,
640
+ contextInput: {
641
+ metadata: {
642
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
643
+ },
644
+ },
645
+ fallback: {
646
+ command: CliCommands.STATE_DOCTOR,
647
+ args,
648
+ errorCode: ErrorCodes.STATE_DOCTOR_ERROR,
649
+ },
650
+ });
651
+ if (!execution.success) {
652
+ return execution;
443
653
  }
444
- return error(result.stderr || result.error?.message || 'state:doctor failed', ErrorCodes.STATE_DOCTOR_ERROR);
654
+ return success(unwrapExecuteViaPackData(execution.data));
445
655
  },
446
656
  };
447
657
  /**
@@ -456,15 +666,30 @@ export const syncTemplatesTool = {
456
666
  if (input.dry_run)
457
667
  args.push('--dry-run');
458
668
  if (input.verbose)
459
- args.push('--verbose');
669
+ args.push(CliArgs.VERBOSE);
460
670
  if (input.check_drift)
461
671
  args.push('--check-drift');
462
- const cliOptions = { projectRoot: options?.projectRoot };
463
- const result = await runCliCommand('sync:templates', args, cliOptions);
464
- if (result.success) {
465
- return success({ message: result.stdout || 'Template sync complete' });
672
+ const execution = await executeViaPack(CliCommands.SYNC_TEMPLATES, {
673
+ dry_run: input.dry_run,
674
+ verbose: input.verbose,
675
+ check_drift: input.check_drift,
676
+ }, {
677
+ projectRoot: options?.projectRoot,
678
+ contextInput: {
679
+ metadata: {
680
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
681
+ },
682
+ },
683
+ fallback: {
684
+ command: CliCommands.SYNC_TEMPLATES,
685
+ args,
686
+ errorCode: ErrorCodes.SYNC_TEMPLATES_ALIAS_ERROR,
687
+ },
688
+ });
689
+ if (!execution.success) {
690
+ return execution;
466
691
  }
467
- return error(result.stderr || result.error?.message || 'sync:templates failed', ErrorCodes.SYNC_TEMPLATES_ALIAS_ERROR);
692
+ return success(unwrapExecuteViaPackData(execution.data));
468
693
  },
469
694
  };
470
695
  // ============================================================================
@@ -481,7 +706,7 @@ export const fileReadTool = {
481
706
  if (!input.path) {
482
707
  return error(ErrorMessages.PATH_REQUIRED, ErrorCodes.MISSING_PARAMETER);
483
708
  }
484
- const args = ['--path', input.path];
709
+ const args = [CliArgs.PATH, input.path];
485
710
  if (input.encoding)
486
711
  args.push(CliArgs.ENCODING, input.encoding);
487
712
  if (input.start_line !== undefined)
@@ -490,12 +715,29 @@ export const fileReadTool = {
490
715
  args.push('--end-line', String(input.end_line));
491
716
  if (input.max_size !== undefined)
492
717
  args.push('--max-size', String(input.max_size));
493
- const cliOptions = { projectRoot: options?.projectRoot };
494
- const result = await runCliCommand('file:read', args, cliOptions);
495
- if (result.success) {
496
- return success({ content: result.stdout });
718
+ const execution = await executeViaPack(CliCommands.FILE_READ, {
719
+ path: input.path,
720
+ encoding: input.encoding,
721
+ start_line: input.start_line,
722
+ end_line: input.end_line,
723
+ max_size: input.max_size,
724
+ }, {
725
+ projectRoot: options?.projectRoot,
726
+ contextInput: {
727
+ metadata: {
728
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
729
+ },
730
+ },
731
+ fallback: {
732
+ command: CliCommands.FILE_READ,
733
+ args,
734
+ errorCode: ErrorCodes.FILE_READ_ERROR,
735
+ },
736
+ });
737
+ if (!execution.success) {
738
+ return execution;
497
739
  }
498
- return error(result.stderr || result.error?.message || 'file:read failed', ErrorCodes.FILE_READ_ERROR);
740
+ return success(unwrapExecuteViaPackData(execution.data));
499
741
  },
500
742
  };
501
743
  /**
@@ -512,17 +754,46 @@ export const fileWriteTool = {
512
754
  if (input.content === undefined) {
513
755
  return error(ErrorMessages.CONTENT_REQUIRED, ErrorCodes.MISSING_PARAMETER);
514
756
  }
515
- const args = ['--path', input.path, '--content', input.content];
757
+ // WU-1853: Check worktree enforcement before writing
758
+ const enforcement = checkWorktreeEnforcement({
759
+ filePath: input.path,
760
+ projectRoot: options?.projectRoot,
761
+ });
762
+ if (!enforcement.allowed) {
763
+ return error(enforcement.reason ?? 'Write blocked by worktree enforcement', enforcement.errorCode ?? ErrorCodes.WORKTREE_ENFORCEMENT_BLOCKED);
764
+ }
765
+ const args = [
766
+ CliArgs.PATH,
767
+ input.path,
768
+ '--content',
769
+ input.content,
770
+ ];
516
771
  if (input.encoding)
517
772
  args.push(CliArgs.ENCODING, input.encoding);
518
773
  if (input.no_create_dirs)
519
774
  args.push('--no-create-dirs');
520
- const cliOptions = { projectRoot: options?.projectRoot };
521
- const result = await runCliCommand('file:write', args, cliOptions);
522
- if (result.success) {
523
- return success({ message: result.stdout || 'File written' });
775
+ const execution = await executeViaPack(CliCommands.FILE_WRITE, {
776
+ path: input.path,
777
+ content: input.content,
778
+ encoding: input.encoding,
779
+ no_create_dirs: input.no_create_dirs,
780
+ }, {
781
+ projectRoot: options?.projectRoot,
782
+ contextInput: {
783
+ metadata: {
784
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
785
+ },
786
+ },
787
+ fallback: {
788
+ command: CliCommands.FILE_WRITE,
789
+ args,
790
+ errorCode: ErrorCodes.FILE_WRITE_ERROR,
791
+ },
792
+ });
793
+ if (!execution.success) {
794
+ return execution;
524
795
  }
525
- return error(result.stderr || result.error?.message || 'file:write failed', ErrorCodes.FILE_WRITE_ERROR);
796
+ return success(unwrapExecuteViaPackData(execution.data));
526
797
  },
527
798
  };
528
799
  /**
@@ -542,8 +813,16 @@ export const fileEditTool = {
542
813
  if (input.new_string === undefined) {
543
814
  return error(ErrorMessages.NEW_STRING_REQUIRED, ErrorCodes.MISSING_PARAMETER);
544
815
  }
816
+ // WU-1853: Check worktree enforcement before editing
817
+ const enforcement = checkWorktreeEnforcement({
818
+ filePath: input.path,
819
+ projectRoot: options?.projectRoot,
820
+ });
821
+ if (!enforcement.allowed) {
822
+ return error(enforcement.reason ?? 'Edit blocked by worktree enforcement', enforcement.errorCode ?? ErrorCodes.WORKTREE_ENFORCEMENT_BLOCKED);
823
+ }
545
824
  const args = [
546
- '--path',
825
+ CliArgs.PATH,
547
826
  input.path,
548
827
  '--old-string',
549
828
  input.old_string,
@@ -554,12 +833,29 @@ export const fileEditTool = {
554
833
  args.push(CliArgs.ENCODING, input.encoding);
555
834
  if (input.replace_all)
556
835
  args.push('--replace-all');
557
- const cliOptions = { projectRoot: options?.projectRoot };
558
- const result = await runCliCommand('file:edit', args, cliOptions);
559
- if (result.success) {
560
- return success({ message: result.stdout || 'File edited' });
836
+ const execution = await executeViaPack(CliCommands.FILE_EDIT, {
837
+ path: input.path,
838
+ old_string: input.old_string,
839
+ new_string: input.new_string,
840
+ encoding: input.encoding,
841
+ replace_all: input.replace_all,
842
+ }, {
843
+ projectRoot: options?.projectRoot,
844
+ contextInput: {
845
+ metadata: {
846
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
847
+ },
848
+ },
849
+ fallback: {
850
+ command: CliCommands.FILE_EDIT,
851
+ args,
852
+ errorCode: ErrorCodes.FILE_EDIT_ERROR,
853
+ },
854
+ });
855
+ if (!execution.success) {
856
+ return execution;
561
857
  }
562
- return error(result.stderr || result.error?.message || 'file:edit failed', ErrorCodes.FILE_EDIT_ERROR);
858
+ return success(unwrapExecuteViaPackData(execution.data));
563
859
  },
564
860
  };
565
861
  /**
@@ -573,17 +869,32 @@ export const fileDeleteTool = {
573
869
  if (!input.path) {
574
870
  return error(ErrorMessages.PATH_REQUIRED, ErrorCodes.MISSING_PARAMETER);
575
871
  }
576
- const args = ['--path', input.path];
872
+ const args = [CliArgs.PATH, input.path];
577
873
  if (input.recursive)
578
874
  args.push('--recursive');
579
875
  if (input.force)
580
- args.push('--force');
581
- const cliOptions = { projectRoot: options?.projectRoot };
582
- const result = await runCliCommand('file:delete', args, cliOptions);
583
- if (result.success) {
584
- return success({ message: result.stdout || 'Delete complete' });
876
+ args.push(CliArgs.FORCE);
877
+ const execution = await executeViaPack(CliCommands.FILE_DELETE, {
878
+ path: input.path,
879
+ recursive: input.recursive,
880
+ force: input.force,
881
+ }, {
882
+ projectRoot: options?.projectRoot,
883
+ contextInput: {
884
+ metadata: {
885
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
886
+ },
887
+ },
888
+ fallback: {
889
+ command: CliCommands.FILE_DELETE,
890
+ args,
891
+ errorCode: ErrorCodes.FILE_DELETE_ERROR,
892
+ },
893
+ });
894
+ if (!execution.success) {
895
+ return execution;
585
896
  }
586
- return error(result.stderr || result.error?.message || 'file:delete failed', ErrorCodes.FILE_DELETE_ERROR);
897
+ return success(unwrapExecuteViaPackData(execution.data));
587
898
  },
588
899
  };
589
900
  /**
@@ -594,6 +905,7 @@ export const gitStatusTool = {
594
905
  description: 'Show git status with optional porcelain/short modes',
595
906
  inputSchema: gitStatusSchema,
596
907
  async execute(input, options) {
908
+ const runtimeProjectRoot = resolveRuntimeProjectRoot(input.base_dir, options?.projectRoot);
597
909
  const args = [];
598
910
  if (input.base_dir)
599
911
  args.push(CliArgs.BASE_DIR, input.base_dir);
@@ -603,12 +915,33 @@ export const gitStatusTool = {
603
915
  args.push('--short');
604
916
  if (input.path)
605
917
  args.push(input.path);
606
- const cliOptions = { projectRoot: options?.projectRoot };
607
- const result = await runCliCommand('git:status', args, cliOptions);
608
- if (result.success) {
609
- return success({ output: result.stdout });
918
+ const gitCommandArgs = ['status'];
919
+ if (input.porcelain)
920
+ gitCommandArgs.push('--porcelain');
921
+ if (input.short)
922
+ gitCommandArgs.push('--short');
923
+ if (input.path)
924
+ gitCommandArgs.push(input.path);
925
+ const execution = await executeViaPack(GIT_RUNTIME_TOOL_NAME, {
926
+ commands: [[GIT_BINARY, ...gitCommandArgs]],
927
+ }, {
928
+ projectRoot: runtimeProjectRoot,
929
+ contextInput: {
930
+ metadata: {
931
+ [RUNTIME_PROJECT_ROOT_KEY]: runtimeProjectRoot,
932
+ },
933
+ },
934
+ fallback: {
935
+ command: CliCommands.GIT_STATUS,
936
+ args,
937
+ errorCode: ErrorCodes.GIT_STATUS_ERROR,
938
+ },
939
+ });
940
+ if (!execution.success) {
941
+ return execution;
610
942
  }
611
- return error(result.stderr || result.error?.message || 'git:status failed', ErrorCodes.GIT_STATUS_ERROR);
943
+ const runtimeData = unwrapExecuteViaPackData(execution.data);
944
+ return success({ output: extractGitOutput(runtimeData) });
612
945
  },
613
946
  };
614
947
  /**
@@ -619,6 +952,7 @@ export const gitDiffTool = {
619
952
  description: 'Show git diff with staged/name-only/stat modes',
620
953
  inputSchema: gitDiffSchema,
621
954
  async execute(input, options) {
955
+ const runtimeProjectRoot = resolveRuntimeProjectRoot(input.base_dir, options?.projectRoot);
622
956
  const args = [];
623
957
  if (input.base_dir)
624
958
  args.push(CliArgs.BASE_DIR, input.base_dir);
@@ -632,12 +966,37 @@ export const gitDiffTool = {
632
966
  args.push(input.ref);
633
967
  if (input.path)
634
968
  args.push('--', input.path);
635
- const cliOptions = { projectRoot: options?.projectRoot };
636
- const result = await runCliCommand('git:diff', args, cliOptions);
637
- if (result.success) {
638
- return success({ output: result.stdout });
969
+ const gitCommandArgs = ['diff'];
970
+ if (input.staged)
971
+ gitCommandArgs.push('--staged');
972
+ if (input.name_only)
973
+ gitCommandArgs.push('--name-only');
974
+ if (input.stat)
975
+ gitCommandArgs.push('--stat');
976
+ if (input.ref)
977
+ gitCommandArgs.push(input.ref);
978
+ if (input.path)
979
+ gitCommandArgs.push('--', input.path);
980
+ const execution = await executeViaPack(GIT_RUNTIME_TOOL_NAME, {
981
+ commands: [[GIT_BINARY, ...gitCommandArgs]],
982
+ }, {
983
+ projectRoot: runtimeProjectRoot,
984
+ contextInput: {
985
+ metadata: {
986
+ [RUNTIME_PROJECT_ROOT_KEY]: runtimeProjectRoot,
987
+ },
988
+ },
989
+ fallback: {
990
+ command: CliCommands.GIT_DIFF,
991
+ args,
992
+ errorCode: ErrorCodes.GIT_DIFF_ERROR,
993
+ },
994
+ });
995
+ if (!execution.success) {
996
+ return execution;
639
997
  }
640
- return error(result.stderr || result.error?.message || 'git:diff failed', ErrorCodes.GIT_DIFF_ERROR);
998
+ const runtimeData = unwrapExecuteViaPackData(execution.data);
999
+ return success({ output: extractGitOutput(runtimeData) });
641
1000
  },
642
1001
  };
643
1002
  /**
@@ -648,6 +1007,7 @@ export const gitLogTool = {
648
1007
  description: 'Show git commit log with filters',
649
1008
  inputSchema: gitLogSchema,
650
1009
  async execute(input, options) {
1010
+ const runtimeProjectRoot = resolveRuntimeProjectRoot(input.base_dir, options?.projectRoot);
651
1011
  const args = [];
652
1012
  if (input.base_dir)
653
1013
  args.push(CliArgs.BASE_DIR, input.base_dir);
@@ -656,19 +1016,46 @@ export const gitLogTool = {
656
1016
  if (input.max_count !== undefined)
657
1017
  args.push('-n', String(input.max_count));
658
1018
  if (input.format)
659
- args.push('--format', input.format);
1019
+ args.push(CliArgs.FORMAT, input.format);
660
1020
  if (input.since)
661
- args.push('--since', input.since);
1021
+ args.push(CliArgs.SINCE, input.since);
662
1022
  if (input.author)
663
1023
  args.push('--author', input.author);
664
1024
  if (input.ref)
665
1025
  args.push(input.ref);
666
- const cliOptions = { projectRoot: options?.projectRoot };
667
- const result = await runCliCommand('git:log', args, cliOptions);
668
- if (result.success) {
669
- return success({ output: result.stdout });
1026
+ const gitCommandArgs = ['log'];
1027
+ if (input.oneline)
1028
+ gitCommandArgs.push('--oneline');
1029
+ if (input.max_count !== undefined)
1030
+ gitCommandArgs.push('-n', String(input.max_count));
1031
+ if (input.format)
1032
+ gitCommandArgs.push(CliArgs.FORMAT, input.format);
1033
+ if (input.since)
1034
+ gitCommandArgs.push(CliArgs.SINCE, input.since);
1035
+ if (input.author)
1036
+ gitCommandArgs.push('--author', input.author);
1037
+ if (input.ref)
1038
+ gitCommandArgs.push(input.ref);
1039
+ const execution = await executeViaPack(GIT_RUNTIME_TOOL_NAME, {
1040
+ commands: [[GIT_BINARY, ...gitCommandArgs]],
1041
+ }, {
1042
+ projectRoot: runtimeProjectRoot,
1043
+ contextInput: {
1044
+ metadata: {
1045
+ [RUNTIME_PROJECT_ROOT_KEY]: runtimeProjectRoot,
1046
+ },
1047
+ },
1048
+ fallback: {
1049
+ command: CliCommands.GIT_LOG,
1050
+ args,
1051
+ errorCode: ErrorCodes.GIT_LOG_ERROR,
1052
+ },
1053
+ });
1054
+ if (!execution.success) {
1055
+ return execution;
670
1056
  }
671
- return error(result.stderr || result.error?.message || 'git:log failed', ErrorCodes.GIT_LOG_ERROR);
1057
+ const runtimeData = unwrapExecuteViaPackData(execution.data);
1058
+ return success({ output: extractGitOutput(runtimeData) });
672
1059
  },
673
1060
  };
674
1061
  /**
@@ -679,6 +1066,7 @@ export const gitBranchTool = {
679
1066
  description: 'Show git branch listing and current branch',
680
1067
  inputSchema: gitBranchSchema,
681
1068
  async execute(input, options) {
1069
+ const runtimeProjectRoot = resolveRuntimeProjectRoot(input.base_dir, options?.projectRoot);
682
1070
  const args = [];
683
1071
  if (input.base_dir)
684
1072
  args.push(CliArgs.BASE_DIR, input.base_dir);
@@ -692,12 +1080,37 @@ export const gitBranchTool = {
692
1080
  args.push('--show-current');
693
1081
  if (input.contains)
694
1082
  args.push('--contains', input.contains);
695
- const cliOptions = { projectRoot: options?.projectRoot };
696
- const result = await runCliCommand('git:branch', args, cliOptions);
697
- if (result.success) {
698
- return success({ output: result.stdout });
1083
+ const gitCommandArgs = ['branch'];
1084
+ if (input.list)
1085
+ gitCommandArgs.push('--list');
1086
+ if (input.all)
1087
+ gitCommandArgs.push('--all');
1088
+ if (input.remotes)
1089
+ gitCommandArgs.push('--remotes');
1090
+ if (input.show_current)
1091
+ gitCommandArgs.push('--show-current');
1092
+ if (input.contains)
1093
+ gitCommandArgs.push('--contains', input.contains);
1094
+ const execution = await executeViaPack(GIT_RUNTIME_TOOL_NAME, {
1095
+ commands: [[GIT_BINARY, ...gitCommandArgs]],
1096
+ }, {
1097
+ projectRoot: runtimeProjectRoot,
1098
+ contextInput: {
1099
+ metadata: {
1100
+ [RUNTIME_PROJECT_ROOT_KEY]: runtimeProjectRoot,
1101
+ },
1102
+ },
1103
+ fallback: {
1104
+ command: CliCommands.GIT_BRANCH,
1105
+ args,
1106
+ errorCode: ErrorCodes.GIT_BRANCH_ERROR,
1107
+ },
1108
+ });
1109
+ if (!execution.success) {
1110
+ return execution;
699
1111
  }
700
- return error(result.stderr || result.error?.message || 'git:branch failed', ErrorCodes.GIT_BRANCH_ERROR);
1112
+ const runtimeData = unwrapExecuteViaPackData(execution.data);
1113
+ return success({ output: extractGitOutput(runtimeData) });
701
1114
  },
702
1115
  };
703
1116
  /**
@@ -719,12 +1132,22 @@ export const initPlanTool = {
719
1132
  args.push('--plan', input.plan);
720
1133
  if (input.create)
721
1134
  args.push('--create');
722
- const cliOptions = { projectRoot: options?.projectRoot };
723
- const result = await runCliCommand('init:plan', args, cliOptions);
724
- if (result.success) {
725
- return success({ message: result.stdout || 'Plan linked' });
726
- }
727
- return error(result.stderr || result.error?.message || 'init:plan failed', ErrorCodes.INIT_PLAN_ERROR);
1135
+ const execution = await executeViaPack(CliCommands.INIT_PLAN, input, {
1136
+ projectRoot: options?.projectRoot,
1137
+ contextInput: {
1138
+ metadata: {
1139
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1140
+ },
1141
+ },
1142
+ fallback: {
1143
+ command: CliCommands.INIT_PLAN,
1144
+ args,
1145
+ errorCode: ErrorCodes.INIT_PLAN_ERROR,
1146
+ },
1147
+ });
1148
+ return execution.success
1149
+ ? success(unwrapExecuteViaPackData(execution.data))
1150
+ : error(execution.error?.message ?? 'init:plan failed', ErrorCodes.INIT_PLAN_ERROR);
728
1151
  },
729
1152
  };
730
1153
  /**
@@ -741,13 +1164,27 @@ export const planCreateTool = {
741
1164
  if (!input.title) {
742
1165
  return error(ErrorMessages.TITLE_REQUIRED, ErrorCodes.MISSING_PARAMETER);
743
1166
  }
744
- const args = ['--id', input.id, '--title', input.title];
745
- const cliOptions = { projectRoot: options?.projectRoot };
746
- const result = await runCliCommand('plan:create', args, cliOptions);
747
- if (result.success) {
748
- return success({ message: result.stdout || 'Plan created' });
1167
+ const args = [CliArgs.ID, input.id, '--title', input.title];
1168
+ const execution = await executeViaPack(CliCommands.PLAN_CREATE, {
1169
+ id: input.id,
1170
+ title: input.title,
1171
+ }, {
1172
+ projectRoot: options?.projectRoot,
1173
+ contextInput: {
1174
+ metadata: {
1175
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1176
+ },
1177
+ },
1178
+ fallback: {
1179
+ command: CliCommands.PLAN_CREATE,
1180
+ args,
1181
+ errorCode: ErrorCodes.PLAN_CREATE_ERROR,
1182
+ },
1183
+ });
1184
+ if (!execution.success) {
1185
+ return execution;
749
1186
  }
750
- return error(result.stderr || result.error?.message || 'plan:create failed', ErrorCodes.PLAN_CREATE_ERROR);
1187
+ return success(unwrapExecuteViaPackData(execution.data));
751
1188
  },
752
1189
  };
753
1190
  /**
@@ -767,17 +1204,33 @@ export const planEditTool = {
767
1204
  if (!input.content && !input.append) {
768
1205
  return error(ErrorMessages.CONTENT_REQUIRED, ErrorCodes.MISSING_PARAMETER);
769
1206
  }
770
- const args = ['--id', input.id, '--section', input.section];
1207
+ const args = [CliArgs.ID, input.id, '--section', input.section];
771
1208
  if (input.content)
772
1209
  args.push('--content', input.content);
773
1210
  if (input.append)
774
1211
  args.push('--append', input.append);
775
- const cliOptions = { projectRoot: options?.projectRoot };
776
- const result = await runCliCommand('plan:edit', args, cliOptions);
777
- if (result.success) {
778
- return success({ message: result.stdout || 'Plan edited' });
1212
+ const execution = await executeViaPack(CliCommands.PLAN_EDIT, {
1213
+ id: input.id,
1214
+ section: input.section,
1215
+ content: input.content,
1216
+ append: input.append,
1217
+ }, {
1218
+ projectRoot: options?.projectRoot,
1219
+ contextInput: {
1220
+ metadata: {
1221
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1222
+ },
1223
+ },
1224
+ fallback: {
1225
+ command: CliCommands.PLAN_EDIT,
1226
+ args,
1227
+ errorCode: ErrorCodes.PLAN_EDIT_ERROR,
1228
+ },
1229
+ });
1230
+ if (!execution.success) {
1231
+ return execution;
779
1232
  }
780
- return error(result.stderr || result.error?.message || 'plan:edit failed', ErrorCodes.PLAN_EDIT_ERROR);
1233
+ return success(unwrapExecuteViaPackData(execution.data));
781
1234
  },
782
1235
  };
783
1236
  /**
@@ -794,13 +1247,27 @@ export const planLinkTool = {
794
1247
  if (!input.plan) {
795
1248
  return error(ErrorMessages.PLAN_REQUIRED, ErrorCodes.MISSING_PARAMETER);
796
1249
  }
797
- const args = ['--id', input.id, '--plan', input.plan];
798
- const cliOptions = { projectRoot: options?.projectRoot };
799
- const result = await runCliCommand('plan:link', args, cliOptions);
800
- if (result.success) {
801
- return success({ message: result.stdout || 'Plan linked' });
1250
+ const args = [CliArgs.ID, input.id, '--plan', input.plan];
1251
+ const execution = await executeViaPack(CliCommands.PLAN_LINK, {
1252
+ id: input.id,
1253
+ plan: input.plan,
1254
+ }, {
1255
+ projectRoot: options?.projectRoot,
1256
+ contextInput: {
1257
+ metadata: {
1258
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1259
+ },
1260
+ },
1261
+ fallback: {
1262
+ command: CliCommands.PLAN_LINK,
1263
+ args,
1264
+ errorCode: ErrorCodes.PLAN_LINK_ERROR,
1265
+ },
1266
+ });
1267
+ if (!execution.success) {
1268
+ return execution;
802
1269
  }
803
- return error(result.stderr || result.error?.message || 'plan:link failed', ErrorCodes.PLAN_LINK_ERROR);
1270
+ return success(unwrapExecuteViaPackData(execution.data));
804
1271
  },
805
1272
  };
806
1273
  /**
@@ -814,15 +1281,29 @@ export const planPromoteTool = {
814
1281
  if (!input.id) {
815
1282
  return error(ErrorMessages.ID_REQUIRED, ErrorCodes.MISSING_PARAMETER);
816
1283
  }
817
- const args = ['--id', input.id];
1284
+ const args = [CliArgs.ID, input.id];
818
1285
  if (input.force)
819
- args.push('--force');
820
- const cliOptions = { projectRoot: options?.projectRoot };
821
- const result = await runCliCommand('plan:promote', args, cliOptions);
822
- if (result.success) {
823
- return success({ message: result.stdout || 'Plan promoted' });
1286
+ args.push(CliArgs.FORCE);
1287
+ const execution = await executeViaPack(CliCommands.PLAN_PROMOTE, {
1288
+ id: input.id,
1289
+ force: input.force,
1290
+ }, {
1291
+ projectRoot: options?.projectRoot,
1292
+ contextInput: {
1293
+ metadata: {
1294
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1295
+ },
1296
+ },
1297
+ fallback: {
1298
+ command: CliCommands.PLAN_PROMOTE,
1299
+ args,
1300
+ errorCode: ErrorCodes.PLAN_PROMOTE_ERROR,
1301
+ },
1302
+ });
1303
+ if (!execution.success) {
1304
+ return execution;
824
1305
  }
825
- return error(result.stderr || result.error?.message || 'plan:promote failed', ErrorCodes.PLAN_PROMOTE_ERROR);
1306
+ return success(unwrapExecuteViaPackData(execution.data));
826
1307
  },
827
1308
  };
828
1309
  /**
@@ -843,17 +1324,108 @@ export const signalCleanupTool = {
843
1324
  if (input.max_entries !== undefined)
844
1325
  args.push('--max-entries', String(input.max_entries));
845
1326
  if (input.json)
846
- args.push('--json');
1327
+ args.push(CliArgs.JSON);
847
1328
  if (input.quiet)
848
- args.push('--quiet');
1329
+ args.push(CliArgs.QUIET);
849
1330
  if (input.base_dir)
850
1331
  args.push(CliArgs.BASE_DIR, input.base_dir);
851
- const cliOptions = { projectRoot: options?.projectRoot };
852
- const result = await runCliCommand('signal:cleanup', args, cliOptions);
853
- if (result.success) {
854
- return success({ message: result.stdout || 'Signal cleanup complete' });
1332
+ const execution = await executeViaPack(CliCommands.SIGNAL_CLEANUP, {
1333
+ dry_run: input.dry_run,
1334
+ ttl: input.ttl,
1335
+ unread_ttl: input.unread_ttl,
1336
+ max_entries: input.max_entries,
1337
+ json: input.json,
1338
+ quiet: input.quiet,
1339
+ base_dir: input.base_dir,
1340
+ }, {
1341
+ projectRoot: options?.projectRoot,
1342
+ contextInput: {
1343
+ metadata: {
1344
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1345
+ },
1346
+ },
1347
+ fallback: {
1348
+ command: CliCommands.SIGNAL_CLEANUP,
1349
+ args,
1350
+ errorCode: ErrorCodes.SIGNAL_CLEANUP_ERROR,
1351
+ },
1352
+ });
1353
+ if (!execution.success) {
1354
+ return execution;
1355
+ }
1356
+ return success(unwrapExecuteViaPackData(execution.data));
1357
+ },
1358
+ };
1359
+ /**
1360
+ * config_set - Safely update .lumenflow.config.yaml via micro-worktree
1361
+ * WU-1902: config:set MCP parity tool
1362
+ */
1363
+ export const configSetTool = {
1364
+ name: 'config_set',
1365
+ description: 'Safely update .lumenflow.config.yaml via micro-worktree',
1366
+ inputSchema: configSetSchema,
1367
+ async execute(input, options) {
1368
+ if (!input.key) {
1369
+ return error(ErrorMessages.KEY_REQUIRED, ErrorCodes.MISSING_PARAMETER);
1370
+ }
1371
+ if (input.value === undefined) {
1372
+ return error(ErrorMessages.VALUE_REQUIRED, ErrorCodes.MISSING_PARAMETER);
1373
+ }
1374
+ const args = ['--key', input.key, '--value', input.value];
1375
+ const execution = await executeViaPack(CliCommands.CONFIG_SET, {
1376
+ key: input.key,
1377
+ value: input.value,
1378
+ }, {
1379
+ projectRoot: options?.projectRoot,
1380
+ contextInput: {
1381
+ metadata: {
1382
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1383
+ },
1384
+ },
1385
+ fallback: {
1386
+ command: CliCommands.CONFIG_SET,
1387
+ args,
1388
+ errorCode: ErrorCodes.CONFIG_SET_ERROR,
1389
+ },
1390
+ });
1391
+ if (!execution.success) {
1392
+ return execution;
1393
+ }
1394
+ return success(unwrapExecuteViaPackData(execution.data));
1395
+ },
1396
+ };
1397
+ /**
1398
+ * config_get - Read and display a value from .lumenflow.config.yaml
1399
+ * WU-1902: config:get MCP parity tool
1400
+ */
1401
+ export const configGetTool = {
1402
+ name: 'config_get',
1403
+ description: 'Read and display a value from .lumenflow.config.yaml',
1404
+ inputSchema: configGetSchema,
1405
+ async execute(input, options) {
1406
+ if (!input.key) {
1407
+ return error(ErrorMessages.KEY_REQUIRED, ErrorCodes.MISSING_PARAMETER);
855
1408
  }
856
- return error(result.stderr || result.error?.message || 'signal:cleanup failed', ErrorCodes.SIGNAL_CLEANUP_ERROR);
1409
+ const args = ['--key', input.key];
1410
+ const execution = await executeViaPack(CliCommands.CONFIG_GET, {
1411
+ key: input.key,
1412
+ }, {
1413
+ projectRoot: options?.projectRoot,
1414
+ contextInput: {
1415
+ metadata: {
1416
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1417
+ },
1418
+ },
1419
+ fallback: {
1420
+ command: CliCommands.CONFIG_GET,
1421
+ args,
1422
+ errorCode: ErrorCodes.CONFIG_GET_ERROR,
1423
+ },
1424
+ });
1425
+ if (!execution.success) {
1426
+ return execution;
1427
+ }
1428
+ return success(unwrapExecuteViaPackData(execution.data));
857
1429
  },
858
1430
  };
859
1431
  /**
@@ -870,7 +1442,7 @@ export const wuProtoTool = {
870
1442
  if (!input.title) {
871
1443
  return error(ErrorMessages.TITLE_REQUIRED, ErrorCodes.MISSING_PARAMETER);
872
1444
  }
873
- const args = ['--lane', input.lane, '--title', input.title];
1445
+ const args = [CliArgs.LANE, input.lane, '--title', input.title];
874
1446
  if (input.description)
875
1447
  args.push(CliArgs.DESCRIPTION, input.description);
876
1448
  if (Array.isArray(input.code_paths)) {
@@ -883,12 +1455,23 @@ export const wuProtoTool = {
883
1455
  }
884
1456
  if (input.assigned_to)
885
1457
  args.push('--assigned-to', input.assigned_to);
886
- const cliOptions = { projectRoot: options?.projectRoot };
887
- const result = await runCliCommand('wu:proto', args, cliOptions);
888
- if (result.success) {
889
- return success({ message: result.stdout || 'Prototype WU created' });
1458
+ const execution = await executeViaPack(CliCommands.WU_PROTO, input, {
1459
+ projectRoot: options?.projectRoot,
1460
+ contextInput: {
1461
+ metadata: {
1462
+ [MetadataKeys.PROJECT_ROOT]: options?.projectRoot,
1463
+ },
1464
+ },
1465
+ fallback: {
1466
+ command: CliCommands.WU_PROTO,
1467
+ args,
1468
+ errorCode: ErrorCodes.WU_PROTO_ERROR,
1469
+ },
1470
+ });
1471
+ if (!execution.success) {
1472
+ return error(execution.error?.message ?? 'wu:proto failed', ErrorCodes.WU_PROTO_ERROR);
890
1473
  }
891
- return error(result.stderr || result.error?.message || 'wu:proto failed', ErrorCodes.WU_PROTO_ERROR);
1474
+ return success(execution.data ?? { message: 'Prototype WU created' });
892
1475
  },
893
1476
  };
894
1477
  //# sourceMappingURL=parity-tools.js.map