@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,260 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { ToolApprovalManager } from '../src/claude/tool-approval-manager.js';
3
- describe('ToolApprovalManager', () => {
4
- describe('evaluate()', () => {
5
- it('allows Skill tool by default policy', () => {
6
- const manager = new ToolApprovalManager();
7
- const result = manager.evaluate('Skill', { command: 'my-skill' });
8
- expect(result).toEqual({ behavior: 'allow' });
9
- });
10
- it('allows read-only tools by default policy', () => {
11
- const manager = new ToolApprovalManager();
12
- expect(manager.evaluate('Read', { file_path: '/tmp/foo.ts' })).toEqual({
13
- behavior: 'allow',
14
- });
15
- expect(manager.evaluate('Grep', { pattern: 'foo' })).toEqual({
16
- behavior: 'allow',
17
- });
18
- expect(manager.evaluate('Glob', { pattern: '*.ts' })).toEqual({
19
- behavior: 'allow',
20
- });
21
- });
22
- it('allows edit tools by default policy', () => {
23
- const manager = new ToolApprovalManager();
24
- expect(manager.evaluate('Edit', {
25
- file_path: '/tmp/foo.ts',
26
- old_string: 'a',
27
- new_string: 'b',
28
- })).toEqual({ behavior: 'allow' });
29
- expect(manager.evaluate('Write', {
30
- file_path: '/tmp/foo.ts',
31
- content: 'hello',
32
- })).toEqual({ behavior: 'allow' });
33
- });
34
- it('denies bash rm -rf on root', () => {
35
- const manager = new ToolApprovalManager();
36
- const result = manager.evaluate('Bash', { command: 'rm -rf /' });
37
- expect(result.behavior).toBe('deny');
38
- if (result.behavior === 'deny') {
39
- expect(result.message).toContain('rm -rf');
40
- }
41
- });
42
- it('denies git push --force', () => {
43
- const manager = new ToolApprovalManager();
44
- const result = manager.evaluate('Bash', {
45
- command: 'git push --force origin main',
46
- });
47
- expect(result.behavior).toBe('deny');
48
- if (result.behavior === 'deny') {
49
- expect(result.message).toContain('Force push');
50
- }
51
- });
52
- it('denies git reset --hard', () => {
53
- const manager = new ToolApprovalManager();
54
- const result = manager.evaluate('Bash', {
55
- command: 'git reset --hard HEAD',
56
- });
57
- expect(result.behavior).toBe('deny');
58
- if (result.behavior === 'deny') {
59
- expect(result.message).toContain('git reset --hard');
60
- }
61
- });
62
- it('allows normal bash commands', () => {
63
- const manager = new ToolApprovalManager();
64
- expect(manager.evaluate('Bash', { command: 'ls -la' })).toEqual({
65
- behavior: 'allow',
66
- });
67
- expect(manager.evaluate('Bash', { command: 'pnpm test' })).toEqual({
68
- behavior: 'allow',
69
- });
70
- });
71
- it('returns allow when disabled', () => {
72
- const manager = new ToolApprovalManager({ enabled: false });
73
- const result = manager.evaluate('Bash', { command: 'rm -rf /' });
74
- expect(result).toEqual({ behavior: 'allow' });
75
- });
76
- it('allows tools when no rule matches (deny-list contract)', () => {
77
- const manager = new ToolApprovalManager({
78
- rules: [],
79
- });
80
- const result = manager.evaluate('SomeUnknownTool', {});
81
- expect(result.behavior).toBe('allow');
82
- });
83
- it('first matching rule wins', () => {
84
- const manager = new ToolApprovalManager({
85
- rules: [
86
- {
87
- id: 'deny-all-bash',
88
- toolPattern: 'Bash',
89
- action: 'deny',
90
- denyMessage: 'No bash',
91
- },
92
- { id: 'allow-bash', toolPattern: 'Bash', action: 'allow' },
93
- ],
94
- defaultAction: 'allow',
95
- enabled: true,
96
- });
97
- const result = manager.evaluate('Bash', { command: 'echo hi' });
98
- expect(result.behavior).toBe('deny');
99
- });
100
- it('matches glob patterns in tool names', () => {
101
- const manager = new ToolApprovalManager({
102
- rules: [
103
- {
104
- id: 'deny-notebook',
105
- toolPattern: 'Notebook*',
106
- action: 'deny',
107
- denyMessage: 'No notebooks',
108
- },
109
- ],
110
- defaultAction: 'allow',
111
- enabled: true,
112
- });
113
- expect(manager.evaluate('NotebookEdit', {}).behavior).toBe('deny');
114
- expect(manager.evaluate('NotebookRead', {}).behavior).toBe('deny');
115
- expect(manager.evaluate('Read', {}).behavior).toBe('allow');
116
- });
117
- it('matches inputPattern as substring of serialized input', () => {
118
- const manager = new ToolApprovalManager({
119
- rules: [
120
- {
121
- id: 'deny-secret-files',
122
- toolPattern: '*',
123
- inputPattern: '.env',
124
- action: 'deny',
125
- denyMessage: 'No .env access',
126
- },
127
- ],
128
- defaultAction: 'allow',
129
- enabled: true,
130
- });
131
- expect(manager.evaluate('Read', { file_path: '/project/.env' }).behavior).toBe('deny');
132
- expect(manager.evaluate('Read', { file_path: '/project/src/index.ts' }).behavior).toBe('allow');
133
- });
134
- it('records decisions in the log', () => {
135
- const manager = new ToolApprovalManager();
136
- manager.evaluate('Read', { file_path: '/tmp/foo.ts' });
137
- const decisions = manager.getDecisions();
138
- expect(decisions).toHaveLength(1);
139
- expect(decisions[0].toolName).toBe('Read');
140
- expect(decisions[0].action).toBe('allow');
141
- expect(decisions[0].matchedRuleId).toBe('allow-read');
142
- });
143
- });
144
- describe('policy management', () => {
145
- it('addRule inserts at specified position', async () => {
146
- const manager = new ToolApprovalManager({
147
- rules: [],
148
- enabled: true,
149
- defaultAction: 'allow',
150
- });
151
- await manager.addRule({ id: 'a', toolPattern: 'A', action: 'allow' });
152
- await manager.addRule({ id: 'b', toolPattern: 'B', action: 'allow' });
153
- await manager.addRule({ id: 'c', toolPattern: 'C', action: 'deny' }, 1);
154
- const rules = manager.getPolicy().rules;
155
- expect(rules.map((r) => r.id)).toEqual(['a', 'c', 'b']);
156
- });
157
- it('addRule appends to end by default', async () => {
158
- const manager = new ToolApprovalManager({
159
- rules: [],
160
- enabled: true,
161
- defaultAction: 'allow',
162
- });
163
- await manager.addRule({ id: 'a', toolPattern: 'A', action: 'allow' });
164
- await manager.addRule({ id: 'b', toolPattern: 'B', action: 'allow' });
165
- expect(manager.getPolicy().rules.map((r) => r.id)).toEqual(['a', 'b']);
166
- });
167
- it('removeRule removes by ID and returns true', async () => {
168
- const manager = new ToolApprovalManager();
169
- const removed = await manager.removeRule('allow-read');
170
- expect(removed).toBe(true);
171
- expect(manager.getPolicy().rules.find((r) => r.id === 'allow-read')).toBeUndefined();
172
- });
173
- it('removeRule returns false for non-existent ID', async () => {
174
- const manager = new ToolApprovalManager();
175
- expect(await manager.removeRule('nonexistent')).toBe(false);
176
- });
177
- it('setPolicy replaces entire policy and normalizes defaultAction to allow', async () => {
178
- const manager = new ToolApprovalManager();
179
- await manager.setPolicy({
180
- rules: [{ id: 'only', toolPattern: '*', action: 'deny' }],
181
- defaultAction: 'allow',
182
- enabled: true,
183
- });
184
- expect(manager.getPolicy().rules).toHaveLength(1);
185
- expect(manager.getPolicy().defaultAction).toBe('allow');
186
- });
187
- it('setDefaultAction rejects deny', async () => {
188
- const manager = new ToolApprovalManager({
189
- rules: [],
190
- enabled: true,
191
- });
192
- await expect(manager.setDefaultAction('deny')).rejects.toThrow(/defaultAction cannot be deny/);
193
- });
194
- it('setEnabled toggles the manager', async () => {
195
- const manager = new ToolApprovalManager({
196
- rules: [
197
- {
198
- id: 'deny-all',
199
- toolPattern: '*',
200
- action: 'deny',
201
- denyMessage: 'blocked',
202
- },
203
- ],
204
- enabled: true,
205
- });
206
- expect(manager.evaluate('Read', {}).behavior).toBe('deny');
207
- await manager.setEnabled(false);
208
- expect(manager.evaluate('Read', {}).behavior).toBe('allow');
209
- });
210
- });
211
- describe('decision log', () => {
212
- it('getDecisions returns most recent first', () => {
213
- const manager = new ToolApprovalManager();
214
- manager.evaluate('Read', {});
215
- manager.evaluate('Grep', {});
216
- manager.evaluate('Glob', {});
217
- const decisions = manager.getDecisions();
218
- expect(decisions[0].toolName).toBe('Glob');
219
- expect(decisions[2].toolName).toBe('Read');
220
- });
221
- it('getDeniedDecisions filters to denials only', () => {
222
- const manager = new ToolApprovalManager();
223
- manager.evaluate('Read', {});
224
- manager.evaluate('Bash', { command: 'rm -rf /' });
225
- manager.evaluate('Grep', {});
226
- const denied = manager.getDeniedDecisions();
227
- expect(denied).toHaveLength(1);
228
- expect(denied[0].toolName).toBe('Bash');
229
- });
230
- it('clearDecisions empties the log', () => {
231
- const manager = new ToolApprovalManager();
232
- manager.evaluate('Read', {});
233
- manager.evaluate('Grep', {});
234
- manager.clearDecisions();
235
- expect(manager.getDecisions()).toHaveLength(0);
236
- });
237
- it('respects maxDecisions ring buffer limit', () => {
238
- const manager = new ToolApprovalManager({}, 3);
239
- manager.evaluate('Read', {});
240
- manager.evaluate('Grep', {});
241
- manager.evaluate('Glob', {});
242
- manager.evaluate('Edit', {});
243
- const decisions = manager.getDecisions();
244
- expect(decisions).toHaveLength(3);
245
- // Oldest (Read) should be evicted
246
- expect(decisions.map((d) => d.toolName)).toEqual(['Edit', 'Glob', 'Grep']);
247
- });
248
- it('includes agentId when provided', () => {
249
- const manager = new ToolApprovalManager();
250
- manager.evaluate('Read', {}, { agentID: 'agent_123' });
251
- expect(manager.getDecisions()[0].agentId).toBe('agent_123');
252
- });
253
- it('truncates inputPreview for large inputs', () => {
254
- const manager = new ToolApprovalManager();
255
- manager.evaluate('Read', { data: 'x'.repeat(1000) });
256
- const decision = manager.getDecisions()[0];
257
- expect(decision.inputPreview.length).toBeLessThanOrEqual(300);
258
- });
259
- });
260
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,37 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { appendTranscriptEvents, stripTrailingPartials } from '../src/util/transcript-append.js';
3
- function ev(type, text) {
4
- return { type, text };
5
- }
6
- describe('transcript-append', () => {
7
- it('replaces the last partial when another partial arrives', () => {
8
- const next = appendTranscriptEvents([], [ev('partial', 'a')]);
9
- expect(next).toEqual([ev('partial', 'a')]);
10
- const next2 = appendTranscriptEvents(next, [ev('partial', 'ab')]);
11
- expect(next2).toEqual([ev('partial', 'ab')]);
12
- });
13
- it('strips trailing partials before a non-partial event', () => {
14
- const base = appendTranscriptEvents([], [ev('partial', 'streaming')]);
15
- const next = appendTranscriptEvents(base, [ev('assistant', 'Final answer.')]);
16
- expect(next.map((e) => e.type)).toEqual(['assistant']);
17
- expect(next[0]?.text).toBe('Final answer.');
18
- });
19
- it('stripTrailingPartials removes only trailing partials', () => {
20
- const events = [
21
- ev('init', 'init'),
22
- ev('partial', 'x'),
23
- ev('assistant', 'done'),
24
- ev('partial', 'orphan'),
25
- ];
26
- expect(stripTrailingPartials(events).map((e) => e.type)).toEqual([
27
- 'init',
28
- 'partial',
29
- 'assistant',
30
- ]);
31
- });
32
- it('appends multiple incoming events in order with partial rules', () => {
33
- const batch = appendTranscriptEvents([ev('init', 'init')], [ev('partial', 'p1'), ev('partial', 'p2'), ev('user', 'tool output')]);
34
- expect(batch.map((e) => e.type)).toEqual(['init', 'user']);
35
- expect(batch[1]?.text).toBe('tool output');
36
- });
37
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,50 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { describe, expect, it, beforeEach, afterEach } from 'vitest';
4
- import { TranscriptStore } from '../src/state/transcript-store.js';
5
- function ev(type, text) {
6
- return { type, text };
7
- }
8
- describe('TranscriptStore', () => {
9
- const testDir = path.join(process.cwd(), '.test-transcript-store-' + process.pid);
10
- let store;
11
- beforeEach(async () => {
12
- await fs.mkdir(testDir, { recursive: true });
13
- store = new TranscriptStore('.claude-manager');
14
- });
15
- afterEach(async () => {
16
- await fs.rm(testDir, { recursive: true, force: true });
17
- });
18
- it('returns empty array for nonexistent session', async () => {
19
- const events = await store.readEvents(testDir, 'nonexistent');
20
- expect(events).toEqual([]);
21
- });
22
- it('appends and reads events', async () => {
23
- await store.appendEvents(testDir, 'ses_1', [ev('init', 'init'), ev('assistant', 'Hello.')]);
24
- const events = await store.readEvents(testDir, 'ses_1');
25
- expect(events).toEqual([ev('init', 'init'), ev('assistant', 'Hello.')]);
26
- });
27
- it('accumulates events across multiple appends', async () => {
28
- await store.appendEvents(testDir, 'ses_2', [
29
- ev('init', 'init'),
30
- ev('assistant', 'First response.'),
31
- ]);
32
- await store.appendEvents(testDir, 'ses_2', [
33
- ev('user', 'Follow-up question'),
34
- ev('assistant', 'Second response.'),
35
- ]);
36
- const events = await store.readEvents(testDir, 'ses_2');
37
- expect(events.map((e) => e.type)).toEqual(['init', 'assistant', 'user', 'assistant']);
38
- expect(events[3].text).toBe('Second response.');
39
- });
40
- it('strips trailing partials before persisting', async () => {
41
- await store.appendEvents(testDir, 'ses_3', [ev('init', 'init'), ev('partial', 'streaming...')]);
42
- const events = await store.readEvents(testDir, 'ses_3');
43
- expect(events).toEqual([ev('init', 'init')]);
44
- });
45
- it('skips write when newEvents is empty', async () => {
46
- await store.appendEvents(testDir, 'ses_4', []);
47
- const events = await store.readEvents(testDir, 'ses_4');
48
- expect(events).toEqual([]);
49
- });
50
- });
@@ -1 +0,0 @@
1
- export {};