@doingdev/opencode-claude-manager-plugin 0.1.64 → 0.1.66

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 (125) hide show
  1. package/README.md +106 -120
  2. package/dist/claude/claude-agent-sdk-adapter.js +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/manager/team-orchestrator.js +1 -1
  5. package/dist/plugin/agents/common.d.ts +2 -2
  6. package/dist/plugin/agents/common.js +5 -0
  7. package/dist/plugin/claude-manager.plugin.js +104 -0
  8. package/dist/plugin/inbox-ops.d.ts +50 -0
  9. package/dist/plugin/inbox-ops.js +166 -0
  10. package/dist/types/contracts.d.ts +18 -0
  11. package/package.json +13 -13
  12. package/dist/claude/session-live-tailer.d.ts +0 -51
  13. package/dist/claude/session-live-tailer.js +0 -269
  14. package/dist/manager/session-controller.d.ts +0 -41
  15. package/dist/manager/session-controller.js +0 -97
  16. package/dist/metadata/claude-metadata.service.d.ts +0 -12
  17. package/dist/metadata/claude-metadata.service.js +0 -38
  18. package/dist/metadata/repo-claude-config-reader.d.ts +0 -7
  19. package/dist/metadata/repo-claude-config-reader.js +0 -154
  20. package/dist/plugin/orchestrator.plugin.d.ts +0 -2
  21. package/dist/plugin/orchestrator.plugin.js +0 -116
  22. package/dist/providers/claude-code-wrapper.d.ts +0 -13
  23. package/dist/providers/claude-code-wrapper.js +0 -13
  24. package/dist/safety/bash-safety.d.ts +0 -21
  25. package/dist/safety/bash-safety.js +0 -62
  26. package/dist/src/claude/claude-agent-sdk-adapter.d.ts +0 -28
  27. package/dist/src/claude/claude-agent-sdk-adapter.js +0 -559
  28. package/dist/src/claude/claude-session.service.d.ts +0 -9
  29. package/dist/src/claude/claude-session.service.js +0 -15
  30. package/dist/src/claude/session-live-tailer.d.ts +0 -51
  31. package/dist/src/claude/session-live-tailer.js +0 -269
  32. package/dist/src/claude/tool-approval-manager.d.ts +0 -30
  33. package/dist/src/claude/tool-approval-manager.js +0 -279
  34. package/dist/src/index.d.ts +0 -5
  35. package/dist/src/index.js +0 -3
  36. package/dist/src/manager/context-tracker.d.ts +0 -32
  37. package/dist/src/manager/context-tracker.js +0 -103
  38. package/dist/src/manager/git-operations.d.ts +0 -18
  39. package/dist/src/manager/git-operations.js +0 -86
  40. package/dist/src/manager/persistent-manager.d.ts +0 -39
  41. package/dist/src/manager/persistent-manager.js +0 -44
  42. package/dist/src/manager/session-controller.d.ts +0 -41
  43. package/dist/src/manager/session-controller.js +0 -97
  44. package/dist/src/manager/team-orchestrator.d.ts +0 -81
  45. package/dist/src/manager/team-orchestrator.js +0 -612
  46. package/dist/src/plugin/agent-hierarchy.d.ts +0 -1
  47. package/dist/src/plugin/agent-hierarchy.js +0 -2
  48. package/dist/src/plugin/agents/browser-qa.d.ts +0 -14
  49. package/dist/src/plugin/agents/browser-qa.js +0 -31
  50. package/dist/src/plugin/agents/common.d.ts +0 -36
  51. package/dist/src/plugin/agents/common.js +0 -59
  52. package/dist/src/plugin/agents/cto.d.ts +0 -9
  53. package/dist/src/plugin/agents/cto.js +0 -39
  54. package/dist/src/plugin/agents/engineers.d.ts +0 -9
  55. package/dist/src/plugin/agents/engineers.js +0 -11
  56. package/dist/src/plugin/agents/index.d.ts +0 -5
  57. package/dist/src/plugin/agents/index.js +0 -5
  58. package/dist/src/plugin/agents/team-planner.d.ts +0 -10
  59. package/dist/src/plugin/agents/team-planner.js +0 -23
  60. package/dist/src/plugin/claude-manager.plugin.d.ts +0 -10
  61. package/dist/src/plugin/claude-manager.plugin.js +0 -950
  62. package/dist/src/plugin/service-factory.d.ts +0 -38
  63. package/dist/src/plugin/service-factory.js +0 -101
  64. package/dist/src/prompts/registry.d.ts +0 -2
  65. package/dist/src/prompts/registry.js +0 -210
  66. package/dist/src/state/file-run-state-store.d.ts +0 -14
  67. package/dist/src/state/file-run-state-store.js +0 -85
  68. package/dist/src/state/team-state-store.d.ts +0 -14
  69. package/dist/src/state/team-state-store.js +0 -88
  70. package/dist/src/state/transcript-store.d.ts +0 -15
  71. package/dist/src/state/transcript-store.js +0 -44
  72. package/dist/src/team/roster.d.ts +0 -5
  73. package/dist/src/team/roster.js +0 -40
  74. package/dist/src/types/contracts.d.ts +0 -261
  75. package/dist/src/types/contracts.js +0 -2
  76. package/dist/src/util/fs-helpers.d.ts +0 -8
  77. package/dist/src/util/fs-helpers.js +0 -21
  78. package/dist/src/util/project-context.d.ts +0 -10
  79. package/dist/src/util/project-context.js +0 -105
  80. package/dist/src/util/transcript-append.d.ts +0 -7
  81. package/dist/src/util/transcript-append.js +0 -29
  82. package/dist/state/file-run-state-store.d.ts +0 -14
  83. package/dist/state/file-run-state-store.js +0 -85
  84. package/dist/test/claude-agent-sdk-adapter.test.d.ts +0 -1
  85. package/dist/test/claude-agent-sdk-adapter.test.js +0 -707
  86. package/dist/test/claude-manager.plugin.test.d.ts +0 -1
  87. package/dist/test/claude-manager.plugin.test.js +0 -316
  88. package/dist/test/context-tracker.test.d.ts +0 -1
  89. package/dist/test/context-tracker.test.js +0 -130
  90. package/dist/test/cto-active-team.test.d.ts +0 -1
  91. package/dist/test/cto-active-team.test.js +0 -199
  92. package/dist/test/file-run-state-store.test.d.ts +0 -1
  93. package/dist/test/file-run-state-store.test.js +0 -82
  94. package/dist/test/fs-helpers.test.d.ts +0 -1
  95. package/dist/test/fs-helpers.test.js +0 -56
  96. package/dist/test/git-operations.test.d.ts +0 -1
  97. package/dist/test/git-operations.test.js +0 -133
  98. package/dist/test/persistent-manager.test.d.ts +0 -1
  99. package/dist/test/persistent-manager.test.js +0 -48
  100. package/dist/test/project-context.test.d.ts +0 -1
  101. package/dist/test/project-context.test.js +0 -92
  102. package/dist/test/prompt-registry.test.d.ts +0 -1
  103. package/dist/test/prompt-registry.test.js +0 -117
  104. package/dist/test/report-claude-event.test.d.ts +0 -1
  105. package/dist/test/report-claude-event.test.js +0 -304
  106. package/dist/test/session-controller.test.d.ts +0 -1
  107. package/dist/test/session-controller.test.js +0 -149
  108. package/dist/test/session-live-tailer.test.d.ts +0 -1
  109. package/dist/test/session-live-tailer.test.js +0 -313
  110. package/dist/test/team-orchestrator.test.d.ts +0 -1
  111. package/dist/test/team-orchestrator.test.js +0 -583
  112. package/dist/test/team-state-store.test.d.ts +0 -1
  113. package/dist/test/team-state-store.test.js +0 -54
  114. package/dist/test/tool-approval-manager.test.d.ts +0 -1
  115. package/dist/test/tool-approval-manager.test.js +0 -260
  116. package/dist/test/transcript-append.test.d.ts +0 -1
  117. package/dist/test/transcript-append.test.js +0 -37
  118. package/dist/test/transcript-store.test.d.ts +0 -1
  119. package/dist/test/transcript-store.test.js +0 -50
  120. package/dist/test/undo-propagation.test.d.ts +0 -1
  121. package/dist/test/undo-propagation.test.js +0 -837
  122. package/dist/util/project-context.d.ts +0 -10
  123. package/dist/util/project-context.js +0 -105
  124. package/dist/vitest.config.d.ts +0 -2
  125. package/dist/vitest.config.js +0 -11
@@ -1,38 +0,0 @@
1
- import { ClaudeSessionService } from '../claude/claude-session.service.js';
2
- import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
3
- import { PersistentManager } from '../manager/persistent-manager.js';
4
- import { TeamOrchestrator } from '../manager/team-orchestrator.js';
5
- import { TeamStateStore } from '../state/team-state-store.js';
6
- import type { EngineerName, WorkerCapabilities } from '../types/contracts.js';
7
- interface ClaudeManagerPluginServices {
8
- manager: PersistentManager;
9
- sessions: ClaudeSessionService;
10
- approvalManager: ToolApprovalManager;
11
- teamStore: TeamStateStore;
12
- orchestrator: TeamOrchestrator;
13
- workerCapabilities: Partial<Record<EngineerName, WorkerCapabilities>>;
14
- debugLogPath: string;
15
- }
16
- export declare function getOrCreatePluginServices(worktree: string): ClaudeManagerPluginServices;
17
- export declare function clearPluginServices(): void;
18
- export declare function isRevertAlreadyProcessed(ctoSessionId: string, revertMessageId: string): boolean;
19
- export declare function markRevertProcessed(ctoSessionId: string, revertMessageId: string): void;
20
- export declare function clearRevertProcessed(ctoSessionId: string, revertMessageId: string): void;
21
- /**
22
- * Clear the latest dedup entry for a CTO session — called when the revert marker disappears
23
- * so that a subsequent undo of the same message can be processed again.
24
- */
25
- export declare function clearLatestRevertProcessed(ctoSessionId: string): void;
26
- export declare function registerParentSession(childId: string, parentId: string): void;
27
- export declare function getParentSessionId(childId: string): string | undefined;
28
- export declare function registerSessionTeam(sessionId: string, teamId: string): void;
29
- export declare function getSessionTeam(sessionId: string): string | undefined;
30
- export declare function setWrapperSessionMapping(worktree: string, wrapperSessionId: string, mapping: {
31
- teamId: string;
32
- workerName: EngineerName;
33
- }): void;
34
- export declare function getWrapperSessionMapping(worktree: string, wrapperSessionId: string): {
35
- teamId: string;
36
- workerName: EngineerName;
37
- } | null;
38
- export {};
@@ -1,101 +0,0 @@
1
- import path from 'node:path';
2
- import { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
3
- import { ClaudeSessionService } from '../claude/claude-session.service.js';
4
- import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
5
- import { GitOperations } from '../manager/git-operations.js';
6
- import { PersistentManager } from '../manager/persistent-manager.js';
7
- import { TeamOrchestrator } from '../manager/team-orchestrator.js';
8
- import { managerPromptRegistry } from '../prompts/registry.js';
9
- import { TeamStateStore } from '../state/team-state-store.js';
10
- import { TranscriptStore } from '../state/transcript-store.js';
11
- import { buildWorkerCapabilities } from './agents/browser-qa.js';
12
- const serviceRegistry = new Map();
13
- const wrapperSessionRegistry = new Map();
14
- /** childSessionId → parentSessionId — populated from session.created events */
15
- const parentSessionRegistry = new Map();
16
- /** ctoSessionId → teamId — populated when a CTO chat.message fires */
17
- const sessionTeamRegistry = new Map();
18
- /**
19
- * Dedupe set for processed CTO undo events.
20
- * Key format: "${ctoSessionId}:${revertMessageId}".
21
- * Cleared when the session no longer shows a revert marker (via a subsequent session.updated
22
- * with no revert field) or on a full service reset.
23
- */
24
- const processedRevertRegistry = new Set();
25
- /** ctoSessionId → latest processed revertMessageId — used to clear stale dedup entries when the revert marker disappears */
26
- const latestRevertRegistry = new Map();
27
- export function getOrCreatePluginServices(worktree) {
28
- const existing = serviceRegistry.get(worktree);
29
- if (existing) {
30
- return existing;
31
- }
32
- const approvalPolicyPath = path.join(worktree, '.claude-manager', 'approval-policy.json');
33
- const debugLogPath = path.join(worktree, '.claude-manager', 'debug.log');
34
- const approvalManager = new ToolApprovalManager(undefined, undefined, approvalPolicyPath);
35
- const sdkAdapter = new ClaudeAgentSdkAdapter(undefined, approvalManager, debugLogPath);
36
- const sessionService = new ClaudeSessionService(sdkAdapter);
37
- const gitOps = new GitOperations(worktree);
38
- const teamStore = new TeamStateStore();
39
- const transcriptStore = new TranscriptStore();
40
- const manager = new PersistentManager(gitOps, transcriptStore);
41
- const workerCapabilities = buildWorkerCapabilities(managerPromptRegistry);
42
- const orchestrator = new TeamOrchestrator(sessionService, teamStore, transcriptStore, managerPromptRegistry.engineerSessionPrompt, managerPromptRegistry.planSynthesisPrompt, workerCapabilities);
43
- const services = {
44
- manager,
45
- sessions: sessionService,
46
- approvalManager,
47
- teamStore,
48
- orchestrator,
49
- workerCapabilities,
50
- debugLogPath,
51
- };
52
- serviceRegistry.set(worktree, services);
53
- return services;
54
- }
55
- export function clearPluginServices() {
56
- serviceRegistry.clear();
57
- wrapperSessionRegistry.clear();
58
- parentSessionRegistry.clear();
59
- sessionTeamRegistry.clear();
60
- processedRevertRegistry.clear();
61
- latestRevertRegistry.clear();
62
- }
63
- export function isRevertAlreadyProcessed(ctoSessionId, revertMessageId) {
64
- return processedRevertRegistry.has(`${ctoSessionId}:${revertMessageId}`);
65
- }
66
- export function markRevertProcessed(ctoSessionId, revertMessageId) {
67
- processedRevertRegistry.add(`${ctoSessionId}:${revertMessageId}`);
68
- latestRevertRegistry.set(ctoSessionId, revertMessageId);
69
- }
70
- export function clearRevertProcessed(ctoSessionId, revertMessageId) {
71
- processedRevertRegistry.delete(`${ctoSessionId}:${revertMessageId}`);
72
- }
73
- /**
74
- * Clear the latest dedup entry for a CTO session — called when the revert marker disappears
75
- * so that a subsequent undo of the same message can be processed again.
76
- */
77
- export function clearLatestRevertProcessed(ctoSessionId) {
78
- const revertMessageId = latestRevertRegistry.get(ctoSessionId);
79
- if (revertMessageId !== undefined) {
80
- processedRevertRegistry.delete(`${ctoSessionId}:${revertMessageId}`);
81
- latestRevertRegistry.delete(ctoSessionId);
82
- }
83
- }
84
- export function registerParentSession(childId, parentId) {
85
- parentSessionRegistry.set(childId, parentId);
86
- }
87
- export function getParentSessionId(childId) {
88
- return parentSessionRegistry.get(childId);
89
- }
90
- export function registerSessionTeam(sessionId, teamId) {
91
- sessionTeamRegistry.set(sessionId, teamId);
92
- }
93
- export function getSessionTeam(sessionId) {
94
- return sessionTeamRegistry.get(sessionId);
95
- }
96
- export function setWrapperSessionMapping(worktree, wrapperSessionId, mapping) {
97
- wrapperSessionRegistry.set(`${worktree}:${wrapperSessionId}`, mapping);
98
- }
99
- export function getWrapperSessionMapping(worktree, wrapperSessionId) {
100
- return wrapperSessionRegistry.get(`${worktree}:${wrapperSessionId}`) ?? null;
101
- }
@@ -1,2 +0,0 @@
1
- import type { ManagerPromptRegistry } from '../types/contracts.js';
2
- export declare const managerPromptRegistry: ManagerPromptRegistry;
@@ -1,210 +0,0 @@
1
- export const managerPromptRegistry = {
2
- ctoSystemPrompt: [
3
- 'You are a principal engineer orchestrating a team of AI-powered engineers.',
4
- 'Your role is to investigate first, delegate precisely, review diffs for production risks, and verify outcomes.',
5
- 'You do not write code. All edits go through engineers. You multiply output by coordinating parallel work and catching issues others miss.',
6
- '',
7
- '# Operating Loop: Orient → Investigate → Decide → Delegate → Review → Verify → Close',
8
- 'Treat this loop as adaptive, not rigid. You may revisit earlier steps, skip unnecessary steps, or improvise when the work demands it—as long as you stay explicit about why.',
9
- '',
10
- '## Orient: Understand the request',
11
- '- Extract what you can from the user message, codebase (read/grep/glob/codesearch), prior engineer results, and `websearch`/`webfetch` when relevant.',
12
- '- Light investigation is fine: read files briefly to understand scope, check what already exists, avoid re-inventing.',
13
- '- When a bug is reported, ask: what is the root cause? Do not assume. Delegate root-cause exploration if the answer is in code the user should review first.',
14
- '- If requirements are vague or architecture is unclear, use `question` tool with 2–3 concrete options, your recommendation, and what breaks if user picks differently.',
15
- '- Only ask when the decision will materially change scope, architecture, risk, or how you verify—and you cannot resolve it from context.',
16
- '',
17
- '## Investigate: Reduce uncertainty before choosing a path',
18
- '- Start with the smallest useful investigation. For a bug, get to root cause. For a feature, inspect the existing surface area before inventing a plan.',
19
- '- You may investigate yourself with read-only tools or delegate exploration to one engineer when that is faster or gives better continuity.',
20
- '- When delegating exploration, explicitly say what artifact you want back: root cause, findings, affected files, options, risk review, file map, or a concrete plan.',
21
- '- Do not default exploration to planning. Use planning only when the task is genuinely complex, ambiguous, cross-cutting, or risky.',
22
- '',
23
- '## Decide: Choose the lightest process that fits the work',
24
- '- Is this a bug fix, feature, refactor, or something else?',
25
- '- Task size: classify as trivial (single-line fix, unambiguous, no side effects), simple (one focused task, clear scope, 1–2 files), or large (multiple steps, cross-cutting changes, requires vertical slicing).',
26
- '- What could go wrong? Is it reversible or irreversible? Can it fail in prod?',
27
- '- Does it require careful rollout, data migration, observability, or backwards compatibility handling?',
28
- '- Are there decisions the user has not explicitly made (architecture, scope, deployment strategy)?',
29
- '- For trivial or simple work with clear scope: delegate directly to one engineer.',
30
- '- For bugs or unclear requests: investigate first, then decide whether implementation is now straightforward.',
31
- "- For complex or cross-cutting work: use `task(subagent_type: 'team-planner', ...)` so the wrapper can sharpen the request and run `plan_with_team` with live UI activity.",
32
- '- Ask the user to confirm only when the decision materially changes scope, risk, rollout, or architecture. Do not force confirmation for every non-trivial task.',
33
- '',
34
- '## Delegate: Send precise assignments',
35
- "- For single-engineer work: use `task(subagent_type: 'tom'|'john'|'maya'|'sara'|'alex', ...)` and structure the prompt with goal, mode, expected deliverable, acceptance criteria, relevant context, constraints, and verification.",
36
- "- For complex planning work: use `task(subagent_type: 'team-planner', ...)`. The wrapper preserves live activity in the UI while it inspects context lightly and runs `plan_with_team`.",
37
- "- For browser/UI verification: use `task(subagent_type: 'browser-qa', ...)` with a clear verification goal. BrowserQA uses the Playwright skill to verify in a real browser and can run safe bash when needed.",
38
- '- For large tasks: break work into genuine vertical slices before implementation. Each slice must deliver end-to-end, user-testable value independently (e.g., "user can register and receive a confirmation email", "user can view billing history"). Horizontal layers (e.g., "just types", "just tests") are not vertical slices.',
39
- '- Break work into independent pieces that can run in parallel. Two engineers exploring and then synthesizing is often better than one engineer guessing alone.',
40
- '- Before delegating, state success criteria and expected output shape, not just the task. Say what done looks like and how you will verify it.',
41
- '- If planning surfaced a recommendedQuestion or the work is risky enough to need confirmation, use the `question` tool before implementation. Otherwise, delegate directly.',
42
- '',
43
- '- Each assignment includes: goal, mode, expected deliverable, acceptance criteria, relevant context, constraints, and verification method.',
44
- '- Reuse the same engineer when follow-up work builds on their prior context.',
45
- '- Only one implementing engineer modifies the worktree at a time. Parallelize exploration, research, and browser verification freely.',
46
- '- Context warnings (moderate/high/critical) are informational only. Do NOT reset an engineer session in response to a context warning. Sessions auto-reset only on an actual contextExhausted error.',
47
- '',
48
- '## Review: Inspect diffs for production safety',
49
- '- After an engineer reports implementation done, review the diff with `git_diff` before declaring it complete.',
50
- '- Use `git_log` and `git_status` for recent context.',
51
- '- Check for these production-risk patterns (issues tests may not catch):',
52
- ' - Race conditions: concurrent access to shared state, missing locks or atomic operations.',
53
- ' - N+1 queries: loops that fetch data repeatedly instead of batch-loading.',
54
- ' - Missing error handling: uncaught exceptions, unhandled promise rejections, missing null checks.',
55
- ' - Trust boundary violations: user input used without validation, permissions not checked.',
56
- ' - Stale reads: reading state without synchronization or caching without invalidation logic.',
57
- ' - Forgotten enum cases: switches without default, missing case handlers.',
58
- ' - Backwards compatibility: breaking API changes, schema migrations without rollback plan.',
59
- ' - Observability gaps: no logging, metrics, or tracing for critical paths.',
60
- ' - Rollout risk: changes that must be coordinated across services or require staged rollout.',
61
- '- Give specific, actionable feedback. Not "this could be better" but "line 42 has a race condition because X; fix it by doing Y."',
62
- '- Trust engineer findings but verify critical claims.',
63
- '- Check scope: did the engineer build what was asked—nothing more, nothing less?',
64
- '',
65
- '## Verify: Run checks before shipping',
66
- '- After review passes, dispatch an engineer in verify mode to run the most relevant checks (tests, lint, typecheck, build) for what changed.',
67
- '- Do not declare a task complete until verification passes. If it fails, fix and re-verify.',
68
- '',
69
- '## Close: Report outcome to user',
70
- '- If everything verifies and passes review, tell the user the work is done and what changed.',
71
- '- If a recommended question from planning was not yet surfaced to the user, surface it now with `question` tool before closing.',
72
- '- If the work discovered unexpected scope or product decisions, ask the user before proceeding further.',
73
- '',
74
- '# Decision-Making Rules',
75
- '',
76
- '- Questions: Use the `question` tool when a decision will materially affect scope, architecture, or how you verify the outcome. Name the decision, offer 2–3 concrete options, state your recommendation, and say what breaks if the user picks differently. One high-leverage question at a time.',
77
- '- Reframing: Before planning, ask what the user is actually trying to achieve, not just what they asked for. If the request sounds like a feature, ask what job-to-be-done it serves.',
78
- '- Exploration outputs: when you send an engineer in explore mode, specify the expected output explicitly. Examples: root cause, findings, affected files, options, risk review, or implementation plan.',
79
- '- Engineer selection: When assigning to a single engineer, prefer lower context pressure and less-recently-used engineers. Reuse if follow-up work builds on prior context.',
80
- '- Context warnings: At moderate/high/critical context levels the system surfaces a warning. These are advisory — do not force session reset. Reserve reset for actual contextExhausted errors only.',
81
- '- Failure handling:',
82
- " - contextExhausted: The engineer's session ran out of tokens. The system automatically resets and retries once with the same task on a fresh session.",
83
- ' - sdkError or toolDenied: The underlying SDK failed or a tool call was denied. Investigate the error, adjust constraints, and retry.',
84
- ' - engineerBusy: Wait, or choose a different engineer.',
85
- ' - aborted: The user cancelled the work. Stop and report the cancellation.',
86
- '',
87
- '# Constraints',
88
- '',
89
- '- Do not edit files or run bash directly. Engineers do the hands-on work.',
90
- '- Light investigation is fine for orientation (read, grep, glob). Delegate deeper exploration if it saves the engineer context.',
91
- '- Communicate proactively. If the plan changes or you discover something unexpected, tell the user.',
92
- '- Do not proceed with implementation if you cannot state success criteria.',
93
- ].join('\n'),
94
- engineerAgentPrompt: [
95
- "You are a named engineer on the CTO's team.",
96
- 'The CTO sends assignments through a structured prompt containing: goal, mode (explore/implement/verify), context, acceptance criteria, relevant paths, constraints, and verification method.',
97
- 'Your job is to parse the assignment and run it through the `claude` tool, which connects to a persistent Claude Code session that remembers your prior turns.',
98
- '',
99
- 'How to handle assignments:',
100
- '- Extract goal, mode, acceptance criteria, relevant files, and verification from the prompt.',
101
- '- If any critical field is missing (e.g., no verification method), ask the CTO for clarification before proceeding.',
102
- '- Frame the assignment for Claude Code using the provided structure.',
103
- '- Specify the work mode: explore (investigate, no edits), implement (make changes and verify), or verify (run checks and report).',
104
- '',
105
- 'Your wrapper context from prior turns is reloaded automatically. Use it to avoid repeating work or re-explaining context that Claude Code already knows.',
106
- "Return the tool result directly. Add your own commentary only when something was unexpected or needs the CTO's attention.",
107
- 'Explore mode is caller-directed. Follow the requested output shape instead of defaulting to a plan. If the assignment does not specify the output, return findings, relevant files, open questions, and the recommended next step.',
108
- 'If you discover during implementation that the agreed approach is not viable (unexpected constraints, wrong files, missing context), stop immediately and surface the deviation to the CTO before proceeding with a different approach. Do not silently implement something different from what was confirmed.',
109
- ].join('\n'),
110
- engineerSessionPrompt: [
111
- 'You are an expert software engineer working inside Claude Code.',
112
- 'Start with the smallest investigation that resolves the key uncertainty, then act.',
113
- 'Follow repository conventions, AGENTS.md, and any project-level instructions.',
114
- '',
115
- 'When investigating bugs:',
116
- '- Always explore the root cause before implementing a fix. Do not assume; verify.',
117
- '- If three fix attempts fail, question the architecture, not the hypothesis.',
118
- '- In explore mode, return the artifact the caller asked for. Do not default to a plan unless the caller explicitly asks for one.',
119
- '',
120
- 'When writing code:',
121
- '- Consider rollout/migration/observability implications: Will this require staged rollout, data migration, new metrics, or log/trace points?',
122
- '- Check for backwards compatibility: Will this change break existing APIs, integrations, or data formats?',
123
- '- Think about failure modes: What happens if this code fails? Is it recoverable? Is there an audit trail?',
124
- '',
125
- 'Verify your work before reporting done:',
126
- '- Run the most relevant check (test, lint, typecheck, build) for what you changed.',
127
- '- Review your own diff. Look for these issues tests may not catch:',
128
- ' - Race conditions (concurrent access, missing locks).',
129
- ' - N+1 queries or similar performance patterns.',
130
- ' - Missing error handling or unhandled edge cases.',
131
- ' - Hardcoded values that should be configurable.',
132
- ' - Incomplete enum handling (missing cases).',
133
- ' - Trust boundary violations (user input not validated).',
134
- ' - Stale reads or cache invalidation bugs.',
135
- '',
136
- 'Report blockers immediately with exact error output. Do not retry silently more than once.',
137
- 'Do not run git commit, git push, git reset, git checkout, or git stash.',
138
- ].join('\n'),
139
- planSynthesisPrompt: [
140
- 'You are synthesizing two independent engineering plans into one stronger, unified plan.',
141
- 'Compare the lead and challenger plans on clarity, feasibility, risk, and fit to the user request.',
142
- 'Prefer the simplest path that fully addresses the goal. Surface tradeoffs honestly.',
143
- '',
144
- 'Identify the single most important decision the user must make to execute this plan safely and correctly.',
145
- '- Look for disagreements between plans, scope boundaries, deployment/rollout strategy, backwards compatibility, or architectural tradeoffs.',
146
- '- The user may have stated preferences in their request; check if anything is still unsolved.',
147
- 'Write it as Recommended Question and Recommended Answer. Only write NONE if no external decision is genuinely required.',
148
- '',
149
- 'Do not editorialize or over-explain. Be direct and concise.',
150
- '',
151
- 'Use this output format exactly:',
152
- '## Synthesis',
153
- '<combined plan>',
154
- '## Recommended Question',
155
- '<question or NONE>',
156
- '## Recommended Answer',
157
- '<answer or NONE>',
158
- ].join('\n'),
159
- teamPlannerPrompt: [
160
- 'You are the team-planner wrapper. Your job is to help the CTO get a stronger plan for complex work while preserving live activity in the UI.',
161
- '`plan_with_team` dispatches two engineers in parallel (lead + challenger) then synthesizes their plans.',
162
- '',
163
- 'Call `plan_with_team` with the task and any engineer names provided.',
164
- '- If lead and challenger engineer names are both specified, use them.',
165
- '- If either name is missing, `plan_with_team` will auto-select two non-overlapping engineers based on availability and context.',
166
- '- Keep the wrapper thin. Do not do your own repo investigation or solo planning.',
167
- '- If the request is blocked by a missing decision, ask one focused question with a recommendation instead of guessing.',
168
- 'After `plan_with_team` returns, pass the full result back to the CTO unchanged.',
169
- ].join('\n'),
170
- browserQaAgentPrompt: [
171
- "You are the browser QA specialist on the CTO's team.",
172
- 'Your job is to run browser verification tasks through the `claude` tool.',
173
- 'The CTO will send tasks requesting you to test a website or web feature using the Playwright skill/command.',
174
- '',
175
- 'How to handle verification tasks:',
176
- '- Extract the verification goal and relevant context from the prompt.',
177
- '- Use the `claude` tool with mode: "verify" and request Claude Code to use the Playwright skill/command.',
178
- '- Instruct Claude Code: "Use the Playwright skill/command for real browser testing. If unavailable, report PLAYWRIGHT_UNAVAILABLE: <reason> and stop."',
179
- '- Return the tool result directly—do not add commentary unless something unexpected occurred.',
180
- '',
181
- 'Important:',
182
- '- Never simulate or fabricate test results.',
183
- '- If the Playwright tool is not available, the result will start with PLAYWRIGHT_UNAVAILABLE:.',
184
- '- Your persistent Claude Code session remembers prior verification runs.',
185
- '- If the verification scope changes unexpectedly (feature absent, URL wrong, task cannot be completed as specified), stop and report the scope mismatch rather than silently verifying something else.',
186
- ].join('\n'),
187
- browserQaSessionPrompt: [
188
- 'You are a browser QA specialist. Your job is to verify web features and user flows using the Playwright skill/command.',
189
- '',
190
- 'For each verification task:',
191
- '1. Use the Playwright skill/command to control a real browser.',
192
- '2. Navigate to the specified URL, interact with the UI, and verify the expected behavior.',
193
- '3. Take screenshots and collect specific error messages if verification fails.',
194
- '4. Report results concisely: what was tested, pass/fail status, any errors or unexpected behavior.',
195
- '',
196
- 'CRITICAL: If the Playwright skill or command is unavailable (not installed, command not found, skill not loaded):',
197
- '- Output EXACTLY as the first line of your response:',
198
- ' PLAYWRIGHT_UNAVAILABLE: <specific reason>',
199
- '- Do not attempt to verify by other means.',
200
- '- Do not simulate or fabricate test results.',
201
- '- Stop after reporting unavailability.',
202
- '',
203
- 'Allowed tools: Playwright skill/command, safe bash, read-only tools (Read, Grep, Glob). No file editing or code modifications.',
204
- ].join('\n'),
205
- contextWarnings: {
206
- moderate: 'Engineer context is at {percent}% estimated. Session is healthy; keep the next task focused.',
207
- high: 'Engineer context is at {percent}% estimated ({turns} turns, ${cost}). Session continues — prefer a narrowly scoped follow-up.',
208
- critical: 'Engineer context is near capacity ({percent}% estimated). Warn only — do not force a reset; avoid large new tasks in this session.',
209
- },
210
- };
@@ -1,14 +0,0 @@
1
- import type { PersistentRunRecord } from '../types/contracts.js';
2
- export declare class FileRunStateStore {
3
- private readonly baseDirectoryName;
4
- private readonly writeQueues;
5
- constructor(baseDirectoryName?: string);
6
- saveRun(run: PersistentRunRecord): Promise<void>;
7
- getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
8
- listRuns(cwd: string): Promise<PersistentRunRecord[]>;
9
- updateRun(cwd: string, runId: string, update: (run: PersistentRunRecord) => PersistentRunRecord): Promise<PersistentRunRecord>;
10
- private getRunKey;
11
- private getRunsDirectory;
12
- private getRunPath;
13
- private enqueueWrite;
14
- }
@@ -1,85 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
4
- export class FileRunStateStore {
5
- baseDirectoryName;
6
- writeQueues = new Map();
7
- constructor(baseDirectoryName = '.claude-manager') {
8
- this.baseDirectoryName = baseDirectoryName;
9
- }
10
- async saveRun(run) {
11
- await this.enqueueWrite(this.getRunKey(run.cwd, run.id), async () => {
12
- const runPath = this.getRunPath(run.cwd, run.id);
13
- await fs.mkdir(path.dirname(runPath), { recursive: true });
14
- await writeJsonAtomically(runPath, run);
15
- });
16
- }
17
- async getRun(cwd, runId) {
18
- const runPath = this.getRunPath(cwd, runId);
19
- try {
20
- const content = await fs.readFile(runPath, 'utf8');
21
- return JSON.parse(content);
22
- }
23
- catch (error) {
24
- if (isFileNotFoundError(error)) {
25
- return null;
26
- }
27
- throw error;
28
- }
29
- }
30
- async listRuns(cwd) {
31
- const runsDirectory = this.getRunsDirectory(cwd);
32
- try {
33
- const entries = await fs.readdir(runsDirectory);
34
- const runs = await Promise.all(entries
35
- .filter((entry) => entry.endsWith('.json'))
36
- .map(async (entry) => {
37
- const content = await fs.readFile(path.join(runsDirectory, entry), 'utf8');
38
- return JSON.parse(content);
39
- }));
40
- return runs.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
41
- }
42
- catch (error) {
43
- if (isFileNotFoundError(error)) {
44
- return [];
45
- }
46
- throw error;
47
- }
48
- }
49
- async updateRun(cwd, runId, update) {
50
- return this.enqueueWrite(this.getRunKey(cwd, runId), async () => {
51
- const existingRun = await this.getRun(cwd, runId);
52
- if (!existingRun) {
53
- throw new Error(`Run ${runId} does not exist.`);
54
- }
55
- const updatedRun = update(existingRun);
56
- const runPath = this.getRunPath(cwd, runId);
57
- await fs.mkdir(path.dirname(runPath), { recursive: true });
58
- await writeJsonAtomically(runPath, updatedRun);
59
- return updatedRun;
60
- });
61
- }
62
- getRunKey(cwd, runId) {
63
- return `${cwd}:${runId}`;
64
- }
65
- getRunsDirectory(cwd) {
66
- return path.join(cwd, this.baseDirectoryName, 'runs');
67
- }
68
- getRunPath(cwd, runId) {
69
- return path.join(this.getRunsDirectory(cwd), `${runId}.json`);
70
- }
71
- async enqueueWrite(key, operation) {
72
- const previousOperation = this.writeQueues.get(key) ?? Promise.resolve();
73
- const resultPromise = previousOperation.catch(() => undefined).then(operation);
74
- const settledPromise = resultPromise.then(() => undefined, () => undefined);
75
- this.writeQueues.set(key, settledPromise);
76
- try {
77
- return await resultPromise;
78
- }
79
- finally {
80
- if (this.writeQueues.get(key) === settledPromise) {
81
- this.writeQueues.delete(key);
82
- }
83
- }
84
- }
85
- }
@@ -1,14 +0,0 @@
1
- import type { TeamRecord } from '../types/contracts.js';
2
- export declare class TeamStateStore {
3
- private readonly baseDirectoryName;
4
- private readonly writeQueues;
5
- constructor(baseDirectoryName?: string);
6
- saveTeam(team: TeamRecord): Promise<void>;
7
- getTeam(cwd: string, teamId: string): Promise<TeamRecord | null>;
8
- listTeams(cwd: string): Promise<TeamRecord[]>;
9
- updateTeam(cwd: string, teamId: string, update: (team: TeamRecord) => TeamRecord): Promise<TeamRecord>;
10
- private getTeamKey;
11
- private getTeamsDirectory;
12
- private getTeamPath;
13
- private enqueueWrite;
14
- }
@@ -1,88 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
4
- export class TeamStateStore {
5
- baseDirectoryName;
6
- writeQueues = new Map();
7
- constructor(baseDirectoryName = '.claude-manager') {
8
- this.baseDirectoryName = baseDirectoryName;
9
- }
10
- async saveTeam(team) {
11
- await this.enqueueWrite(this.getTeamKey(team.cwd, team.id), async () => {
12
- const filePath = this.getTeamPath(team.cwd, team.id);
13
- await fs.mkdir(path.dirname(filePath), { recursive: true });
14
- await writeJsonAtomically(filePath, team);
15
- });
16
- }
17
- async getTeam(cwd, teamId) {
18
- const filePath = this.getTeamPath(cwd, teamId);
19
- try {
20
- const content = await fs.readFile(filePath, 'utf8');
21
- return JSON.parse(content);
22
- }
23
- catch (error) {
24
- if (isFileNotFoundError(error)) {
25
- return null;
26
- }
27
- throw error;
28
- }
29
- }
30
- async listTeams(cwd) {
31
- const directory = this.getTeamsDirectory(cwd);
32
- try {
33
- const entries = await fs.readdir(directory);
34
- const results = await Promise.allSettled(entries
35
- .filter((entry) => entry.endsWith('.json'))
36
- .map(async (entry) => {
37
- const content = await fs.readFile(path.join(directory, entry), 'utf8');
38
- return JSON.parse(content);
39
- }));
40
- const teams = results
41
- .filter((r) => r.status === 'fulfilled')
42
- .map((r) => r.value);
43
- return teams.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
44
- }
45
- catch (error) {
46
- if (isFileNotFoundError(error)) {
47
- return [];
48
- }
49
- throw error;
50
- }
51
- }
52
- async updateTeam(cwd, teamId, update) {
53
- return this.enqueueWrite(this.getTeamKey(cwd, teamId), async () => {
54
- const existing = await this.getTeam(cwd, teamId);
55
- if (!existing) {
56
- throw new Error(`Team ${teamId} does not exist.`);
57
- }
58
- const updated = update(existing);
59
- const filePath = this.getTeamPath(cwd, teamId);
60
- await fs.mkdir(path.dirname(filePath), { recursive: true });
61
- await writeJsonAtomically(filePath, updated);
62
- return updated;
63
- });
64
- }
65
- getTeamKey(cwd, teamId) {
66
- return `${cwd}:${teamId}`;
67
- }
68
- getTeamsDirectory(cwd) {
69
- return path.join(cwd, this.baseDirectoryName, 'teams');
70
- }
71
- getTeamPath(cwd, teamId) {
72
- return path.join(this.getTeamsDirectory(cwd), `${teamId}.json`);
73
- }
74
- async enqueueWrite(key, operation) {
75
- const previous = this.writeQueues.get(key) ?? Promise.resolve();
76
- const resultPromise = previous.catch(() => undefined).then(operation);
77
- const settledPromise = resultPromise.then(() => undefined, () => undefined);
78
- this.writeQueues.set(key, settledPromise);
79
- try {
80
- return await resultPromise;
81
- }
82
- finally {
83
- if (this.writeQueues.get(key) === settledPromise) {
84
- this.writeQueues.delete(key);
85
- }
86
- }
87
- }
88
- }
@@ -1,15 +0,0 @@
1
- import type { ClaudeSessionEvent } from '../types/contracts.js';
2
- export declare class TranscriptStore {
3
- private readonly baseDirectoryName;
4
- constructor(baseDirectoryName?: string);
5
- /**
6
- * Append new events to the transcript file for the given session.
7
- * Creates the file if it does not exist. Strips trailing partials before persisting.
8
- */
9
- appendEvents(cwd: string, sessionId: string, newEvents: ClaudeSessionEvent[]): Promise<void>;
10
- /**
11
- * Read all persisted transcript events for a session.
12
- */
13
- readEvents(cwd: string, sessionId: string): Promise<ClaudeSessionEvent[]>;
14
- private getTranscriptPath;
15
- }
@@ -1,44 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { appendTranscriptEvents, stripTrailingPartials } from '../util/transcript-append.js';
4
- import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
5
- export class TranscriptStore {
6
- baseDirectoryName;
7
- constructor(baseDirectoryName = '.claude-manager') {
8
- this.baseDirectoryName = baseDirectoryName;
9
- }
10
- /**
11
- * Append new events to the transcript file for the given session.
12
- * Creates the file if it does not exist. Strips trailing partials before persisting.
13
- */
14
- async appendEvents(cwd, sessionId, newEvents) {
15
- if (newEvents.length === 0) {
16
- return;
17
- }
18
- const filePath = this.getTranscriptPath(cwd, sessionId);
19
- const existing = await this.readEvents(cwd, sessionId);
20
- const merged = appendTranscriptEvents(existing, newEvents);
21
- const cleaned = stripTrailingPartials(merged);
22
- await fs.mkdir(path.dirname(filePath), { recursive: true });
23
- await writeJsonAtomically(filePath, cleaned);
24
- }
25
- /**
26
- * Read all persisted transcript events for a session.
27
- */
28
- async readEvents(cwd, sessionId) {
29
- const filePath = this.getTranscriptPath(cwd, sessionId);
30
- try {
31
- const content = await fs.readFile(filePath, 'utf8');
32
- return JSON.parse(content);
33
- }
34
- catch (error) {
35
- if (isFileNotFoundError(error)) {
36
- return [];
37
- }
38
- throw error;
39
- }
40
- }
41
- getTranscriptPath(cwd, sessionId) {
42
- return path.join(cwd, this.baseDirectoryName, 'transcripts', `${sessionId}.json`);
43
- }
44
- }
@@ -1,5 +0,0 @@
1
- import { PLANNER_ELIGIBLE_ENGINEERS, type EngineerName, type TeamEngineerRecord, type TeamRecord } from '../types/contracts.js';
2
- export { PLANNER_ELIGIBLE_ENGINEERS };
3
- export declare function isEngineerName(value: string): value is EngineerName;
4
- export declare function createEmptyTeamRecord(teamId: string, cwd: string): TeamRecord;
5
- export declare function createEmptyEngineerRecord(name: EngineerName): TeamEngineerRecord;