@haoyiyin/workflow 0.2.2 → 0.2.4

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 (61) hide show
  1. package/package.json +9 -8
  2. package/src/agents/contracts.ts +559 -0
  3. package/src/agents/dispatcher-enhanced.ts +350 -0
  4. package/src/agents/dispatcher.ts +680 -0
  5. package/src/agents/index.ts +48 -0
  6. package/src/agents/resilience.ts +255 -0
  7. package/src/agents/token-budget.ts +83 -0
  8. package/src/agents/types.ts +73 -0
  9. package/src/guard/main-agent.ts +245 -0
  10. package/src/hooks/builtin/index.ts +8 -0
  11. package/src/hooks/builtin/on-error.ts +23 -0
  12. package/src/hooks/builtin/post-execute.ts +40 -0
  13. package/src/hooks/builtin/post-plan.ts +23 -0
  14. package/src/hooks/builtin/pre-execute.ts +30 -0
  15. package/src/hooks/builtin/pre-plan.ts +26 -0
  16. package/src/hooks/index.ts +7 -0
  17. package/src/hooks/loader.ts +98 -0
  18. package/src/hooks/manager.ts +99 -0
  19. package/src/hooks/types-enhanced.ts +38 -0
  20. package/src/hooks/types.ts +35 -0
  21. package/src/index.ts +127 -0
  22. package/src/persistence/index.ts +17 -0
  23. package/src/persistence/plan-md.ts +141 -0
  24. package/src/persistence/state-md.ts +167 -0
  25. package/src/persistence/types.ts +89 -0
  26. package/src/router/classifier.ts +610 -0
  27. package/src/router/guard.ts +483 -0
  28. package/src/router/index.ts +22 -0
  29. package/src/router/router.ts +108 -0
  30. package/src/router/types.ts +127 -0
  31. package/src/skills/agents-md/SKILL.md +45 -0
  32. package/src/skills/agents-md/index.ts +33 -0
  33. package/src/skills/execute-plan/SKILL.md +60 -0
  34. package/src/skills/execute-plan/index.ts +970 -0
  35. package/src/skills/index.ts +13 -0
  36. package/src/skills/quick-task/SKILL.md +54 -0
  37. package/src/skills/quick-task/index.ts +346 -0
  38. package/src/skills/registry.ts +59 -0
  39. package/src/skills/review-diff/SKILL.md +53 -0
  40. package/src/skills/review-diff/index.ts +394 -0
  41. package/src/skills/skill.ts +59 -0
  42. package/src/skills/systematic-debugging/SKILL.md +56 -0
  43. package/src/skills/systematic-debugging/index.ts +404 -0
  44. package/src/skills/tdd/SKILL.md +52 -0
  45. package/src/skills/tdd/index.ts +409 -0
  46. package/src/skills/to-plan/SKILL.md +56 -0
  47. package/src/skills/to-plan/index-enhanced.ts +551 -0
  48. package/src/skills/to-plan/index.ts +586 -0
  49. package/src/skills/types.ts +47 -0
  50. package/src/state/cleanup.ts +118 -0
  51. package/src/state/index.ts +8 -0
  52. package/src/state/manager.ts +96 -0
  53. package/src/state/persistence.ts +77 -0
  54. package/src/state/types.ts +30 -0
  55. package/src/state/validator.ts +78 -0
  56. package/src/types.ts +102 -0
  57. package/src/utils/compress.ts +347 -0
  58. package/src/utils/git.ts +82 -0
  59. package/src/utils/index.ts +6 -0
  60. package/src/utils/logger.ts +23 -0
  61. package/src/utils/paths.ts +55 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haoyiyin/workflow",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Production workflow skills for planning, executing, reviewing, and finishing coding-agent work",
6
6
  "main": "./dist/index.js",
@@ -32,6 +32,7 @@
32
32
  "files": [
33
33
  "dist/",
34
34
  "scripts/",
35
+ "src/",
35
36
  "yi-workflow.js",
36
37
  "README.md",
37
38
  "SETUP.md",
@@ -57,13 +58,13 @@
57
58
  "./dist/pi-extension.js"
58
59
  ],
59
60
  "skills": [
60
- "./dist/skills/to-plan/SKILL.md",
61
- "./dist/skills/execute-plan/SKILL.md",
62
- "./dist/skills/quick-task/SKILL.md",
63
- "./dist/skills/review-diff/SKILL.md",
64
- "./dist/skills/tdd/SKILL.md",
65
- "./dist/skills/systematic-debugging/SKILL.md",
66
- "./dist/skills/agents-md/SKILL.md"
61
+ "./src/skills/to-plan/SKILL.md",
62
+ "./src/skills/execute-plan/SKILL.md",
63
+ "./src/skills/quick-task/SKILL.md",
64
+ "./src/skills/review-diff/SKILL.md",
65
+ "./src/skills/tdd/SKILL.md",
66
+ "./src/skills/systematic-debugging/SKILL.md",
67
+ "./src/skills/agents-md/SKILL.md"
67
68
  ],
68
69
  "prompts": [
69
70
  "./dist/prompts"
@@ -0,0 +1,559 @@
1
+ /**
2
+ * Pre-built SubagentContracts for each subagent role.
3
+ *
4
+ * Each factory accepts role-specific parameters and returns a fully-formed
5
+ * SubagentContract ready for dispatch. The contracts encode:
6
+ * - The exact permission set the subagent needs
7
+ * - Which files it may own (modify) vs. read
8
+ * - A structured prompt template
9
+ * - An optional output schema for validation
10
+ */
11
+
12
+ import type { SubagentContract, PermissionSet } from './types.js';
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Permission presets
16
+ // ---------------------------------------------------------------------------
17
+
18
+ const READ_ONLY: PermissionSet = {
19
+ readFiles: true,
20
+ searchCode: true,
21
+ runCommands: false,
22
+ writeFiles: false,
23
+ gitOperations: false,
24
+ };
25
+
26
+ const READ_SEARCH: PermissionSet = {
27
+ readFiles: true,
28
+ searchCode: true,
29
+ runCommands: false,
30
+ writeFiles: false,
31
+ gitOperations: false,
32
+ };
33
+
34
+ const READ_RUN: PermissionSet = {
35
+ readFiles: true,
36
+ searchCode: true,
37
+ runCommands: true,
38
+ writeFiles: false,
39
+ gitOperations: false,
40
+ };
41
+
42
+ const FULL_ACCESS: PermissionSet = {
43
+ readFiles: true,
44
+ searchCode: true,
45
+ runCommands: true,
46
+ writeFiles: true,
47
+ gitOperations: true,
48
+ };
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Contract parameter types
52
+ // ---------------------------------------------------------------------------
53
+
54
+ export interface ExplorerParams {
55
+ /** What the explorer should search for */
56
+ query: string;
57
+ /** Directories or file patterns to search within */
58
+ searchPaths: string[];
59
+ /** Files the explorer may read (beyond search results) */
60
+ readFiles?: string[];
61
+ /** Specific questions to answer */
62
+ questions?: string[];
63
+ }
64
+
65
+ export interface ImplementerParams {
66
+ /** Description of what to implement */
67
+ task: string;
68
+ /** Files the implementer may modify */
69
+ ownedFiles: string[];
70
+ /** Files the implementer may read for context */
71
+ readFiles?: string[];
72
+ /** Test command to run after implementation */
73
+ testCommand?: string;
74
+ /** Constraints or requirements */
75
+ constraints?: string[];
76
+ }
77
+
78
+ export interface ReviewerParams {
79
+ /** What to review (PR description, diff summary, etc.) */
80
+ target: string;
81
+ /** Files to review */
82
+ reviewFiles: string[];
83
+ /** Specific areas of concern */
84
+ focusAreas?: string[];
85
+ /** Review criteria */
86
+ criteria?: string[];
87
+ }
88
+
89
+ export interface DebuggerParams {
90
+ /** Description of the failure / bug */
91
+ issue: string;
92
+ /** Files likely involved in the bug */
93
+ suspectFiles: string[];
94
+ /** Error messages or stack traces */
95
+ errorOutput?: string;
96
+ /** Steps to reproduce */
97
+ reproSteps?: string[];
98
+ }
99
+
100
+ export interface VerifierParams {
101
+ /** The original goal / requirement */
102
+ goal: string;
103
+ /** The plan that was executed */
104
+ plan: string;
105
+ /** Files that were changed */
106
+ changedFiles: string[];
107
+ /** Acceptance criteria */
108
+ acceptanceCriteria: string[];
109
+ }
110
+
111
+ export interface ResearcherParams {
112
+ /** Research topic or question */
113
+ topic: string;
114
+ /** Specific questions to answer */
115
+ questions?: string[];
116
+ /** Search scope: technical, business, security, etc. */
117
+ scope?: 'technical' | 'business' | 'security' | 'general';
118
+ /** Maximum results to return */
119
+ maxResults?: number;
120
+ /** Time range for results (e.g., '1y', '6m', '1w') */
121
+ timeRange?: string;
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Contract factories
126
+ // ---------------------------------------------------------------------------
127
+
128
+ /**
129
+ * Explorer contract: read-only, searches the codebase to answer questions
130
+ * about structure, dependencies, patterns, or specific implementations.
131
+ */
132
+ export function explorerContract(params: ExplorerParams): SubagentContract {
133
+ const reads = [...params.searchPaths, ...(params.readFiles ?? [])];
134
+ const questionsBlock =
135
+ params.questions && params.questions.length > 0
136
+ ? `\n\n## Questions to Answer\n\n${params.questions.map((q, i) => `${i + 1}. ${q}`).join('\n')}`
137
+ : '';
138
+
139
+ const prompt = [
140
+ `Search the codebase for information related to: **${params.query}**`,
141
+ '',
142
+ `## Search Scope`,
143
+ '',
144
+ params.searchPaths.map((p) => `- \`${p}\``).join('\n'),
145
+ '',
146
+ 'For each relevant file found, report:',
147
+ '- File path and purpose',
148
+ '- Key exports, functions, or classes',
149
+ '- Dependencies and imports',
150
+ '- Any notable patterns or issues',
151
+ questionsBlock,
152
+ ].join('\n');
153
+
154
+ return {
155
+ permissions: READ_SEARCH,
156
+ prompt,
157
+ owns: [],
158
+ reads,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Implementer contract: writes code, runs tests, works in isolation.
164
+ * The implementer owns specific files and may modify them.
165
+ */
166
+ export function implementerContract(
167
+ params: ImplementerParams,
168
+ ): SubagentContract {
169
+ const constraintsBlock =
170
+ params.constraints && params.constraints.length > 0
171
+ ? `\n\n## Constraints\n\n${params.constraints.map((c) => `- ${c}`).join('\n')}`
172
+ : '';
173
+
174
+ const testBlock = params.testCommand
175
+ ? `\n\n## Verification\n\nAfter implementing, run this command to verify:\n\n\`\`\`bash\n${params.testCommand}\n\`\`\``
176
+ : '';
177
+
178
+ const prompt = [
179
+ `Implement the following task:`,
180
+ '',
181
+ params.task,
182
+ '',
183
+ '## Files You Own (may modify)',
184
+ '',
185
+ params.ownedFiles.map((f) => `- \`${f}\``).join('\n'),
186
+ '',
187
+ '## Approach',
188
+ '',
189
+ '1. Read all owned files to understand current state',
190
+ '2. Implement the changes',
191
+ '3. Verify the code compiles',
192
+ '4. Run the test command if provided',
193
+ '5. Report what you changed and why',
194
+ constraintsBlock,
195
+ testBlock,
196
+ '',
197
+ '## Output Format',
198
+ '',
199
+ 'Respond with a JSON block containing:',
200
+ '```json',
201
+ '{ "summary": "...", "filesChanged": [...], "testResult": "..." }',
202
+ '```',
203
+ ].join('\n');
204
+
205
+ return {
206
+ permissions: FULL_ACCESS,
207
+ outputSchema: {
208
+ summary: 'string',
209
+ filesChanged: 'object',
210
+ testResult: 'string',
211
+ },
212
+ prompt,
213
+ owns: [...params.ownedFiles],
214
+ reads: [...(params.readFiles ?? []), ...params.ownedFiles],
215
+ };
216
+ }
217
+
218
+ /**
219
+ * Reviewer contract: reads code changes and produces a structured review
220
+ * report covering correctness, style, security, and performance.
221
+ */
222
+ export function reviewerContract(params: ReviewerParams): SubagentContract {
223
+ const focusBlock =
224
+ params.focusAreas && params.focusAreas.length > 0
225
+ ? `\n\n## Focus Areas\n\n${params.focusAreas.map((a) => `- ${a}`).join('\n')}`
226
+ : '';
227
+
228
+ const criteriaBlock =
229
+ params.criteria && params.criteria.length > 0
230
+ ? `\n\n## Review Criteria\n\n${params.criteria.map((c) => `- ${c}`).join('\n')}`
231
+ : '';
232
+
233
+ const prompt = [
234
+ `Review the following change:`,
235
+ '',
236
+ `> ${params.target}`,
237
+ '',
238
+ '## Files to Review',
239
+ '',
240
+ params.reviewFiles.map((f) => `- \`${f}\``).join('\n'),
241
+ '',
242
+ '## Review Checklist',
243
+ '',
244
+ 'For each file, evaluate:',
245
+ '- **Correctness**: Does the logic do what it claims?',
246
+ '- **Edge Cases**: Are boundary conditions handled?',
247
+ '- **Error Handling**: Are errors caught and handled gracefully?',
248
+ '- **Immutability**: Are objects/arrays mutated or replaced?',
249
+ '- **Naming**: Are names clear and conventional?',
250
+ '- **Security**: Any injection risks, leaked secrets, or unsafe patterns?',
251
+ '- **Performance**: Any obvious N+1 queries, unnecessary allocations, or blocking calls?',
252
+ focusBlock,
253
+ criteriaBlock,
254
+ '',
255
+ '## Output Format',
256
+ '',
257
+ 'Respond with a JSON block containing:',
258
+ '```json',
259
+ '{ "verdict": "approve|request_changes|comment", "summary": "...", "findings": [{ "severity": "critical|high|medium|low", "file": "...", "line": ..., "message": "...", "suggestion": "..." }] }',
260
+ '```',
261
+ ].join('\n');
262
+
263
+ return {
264
+ permissions: READ_ONLY,
265
+ outputSchema: {
266
+ verdict: 'string',
267
+ summary: 'string',
268
+ findings: 'object',
269
+ },
270
+ prompt,
271
+ owns: [],
272
+ reads: [...params.reviewFiles],
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Debugger contract: analyses failures, identifies root causes, and
278
+ * proposes minimal fixes. Read-only unless explicitly allowed to write.
279
+ */
280
+ export function debuggerContract(params: DebuggerParams): SubagentContract {
281
+ const errorBlock = params.errorOutput
282
+ ? `\n\n## Error Output\n\n\`\`\`\n${params.errorOutput}\n\`\`\``
283
+ : '';
284
+
285
+ const reproBlock =
286
+ params.reproSteps && params.reproSteps.length > 0
287
+ ? `\n\n## Reproduction Steps\n\n${params.reproSteps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`
288
+ : '';
289
+
290
+ const prompt = [
291
+ `Investigate and find the root cause of this issue:`,
292
+ '',
293
+ `> ${params.issue}`,
294
+ '',
295
+ '## Suspect Files',
296
+ '',
297
+ params.suspectFiles.map((f) => `- \`${f}\``).join('\n'),
298
+ errorBlock,
299
+ reproBlock,
300
+ '',
301
+ '## Process',
302
+ '',
303
+ '1. Read each suspect file carefully',
304
+ '2. Trace the execution path that leads to the failure',
305
+ '3. Identify the root cause (not just the symptom)',
306
+ '4. Propose a minimal, safe fix',
307
+ '5. Explain why the fix addresses the root cause',
308
+ '',
309
+ '## Output Format',
310
+ '',
311
+ 'Respond with a JSON block containing:',
312
+ '```json',
313
+ '{ "rootCause": "...", "confidence": "high|medium|low", "fixDescription": "...", "affectedFiles": [...], "prevention": "..." }',
314
+ '```',
315
+ ].join('\n');
316
+
317
+ return {
318
+ permissions: READ_RUN,
319
+ outputSchema: {
320
+ rootCause: 'string',
321
+ confidence: 'string',
322
+ fixDescription: 'string',
323
+ affectedFiles: 'object',
324
+ prevention: 'string',
325
+ },
326
+ prompt,
327
+ owns: [],
328
+ reads: [...params.suspectFiles],
329
+ };
330
+ }
331
+
332
+ /**
333
+ * Verifier contract: goal-backward verification. Checks that the
334
+ * implemented changes actually satisfy the original requirements by
335
+ * working backward from the goal through each acceptance criterion.
336
+ */
337
+ export function verifierContract(params: VerifierParams): SubagentContract {
338
+ const criteriaList = params.acceptanceCriteria
339
+ .map((c, i) => `${i + 1}. ${c}`)
340
+ .join('\n');
341
+
342
+ const prompt = [
343
+ `Verify that the implemented changes satisfy the original goal.`,
344
+ '',
345
+ '## Original Goal',
346
+ '',
347
+ params.goal,
348
+ '',
349
+ '## Execution Plan',
350
+ '',
351
+ params.plan,
352
+ '',
353
+ '## Changed Files',
354
+ '',
355
+ params.changedFiles.map((f) => `- \`${f}\``).join('\n'),
356
+ '',
357
+ '## Acceptance Criteria',
358
+ '',
359
+ criteriaList,
360
+ '',
361
+ '## Verification Process',
362
+ '',
363
+ 'Work backward from each acceptance criterion:',
364
+ '1. For each criterion, identify what evidence would prove it is met',
365
+ '2. Check the changed files for that evidence',
366
+ '3. Mark each criterion as PASS, FAIL, or UNCERTAIN',
367
+ '4. If any criterion fails, explain the gap',
368
+ '5. Produce a final verdict',
369
+ '',
370
+ '## Output Format',
371
+ '',
372
+ 'Respond with a JSON block containing:',
373
+ '```json',
374
+ '{ "verdict": "pass|fail|partial", "criteriaResults": [{ "criterion": "...", "status": "pass|fail|uncertain", "evidence": "..." }], "gaps": [...], "recommendation": "..." }',
375
+ '```',
376
+ ].join('\n');
377
+
378
+ return {
379
+ permissions: READ_ONLY,
380
+ outputSchema: {
381
+ verdict: 'string',
382
+ criteriaResults: 'object',
383
+ gaps: 'object',
384
+ recommendation: 'string',
385
+ },
386
+ prompt,
387
+ owns: [],
388
+ reads: [...params.changedFiles],
389
+ };
390
+ }
391
+
392
+ /**
393
+ * Researcher contract: searches the internet for information on a topic.
394
+ * Returns structured research findings with sources.
395
+ */
396
+ export function researcherContract(params: ResearcherParams): SubagentContract {
397
+ const scopeText = {
398
+ technical: 'Focus on technical documentation, GitHub repos, Stack Overflow, and official docs.',
399
+ business: 'Focus on industry reports, market analysis, and business news.',
400
+ security: 'Focus on CVE databases, security advisories, and best practices.',
401
+ general: 'Broad search across all sources.',
402
+ }[params.scope ?? 'general'];
403
+
404
+ const questionsBlock =
405
+ params.questions && params.questions.length > 0
406
+ ? `\n\n## Specific Questions to Answer\n\n${params.questions.map((q, i) => `${i + 1}. ${q}`).join('\n')}`
407
+ : '';
408
+
409
+ const timeRangeText = params.timeRange
410
+ ? `\n\n## Time Range\nPrioritize results from the last ${params.timeRange}.`
411
+ : '';
412
+
413
+ const prompt = [
414
+ `Research the following topic: **${params.topic}**`,
415
+ '',
416
+ '## Search Scope',
417
+ '',
418
+ scopeText,
419
+ timeRangeText,
420
+ '',
421
+ '## Instructions',
422
+ '',
423
+ '1. Search the internet for relevant, authoritative sources',
424
+ '2. For each source, evaluate: credibility, recency, relevance',
425
+ '3. Synthesize findings into actionable insights',
426
+ '4. Note any conflicting information or uncertainties',
427
+ '',
428
+ '## Source Quality Guidelines',
429
+ '',
430
+ '- **Technical**: Official docs > GitHub repos > Stack Overflow > Blog posts',
431
+ '- **Business**: Industry reports > News articles > Company blogs',
432
+ '- **Security**: CVE databases > Official advisories > Security blogs',
433
+ '',
434
+ '## Anti-Patterns to Avoid',
435
+ '',
436
+ '- Do NOT rely on outdated information (>2 years old unless historical)',
437
+ '- Do NOT cite low-credibility sources (unverified blogs, forums)',
438
+ '- Do NOT make assumptions beyond what sources confirm',
439
+ '',
440
+ '## Output Format',
441
+ '',
442
+ 'Respond with a JSON block containing:',
443
+ '```json',
444
+ '{',
445
+ ' "summary": "Executive summary (2-3 sentences)",',
446
+ ' "findings": [',
447
+ ' {',
448
+ ' "insight": "Key finding or answer",',
449
+ ' "confidence": "high|medium|low",',
450
+ ' "sources": [{ "title": "...", "url": "...", "date": "..." }]',
451
+ ' }',
452
+ ' ],',
453
+ ' "recommendations": ["Actionable recommendations based on research"],',
454
+ ' "knowledgeGaps": ["Questions that could not be answered"]',
455
+ '}',
456
+ '```',
457
+ questionsBlock,
458
+ ].join('\n');
459
+
460
+ return {
461
+ permissions: {
462
+ ...READ_ONLY,
463
+ // Researcher needs web search capability
464
+ runCommands: true, // For web search/fetch via subagent
465
+ },
466
+ outputSchema: {
467
+ summary: 'string',
468
+ findings: 'object',
469
+ recommendations: 'object',
470
+ knowledgeGaps: 'object',
471
+ },
472
+ prompt,
473
+ owns: [],
474
+ reads: [],
475
+ };
476
+ }
477
+
478
+ // ---------------------------------------------------------------------------
479
+ // Worktree contract - Replaces worktree-start skill
480
+ // ---------------------------------------------------------------------------
481
+
482
+ export interface WorktreeParams {
483
+ /** Branch name for the new worktree */
484
+ branchName: string;
485
+ /** Base branch to create from (default: main) */
486
+ baseBranch?: string;
487
+ /** Whether to enable full isolation */
488
+ isolation?: boolean;
489
+ }
490
+
491
+ /**
492
+ * Worktree contract: Creates isolated git worktrees for parallel work.
493
+ * Replaces the worktree-start skill with a direct subagent dispatch.
494
+ */
495
+ export function worktreeContract(params: WorktreeParams): SubagentContract {
496
+ const baseBranch = params.baseBranch || 'main';
497
+ const worktreePath = `.claude/worktrees/${params.branchName}`;
498
+
499
+ const prompt = [
500
+ `Create a git worktree for branch: ${params.branchName}`,
501
+ '',
502
+ `**Base Branch**: ${baseBranch}`,
503
+ `**Worktree Path**: ${worktreePath}`,
504
+ '',
505
+ '## Steps',
506
+ '',
507
+ '1. Inspect current repo state:',
508
+ ' - `git rev-parse --show-toplevel` — get repo root',
509
+ ' - `git status --porcelain --branch` — check current branch',
510
+ ' - `git branch -a` — list all branches',
511
+ '',
512
+ '2. Create worktree:',
513
+ ` - If branch exists: \`git worktree add ${worktreePath} ${params.branchName}\``,
514
+ ` - If branch does not exist: \`git worktree add ${worktreePath} -b ${params.branchName} origin/${baseBranch}\``,
515
+ '',
516
+ '3. Verify creation:',
517
+ ' - `git worktree list`',
518
+ '',
519
+ '## Error Recovery',
520
+ '',
521
+ `- If worktree path exists: \`git worktree remove ${worktreePath} --force\` then retry`,
522
+ `- If branch exists but worktree missing: \`git worktree add ${worktreePath} ${params.branchName}\``,
523
+ '',
524
+ '## Output Format',
525
+ '',
526
+ 'Return JSON:',
527
+ '```json',
528
+ '{',
529
+ ' "worktreePath": "absolute/path/to/worktree",',
530
+ ' "branchName": "' + params.branchName + '",',
531
+ ' "baseBranch": "' + baseBranch + '",',
532
+ ' "repoRoot": "absolute/path/to/repo",',
533
+ ' "status": "created|reused|failed",',
534
+ ' "error": "error message if failed"',
535
+ '}',
536
+ '```',
537
+ ].join('\n');
538
+
539
+ return {
540
+ permissions: {
541
+ readFiles: true,
542
+ searchCode: false,
543
+ runCommands: true,
544
+ writeFiles: false,
545
+ gitOperations: true,
546
+ },
547
+ outputSchema: {
548
+ worktreePath: 'string',
549
+ branchName: 'string',
550
+ baseBranch: 'string',
551
+ repoRoot: 'string',
552
+ status: 'string',
553
+ error: 'string',
554
+ },
555
+ prompt,
556
+ owns: [],
557
+ reads: [],
558
+ };
559
+ }