oh-my-claude-sisyphus 3.5.7 → 3.6.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.
- package/agents/executor-high.md +2 -0
- package/agents/executor-low.md +2 -0
- package/agents/executor.md +2 -0
- package/agents/templates/base-agent.md +9 -0
- package/commands/cancel.md +8 -8
- package/commands/swarm.md +350 -148
- package/dist/__tests__/hooks/auto-slash-command/executor.test.d.ts +7 -0
- package/dist/__tests__/hooks/auto-slash-command/executor.test.d.ts.map +1 -0
- package/dist/__tests__/hooks/auto-slash-command/executor.test.js +374 -0
- package/dist/__tests__/hooks/auto-slash-command/executor.test.js.map +1 -0
- package/dist/__tests__/hooks/learner/bridge.test.d.ts +11 -0
- package/dist/__tests__/hooks/learner/bridge.test.d.ts.map +1 -0
- package/dist/__tests__/hooks/learner/bridge.test.js +199 -0
- package/dist/__tests__/hooks/learner/bridge.test.js.map +1 -0
- package/dist/__tests__/hooks.test.js +10 -9
- package/dist/__tests__/hooks.test.js.map +1 -1
- package/dist/__tests__/installer.test.js +1 -1
- package/dist/agents/codex-agents.d.ts +20 -0
- package/dist/agents/codex-agents.d.ts.map +1 -0
- package/dist/agents/codex-agents.js +36 -0
- package/dist/agents/codex-agents.js.map +1 -0
- package/dist/agents/preamble.d.ts +14 -0
- package/dist/agents/preamble.d.ts.map +1 -0
- package/dist/agents/preamble.js +26 -0
- package/dist/agents/preamble.js.map +1 -0
- package/dist/hooks/autopilot/__tests__/cancel.test.js +14 -4
- package/dist/hooks/autopilot/__tests__/cancel.test.js.map +1 -1
- package/dist/hooks/autopilot/__tests__/state.test.js +1 -0
- package/dist/hooks/autopilot/__tests__/state.test.js.map +1 -1
- package/dist/hooks/autopilot/__tests__/summary.test.js +38 -3
- package/dist/hooks/autopilot/__tests__/summary.test.js.map +1 -1
- package/dist/hooks/autopilot/state.d.ts +1 -1
- package/dist/hooks/autopilot/state.d.ts.map +1 -1
- package/dist/hooks/autopilot/state.js +15 -8
- package/dist/hooks/autopilot/state.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/learner/bridge.d.ts +71 -0
- package/dist/hooks/learner/bridge.d.ts.map +1 -0
- package/dist/hooks/learner/bridge.js +426 -0
- package/dist/hooks/learner/bridge.js.map +1 -0
- package/dist/hooks/mode-registry/index.d.ts +135 -0
- package/dist/hooks/mode-registry/index.d.ts.map +1 -0
- package/dist/hooks/mode-registry/index.js +445 -0
- package/dist/hooks/mode-registry/index.js.map +1 -0
- package/dist/hooks/mode-registry/types.d.ts +31 -0
- package/dist/hooks/mode-registry/types.d.ts.map +1 -0
- package/dist/hooks/mode-registry/types.js +7 -0
- package/dist/hooks/mode-registry/types.js.map +1 -0
- package/dist/hooks/ralph/loop.js +6 -6
- package/dist/hooks/ralph/loop.js.map +1 -1
- package/dist/hooks/skill-bridge.cjs +349 -0
- package/dist/hooks/swarm/__tests__/claiming.test.d.ts +2 -0
- package/dist/hooks/swarm/__tests__/claiming.test.d.ts.map +1 -0
- package/dist/hooks/swarm/__tests__/claiming.test.js +170 -0
- package/dist/hooks/swarm/__tests__/claiming.test.js.map +1 -0
- package/dist/hooks/swarm/__tests__/index.test.d.ts +2 -0
- package/dist/hooks/swarm/__tests__/index.test.d.ts.map +1 -0
- package/dist/hooks/swarm/__tests__/index.test.js +157 -0
- package/dist/hooks/swarm/__tests__/index.test.js.map +1 -0
- package/dist/hooks/swarm/__tests__/mode-registry.test.d.ts +2 -0
- package/dist/hooks/swarm/__tests__/mode-registry.test.d.ts.map +1 -0
- package/dist/hooks/swarm/__tests__/mode-registry.test.js +177 -0
- package/dist/hooks/swarm/__tests__/mode-registry.test.js.map +1 -0
- package/dist/hooks/swarm/claiming.d.ts +101 -0
- package/dist/hooks/swarm/claiming.d.ts.map +1 -0
- package/dist/hooks/swarm/claiming.js +460 -0
- package/dist/hooks/swarm/claiming.js.map +1 -0
- package/dist/hooks/swarm/index.d.ts +221 -0
- package/dist/hooks/swarm/index.d.ts.map +1 -0
- package/dist/hooks/swarm/index.js +413 -0
- package/dist/hooks/swarm/index.js.map +1 -0
- package/dist/hooks/swarm/state.d.ts +94 -0
- package/dist/hooks/swarm/state.d.ts.map +1 -0
- package/dist/hooks/swarm/state.js +530 -0
- package/dist/hooks/swarm/state.js.map +1 -0
- package/dist/hooks/swarm/types.d.ts +116 -0
- package/dist/hooks/swarm/types.d.ts.map +1 -0
- package/dist/hooks/swarm/types.js +22 -0
- package/dist/hooks/swarm/types.js.map +1 -0
- package/dist/hooks/ultrapilot/decomposer.d.ts +141 -0
- package/dist/hooks/ultrapilot/decomposer.d.ts.map +1 -0
- package/dist/hooks/ultrapilot/decomposer.js +377 -0
- package/dist/hooks/ultrapilot/decomposer.js.map +1 -0
- package/dist/hooks/ultrapilot/index.d.ts +31 -0
- package/dist/hooks/ultrapilot/index.d.ts.map +1 -1
- package/dist/hooks/ultrapilot/index.js +43 -2
- package/dist/hooks/ultrapilot/index.js.map +1 -1
- package/dist/hooks/ultrapilot/state.d.ts +1 -1
- package/dist/hooks/ultrapilot/state.d.ts.map +1 -1
- package/dist/hooks/ultrapilot/state.js +7 -0
- package/dist/hooks/ultrapilot/state.js.map +1 -1
- package/dist/hooks/ultraqa/index.js +5 -5
- package/dist/hooks/ultraqa/index.js.map +1 -1
- package/dist/hooks/ultrawork/index.js +3 -3
- package/dist/hooks/ultrawork/index.js.map +1 -1
- package/dist/installer/index.d.ts +1 -1
- package/dist/installer/index.js +1 -1
- package/package.json +6 -2
- package/scripts/build-skill-bridge.mjs +32 -0
- package/scripts/skill-injector.mjs +77 -26
- package/skills/autopilot/SKILL.md +18 -0
- package/skills/cancel/SKILL.md +166 -141
- package/skills/ecomode/SKILL.md +14 -0
- package/skills/pipeline/SKILL.md +13 -0
- package/skills/ralph/SKILL.md +22 -1
- package/skills/swarm/SKILL.md +521 -197
- package/skills/ultrapilot/SKILL.md +82 -13
- package/skills/ultraqa/SKILL.md +13 -0
- package/skills/ultrawork/SKILL.md +14 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { startSwarm, stopSwarm, getSwarmStatus, isSwarmActive } from '../index.js';
|
|
6
|
+
describe('Swarm Lifecycle', () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
testDir = mkdtempSync(join(tmpdir(), 'swarm-test-'));
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
// Clean up any active swarm before removing directory
|
|
13
|
+
try {
|
|
14
|
+
stopSwarm(true);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Ignore errors if swarm was not active
|
|
18
|
+
}
|
|
19
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
describe('startSwarm', () => {
|
|
22
|
+
it('should start swarm with valid config and create db and marker', async () => {
|
|
23
|
+
const success = await startSwarm({
|
|
24
|
+
agentCount: 3,
|
|
25
|
+
tasks: ['task 1', 'task 2', 'task 3'],
|
|
26
|
+
cwd: testDir
|
|
27
|
+
});
|
|
28
|
+
expect(success).toBe(true);
|
|
29
|
+
// Verify database exists
|
|
30
|
+
const dbPath = join(testDir, '.omc', 'state', 'swarm.db');
|
|
31
|
+
expect(existsSync(dbPath)).toBe(true);
|
|
32
|
+
// Verify marker file exists
|
|
33
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
34
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
35
|
+
// Verify state is active
|
|
36
|
+
const status = getSwarmStatus();
|
|
37
|
+
expect(status).not.toBeNull();
|
|
38
|
+
expect(status?.active).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it('should fail with empty tasks array', async () => {
|
|
41
|
+
const success = await startSwarm({
|
|
42
|
+
agentCount: 3,
|
|
43
|
+
tasks: [],
|
|
44
|
+
cwd: testDir
|
|
45
|
+
});
|
|
46
|
+
expect(success).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
it('should fail with agentCount less than 1', async () => {
|
|
49
|
+
const success = await startSwarm({
|
|
50
|
+
agentCount: 0,
|
|
51
|
+
tasks: ['task 1'],
|
|
52
|
+
cwd: testDir
|
|
53
|
+
});
|
|
54
|
+
expect(success).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
it('should fail when another exclusive mode is active', async () => {
|
|
57
|
+
// Create autopilot state file to simulate active autopilot
|
|
58
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
59
|
+
mkdirSync(stateDir, { recursive: true });
|
|
60
|
+
const autopilotStatePath = join(stateDir, 'autopilot-state.json');
|
|
61
|
+
writeFileSync(autopilotStatePath, JSON.stringify({
|
|
62
|
+
active: true,
|
|
63
|
+
phase: 'execution',
|
|
64
|
+
originalIdea: 'test',
|
|
65
|
+
created_at: Date.now()
|
|
66
|
+
}));
|
|
67
|
+
// Attempt to start swarm should fail
|
|
68
|
+
const success = await startSwarm({
|
|
69
|
+
agentCount: 3,
|
|
70
|
+
tasks: ['task 1'],
|
|
71
|
+
cwd: testDir
|
|
72
|
+
});
|
|
73
|
+
expect(success).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('stopSwarm', () => {
|
|
77
|
+
it('should clean up properly and remove marker', async () => {
|
|
78
|
+
// Start swarm
|
|
79
|
+
await startSwarm({
|
|
80
|
+
agentCount: 2,
|
|
81
|
+
tasks: ['task 1', 'task 2'],
|
|
82
|
+
cwd: testDir
|
|
83
|
+
});
|
|
84
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
85
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
86
|
+
// Stop swarm without deleting database
|
|
87
|
+
const success = stopSwarm(false);
|
|
88
|
+
expect(success).toBe(true);
|
|
89
|
+
// Marker should be removed
|
|
90
|
+
expect(existsSync(markerPath)).toBe(false);
|
|
91
|
+
// Database should still exist
|
|
92
|
+
const dbPath = join(testDir, '.omc', 'state', 'swarm.db');
|
|
93
|
+
expect(existsSync(dbPath)).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
it('should remove database when deleteDatabase=true', async () => {
|
|
96
|
+
await startSwarm({
|
|
97
|
+
agentCount: 2,
|
|
98
|
+
tasks: ['task 1'],
|
|
99
|
+
cwd: testDir
|
|
100
|
+
});
|
|
101
|
+
const dbPath = join(testDir, '.omc', 'state', 'swarm.db');
|
|
102
|
+
expect(existsSync(dbPath)).toBe(true);
|
|
103
|
+
// Stop with deleteDatabase flag
|
|
104
|
+
stopSwarm(true);
|
|
105
|
+
// Database should be deleted
|
|
106
|
+
expect(existsSync(dbPath)).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('getSwarmStatus', () => {
|
|
110
|
+
it('should return null when swarm is not active', () => {
|
|
111
|
+
const status = getSwarmStatus();
|
|
112
|
+
expect(status).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
it('should return correct state when swarm is active', async () => {
|
|
115
|
+
await startSwarm({
|
|
116
|
+
agentCount: 5,
|
|
117
|
+
tasks: ['task 1', 'task 2'],
|
|
118
|
+
cwd: testDir
|
|
119
|
+
});
|
|
120
|
+
const status = getSwarmStatus();
|
|
121
|
+
expect(status).not.toBeNull();
|
|
122
|
+
expect(status?.active).toBe(true);
|
|
123
|
+
expect(status?.agentCount).toBe(5);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe('isSwarmActive', () => {
|
|
127
|
+
it('should detect running swarm', async () => {
|
|
128
|
+
await startSwarm({
|
|
129
|
+
agentCount: 3,
|
|
130
|
+
tasks: ['task 1'],
|
|
131
|
+
cwd: testDir
|
|
132
|
+
});
|
|
133
|
+
expect(isSwarmActive(testDir)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
it('should return false when swarm is not running', () => {
|
|
136
|
+
expect(isSwarmActive(testDir)).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
it('should detect inactive state after swarm is stopped with database preserved', async () => {
|
|
139
|
+
await startSwarm({
|
|
140
|
+
agentCount: 2,
|
|
141
|
+
tasks: ['task 1'],
|
|
142
|
+
cwd: testDir
|
|
143
|
+
});
|
|
144
|
+
expect(isSwarmActive(testDir)).toBe(true);
|
|
145
|
+
stopSwarm(false);
|
|
146
|
+
// After stopSwarm(false), database file still exists
|
|
147
|
+
const dbPath = join(testDir, '.omc', 'state', 'swarm.db');
|
|
148
|
+
expect(existsSync(dbPath)).toBe(true);
|
|
149
|
+
// isSwarmActive checks if db file exists (not if it's truly active)
|
|
150
|
+
// This is expected behavior - database is preserved for analysis
|
|
151
|
+
// For true active detection, use marker file (removed by stopSwarm)
|
|
152
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
153
|
+
expect(existsSync(markerPath)).toBe(false);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../../src/hooks/swarm/__tests__/index.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode-registry.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/swarm/__tests__/mode-registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { canStartMode, createModeMarker, removeModeMarker, isModeActive, readModeMarker } from '../../mode-registry/index.js';
|
|
6
|
+
describe('Mode Registry Integration', () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
testDir = mkdtempSync(join(tmpdir(), 'mode-registry-test-'));
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
13
|
+
});
|
|
14
|
+
describe('canStartMode', () => {
|
|
15
|
+
it('should allow mode when no conflicts exist', () => {
|
|
16
|
+
const result = canStartMode('swarm', testDir);
|
|
17
|
+
expect(result.allowed).toBe(true);
|
|
18
|
+
expect(result.blockedBy).toBeUndefined();
|
|
19
|
+
expect(result.message).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
it('should block when exclusive mode is active', () => {
|
|
22
|
+
// Create autopilot state to simulate active mode
|
|
23
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
24
|
+
mkdirSync(stateDir, { recursive: true });
|
|
25
|
+
const autopilotStatePath = join(stateDir, 'autopilot-state.json');
|
|
26
|
+
writeFileSync(autopilotStatePath, JSON.stringify({
|
|
27
|
+
active: true,
|
|
28
|
+
phase: 'execution',
|
|
29
|
+
originalIdea: 'test',
|
|
30
|
+
created_at: Date.now()
|
|
31
|
+
}));
|
|
32
|
+
const result = canStartMode('swarm', testDir);
|
|
33
|
+
expect(result.allowed).toBe(false);
|
|
34
|
+
expect(result.blockedBy).toBe('autopilot');
|
|
35
|
+
expect(result.message).toContain('Cannot start Swarm');
|
|
36
|
+
expect(result.message).toContain('Autopilot is active');
|
|
37
|
+
});
|
|
38
|
+
it('should block when ultrapilot is active', () => {
|
|
39
|
+
// Create ultrapilot state
|
|
40
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
41
|
+
mkdirSync(stateDir, { recursive: true });
|
|
42
|
+
const ultrapilotStatePath = join(stateDir, 'ultrapilot-state.json');
|
|
43
|
+
writeFileSync(ultrapilotStatePath, JSON.stringify({
|
|
44
|
+
active: true,
|
|
45
|
+
created_at: Date.now()
|
|
46
|
+
}));
|
|
47
|
+
const result = canStartMode('swarm', testDir);
|
|
48
|
+
expect(result.allowed).toBe(false);
|
|
49
|
+
expect(result.blockedBy).toBe('ultrapilot');
|
|
50
|
+
});
|
|
51
|
+
it('should allow non-exclusive modes when swarm is active', () => {
|
|
52
|
+
// Create swarm marker
|
|
53
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
54
|
+
mkdirSync(stateDir, { recursive: true });
|
|
55
|
+
createModeMarker('swarm', testDir, { agentCount: 3 });
|
|
56
|
+
// Ralph is not exclusive, so it should be allowed
|
|
57
|
+
const result = canStartMode('ralph', testDir);
|
|
58
|
+
expect(result.allowed).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('createModeMarker', () => {
|
|
62
|
+
it('should create marker file with metadata', () => {
|
|
63
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
64
|
+
const success = createModeMarker('swarm', testDir, {
|
|
65
|
+
agentCount: 5,
|
|
66
|
+
taskCount: 10
|
|
67
|
+
});
|
|
68
|
+
expect(success).toBe(true);
|
|
69
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
70
|
+
const marker = readModeMarker('swarm', testDir);
|
|
71
|
+
expect(marker).not.toBeNull();
|
|
72
|
+
expect(marker?.mode).toBe('swarm');
|
|
73
|
+
expect(marker?.agentCount).toBe(5);
|
|
74
|
+
expect(marker?.taskCount).toBe(10);
|
|
75
|
+
expect(marker?.startedAt).toBeDefined();
|
|
76
|
+
});
|
|
77
|
+
it('should create directory if it does not exist', () => {
|
|
78
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
79
|
+
// Ensure directory doesn't exist
|
|
80
|
+
expect(existsSync(join(testDir, '.omc'))).toBe(false);
|
|
81
|
+
const success = createModeMarker('swarm', testDir, {});
|
|
82
|
+
expect(success).toBe(true);
|
|
83
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
it('should fail for modes without marker file', () => {
|
|
86
|
+
// autopilot uses JSON state file, not marker
|
|
87
|
+
const success = createModeMarker('autopilot', testDir, {});
|
|
88
|
+
expect(success).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('removeModeMarker', () => {
|
|
92
|
+
it('should delete marker file', () => {
|
|
93
|
+
const markerPath = join(testDir, '.omc', 'state', 'swarm-active.marker');
|
|
94
|
+
createModeMarker('swarm', testDir, {});
|
|
95
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
96
|
+
const success = removeModeMarker('swarm', testDir);
|
|
97
|
+
expect(success).toBe(true);
|
|
98
|
+
expect(existsSync(markerPath)).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
it('should succeed if marker does not exist', () => {
|
|
101
|
+
const success = removeModeMarker('swarm', testDir);
|
|
102
|
+
expect(success).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
it('should succeed for modes without marker file', () => {
|
|
105
|
+
const success = removeModeMarker('autopilot', testDir);
|
|
106
|
+
expect(success).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('isModeActive', () => {
|
|
110
|
+
it('should detect active marker-based mode', () => {
|
|
111
|
+
createModeMarker('swarm', testDir, {});
|
|
112
|
+
expect(isModeActive('swarm', testDir)).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it('should detect active JSON-based mode', () => {
|
|
115
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
116
|
+
mkdirSync(stateDir, { recursive: true });
|
|
117
|
+
writeFileSync(join(stateDir, 'autopilot-state.json'), JSON.stringify({
|
|
118
|
+
active: true,
|
|
119
|
+
phase: 'execution',
|
|
120
|
+
originalIdea: 'test',
|
|
121
|
+
created_at: Date.now()
|
|
122
|
+
}));
|
|
123
|
+
expect(isModeActive('autopilot', testDir)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
it('should return false when mode is not active', () => {
|
|
126
|
+
expect(isModeActive('swarm', testDir)).toBe(false);
|
|
127
|
+
expect(isModeActive('autopilot', testDir)).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
it('should return false when JSON mode is inactive', () => {
|
|
130
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
131
|
+
mkdirSync(stateDir, { recursive: true });
|
|
132
|
+
writeFileSync(join(stateDir, 'autopilot-state.json'), JSON.stringify({
|
|
133
|
+
active: false,
|
|
134
|
+
phase: 'complete',
|
|
135
|
+
originalIdea: 'test',
|
|
136
|
+
created_at: Date.now(),
|
|
137
|
+
completed_at: Date.now()
|
|
138
|
+
}));
|
|
139
|
+
expect(isModeActive('autopilot', testDir)).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('Stale marker detection', () => {
|
|
143
|
+
it('should auto-remove stale markers older than 1 hour', () => {
|
|
144
|
+
// Create marker with old timestamp (simulating stale marker)
|
|
145
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
146
|
+
mkdirSync(stateDir, { recursive: true });
|
|
147
|
+
const markerPath = join(stateDir, 'swarm-active.marker');
|
|
148
|
+
// Create marker with timestamp from 2 hours ago (exceeds 1-hour threshold)
|
|
149
|
+
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
150
|
+
writeFileSync(markerPath, JSON.stringify({
|
|
151
|
+
mode: 'swarm',
|
|
152
|
+
startedAt: twoHoursAgo,
|
|
153
|
+
agentCount: 3
|
|
154
|
+
}));
|
|
155
|
+
// Verify marker file exists
|
|
156
|
+
expect(existsSync(markerPath)).toBe(true);
|
|
157
|
+
// isModeActive should detect stale marker and auto-remove it
|
|
158
|
+
expect(isModeActive('swarm', testDir)).toBe(false);
|
|
159
|
+
// Marker should be deleted after staleness check
|
|
160
|
+
expect(existsSync(markerPath)).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
it('should handle marker files without timestamp', () => {
|
|
163
|
+
const stateDir = join(testDir, '.omc', 'state');
|
|
164
|
+
mkdirSync(stateDir, { recursive: true });
|
|
165
|
+
const markerPath = join(stateDir, 'swarm-active.marker');
|
|
166
|
+
// Create marker without startedAt
|
|
167
|
+
writeFileSync(markerPath, JSON.stringify({
|
|
168
|
+
mode: 'swarm',
|
|
169
|
+
agentCount: 3
|
|
170
|
+
}));
|
|
171
|
+
expect(isModeActive('swarm', testDir)).toBe(true);
|
|
172
|
+
const marker = readModeMarker('swarm', testDir);
|
|
173
|
+
expect(marker?.startedAt).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
//# sourceMappingURL=mode-registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode-registry.test.js","sourceRoot":"","sources":["../../../../src/hooks/swarm/__tests__/mode-registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swarm Task Claiming
|
|
3
|
+
*
|
|
4
|
+
* Atomic task claiming with lease-based ownership.
|
|
5
|
+
* Uses SQLite transactions to ensure only one agent can claim a task.
|
|
6
|
+
* Implements 5-minute lease timeout and heartbeat monitoring.
|
|
7
|
+
*/
|
|
8
|
+
import type { ClaimResult, SwarmTask } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Atomically claim the next available task
|
|
11
|
+
*
|
|
12
|
+
* Uses a transaction to ensure only one agent can claim a task.
|
|
13
|
+
* Claims are lease-based with a 5-minute timeout.
|
|
14
|
+
*
|
|
15
|
+
* @param agentId - Unique identifier for the claiming agent
|
|
16
|
+
* @returns ClaimResult indicating success/failure and task details
|
|
17
|
+
*/
|
|
18
|
+
export declare function claimTask(agentId: string): ClaimResult;
|
|
19
|
+
/**
|
|
20
|
+
* Release a claimed task back to the pending pool
|
|
21
|
+
*
|
|
22
|
+
* Used when an agent fails to complete a task or wants to give it up.
|
|
23
|
+
*
|
|
24
|
+
* @param agentId - Agent releasing the task
|
|
25
|
+
* @param taskId - Task to release
|
|
26
|
+
* @returns true if release was successful
|
|
27
|
+
*/
|
|
28
|
+
export declare function releaseTask(agentId: string, taskId: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Mark a task as completed
|
|
31
|
+
*
|
|
32
|
+
* @param agentId - Agent that completed the task
|
|
33
|
+
* @param taskId - Completed task ID
|
|
34
|
+
* @param result - Optional result/output from the task
|
|
35
|
+
* @returns true if completion was recorded
|
|
36
|
+
*/
|
|
37
|
+
export declare function completeTask(agentId: string, taskId: string, result?: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Mark a task as failed
|
|
40
|
+
*
|
|
41
|
+
* @param agentId - Agent that failed the task
|
|
42
|
+
* @param taskId - Failed task ID
|
|
43
|
+
* @param error - Error message/reason for failure
|
|
44
|
+
* @returns true if failure was recorded
|
|
45
|
+
*/
|
|
46
|
+
export declare function failTask(agentId: string, taskId: string, error: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Record agent heartbeat
|
|
49
|
+
*
|
|
50
|
+
* Agents should call this every 60 seconds to indicate they're still alive.
|
|
51
|
+
* Used by cleanupStaleClaims to detect dead agents.
|
|
52
|
+
*
|
|
53
|
+
* @param agentId - Agent sending heartbeat
|
|
54
|
+
* @returns true if heartbeat was recorded
|
|
55
|
+
*/
|
|
56
|
+
export declare function heartbeat(agentId: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Clean up stale claims from dead agents
|
|
59
|
+
*
|
|
60
|
+
* Releases tasks that have been claimed for longer than the lease timeout
|
|
61
|
+
* (default 5 minutes) by agents that haven't sent a heartbeat.
|
|
62
|
+
*
|
|
63
|
+
* @param leaseTimeout - Lease timeout in milliseconds (default: 5 minutes)
|
|
64
|
+
* @returns Number of tasks released
|
|
65
|
+
*/
|
|
66
|
+
export declare function cleanupStaleClaims(leaseTimeout?: number): number;
|
|
67
|
+
/**
|
|
68
|
+
* Get tasks claimed by a specific agent
|
|
69
|
+
*
|
|
70
|
+
* @param agentId - Agent to query
|
|
71
|
+
* @returns Array of tasks claimed by the agent
|
|
72
|
+
*/
|
|
73
|
+
export declare function getTasksClaimedBy(agentId: string): SwarmTask[];
|
|
74
|
+
/**
|
|
75
|
+
* Check if there are any pending tasks
|
|
76
|
+
*
|
|
77
|
+
* @returns true if there are pending tasks
|
|
78
|
+
*/
|
|
79
|
+
export declare function hasPendingTasks(): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Check if all tasks are complete (done or failed)
|
|
82
|
+
*
|
|
83
|
+
* @returns true if all tasks are complete
|
|
84
|
+
*/
|
|
85
|
+
export declare function allTasksComplete(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Get the number of active agents (with recent heartbeats)
|
|
88
|
+
*
|
|
89
|
+
* @param heartbeatTimeout - How old a heartbeat can be to still be considered active
|
|
90
|
+
* @returns Number of active agents
|
|
91
|
+
*/
|
|
92
|
+
export declare function getActiveAgentCount(heartbeatTimeout?: number): number;
|
|
93
|
+
/**
|
|
94
|
+
* Attempt to reclaim a failed task
|
|
95
|
+
*
|
|
96
|
+
* @param agentId - Agent attempting to reclaim
|
|
97
|
+
* @param taskId - Task to reclaim
|
|
98
|
+
* @returns ClaimResult
|
|
99
|
+
*/
|
|
100
|
+
export declare function reclaimFailedTask(agentId: string, taskId: string): ClaimResult;
|
|
101
|
+
//# sourceMappingURL=claiming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claiming.d.ts","sourceRoot":"","sources":["../../../src/hooks/swarm/claiming.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAazD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAqEtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAsCpE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAsCtF;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAsChF;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgBlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,GAAE,MAA0C,GAAG,MAAM,CA2DnG;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAiC9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAczC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAc1C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,GAAE,MAA0C,GAAG,MAAM,CAexG;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAgE9E"}
|