@s_s/harmonia 1.2.0 → 1.4.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/README.md +140 -392
- package/build/cli/setup.d.ts +4 -2
- package/build/cli/setup.js +44 -18
- package/build/cli/setup.js.map +1 -1
- package/build/core/action-registry.d.ts +36 -0
- package/build/core/action-registry.js +53 -0
- package/build/core/action-registry.js.map +1 -0
- package/build/core/artifacts.d.ts +66 -0
- package/build/core/artifacts.js +178 -0
- package/build/core/artifacts.js.map +1 -0
- package/build/core/dispatch.d.ts +18 -11
- package/build/core/dispatch.js +43 -33
- package/build/core/dispatch.js.map +1 -1
- package/build/core/issues.d.ts +37 -0
- package/build/core/issues.js +100 -0
- package/build/core/issues.js.map +1 -0
- package/build/core/overrides.d.ts +19 -26
- package/build/core/overrides.js +32 -98
- package/build/core/overrides.js.map +1 -1
- package/build/core/plugin.d.ts +86 -0
- package/build/core/plugin.js +332 -0
- package/build/core/plugin.js.map +1 -0
- package/build/core/registry.d.ts +36 -3
- package/build/core/registry.js +63 -5
- package/build/core/registry.js.map +1 -1
- package/build/core/reviews.d.ts +13 -13
- package/build/core/reviews.js +31 -32
- package/build/core/reviews.js.map +1 -1
- package/build/core/schema.d.ts +43 -15
- package/build/core/schema.js +124 -20
- package/build/core/schema.js.map +1 -1
- package/build/core/state.d.ts +29 -22
- package/build/core/state.js +49 -81
- package/build/core/state.js.map +1 -1
- package/build/core/steps.d.ts +15 -15
- package/build/core/steps.js +32 -33
- package/build/core/steps.js.map +1 -1
- package/build/core/tree-utils.d.ts +52 -0
- package/build/core/tree-utils.js +226 -0
- package/build/core/tree-utils.js.map +1 -0
- package/build/core/types.d.ts +417 -117
- package/build/core/types.js +15 -1
- package/build/core/types.js.map +1 -1
- package/build/core/workflow-engine.d.ts +68 -0
- package/build/core/workflow-engine.js +821 -0
- package/build/core/workflow-engine.js.map +1 -0
- package/build/core/workflow-validator.d.ts +22 -0
- package/build/core/workflow-validator.js +489 -0
- package/build/core/workflow-validator.js.map +1 -0
- package/build/index.js +28 -25
- package/build/index.js.map +1 -1
- package/build/setup/inject.d.ts +4 -4
- package/build/setup/inject.js +6 -6
- package/build/setup/inject.js.map +1 -1
- package/build/setup/templates.d.ts +9 -7
- package/build/setup/templates.js +68 -103
- package/build/setup/templates.js.map +1 -1
- package/build/tools/artifact-approve.d.ts +8 -0
- package/build/tools/artifact-approve.js +94 -0
- package/build/tools/artifact-approve.js.map +1 -0
- package/build/tools/artifact-schema.d.ts +12 -0
- package/build/tools/artifact-schema.js +148 -0
- package/build/tools/artifact-schema.js.map +1 -0
- package/build/tools/artifact-tools.d.ts +18 -0
- package/build/tools/artifact-tools.js +465 -0
- package/build/tools/artifact-tools.js.map +1 -0
- package/build/tools/{report-dispatch.d.ts → dispatch-report.d.ts} +7 -3
- package/build/tools/dispatch-report.js +261 -0
- package/build/tools/dispatch-report.js.map +1 -0
- package/build/tools/engine-helpers.d.ts +41 -0
- package/build/tools/engine-helpers.js +182 -0
- package/build/tools/engine-helpers.js.map +1 -0
- package/build/tools/get-project-status.d.ts +6 -4
- package/build/tools/get-project-status.js +308 -246
- package/build/tools/get-project-status.js.map +1 -1
- package/build/tools/get-role-prompt.d.ts +1 -1
- package/build/tools/get-role-prompt.js +7 -41
- package/build/tools/get-role-prompt.js.map +1 -1
- package/build/tools/issue-tools.d.ts +10 -0
- package/build/tools/issue-tools.js +169 -0
- package/build/tools/issue-tools.js.map +1 -0
- package/build/tools/iteration-start.d.ts +7 -4
- package/build/tools/iteration-start.js +51 -20
- package/build/tools/iteration-start.js.map +1 -1
- package/build/tools/loop-done.d.ts +11 -0
- package/build/tools/loop-done.js +109 -0
- package/build/tools/loop-done.js.map +1 -0
- package/build/tools/patch-start.d.ts +16 -0
- package/build/tools/patch-start.js +122 -0
- package/build/tools/patch-start.js.map +1 -0
- package/build/tools/project-init.d.ts +5 -5
- package/build/tools/project-init.js +47 -18
- package/build/tools/project-init.js.map +1 -1
- package/build/tools/role-dispatch.d.ts +55 -0
- package/build/tools/role-dispatch.js +508 -0
- package/build/tools/role-dispatch.js.map +1 -0
- package/build/tools/utils.d.ts +40 -0
- package/build/tools/utils.js +97 -0
- package/build/tools/utils.js.map +1 -0
- package/package.json +1 -1
- package/{build/hooks/claude-code.js → workflows/dev/hooks/claude.js} +34 -23
- package/{build → workflows/dev}/hooks/content.js +27 -18
- package/workflows/dev/hooks/index.js +52 -0
- package/{build → workflows/dev}/hooks/openclaw.js +31 -20
- package/{build → workflows/dev}/hooks/opencode.js +31 -20
- package/workflows/dev/roles/architect.md +68 -28
- package/workflows/dev/roles/coordinator.md +103 -0
- package/workflows/dev/roles/developer.md +5 -5
- package/workflows/dev/roles/tester.md +19 -19
- package/workflows/dev/schemas/api-contract.json +42 -0
- package/workflows/dev/schemas/api-design.json +30 -13
- package/workflows/dev/schemas/data-model.json +20 -7
- package/workflows/dev/schemas/prd.completeness-check.json +6 -5
- package/workflows/dev/schemas/prd.draft.json +13 -5
- package/workflows/dev/schemas/prd.final.json +34 -11
- package/workflows/dev/schemas/prd.json +29 -11
- package/workflows/dev/schemas/prd.requirements.json +6 -5
- package/workflows/dev/schemas/prototype.json +6 -2
- package/workflows/dev/schemas/task-breakdown.coarse.json +4 -3
- package/workflows/dev/schemas/task-breakdown.dependencies.json +5 -4
- package/workflows/dev/schemas/task-breakdown.detailed.json +8 -3
- package/workflows/dev/schemas/task-breakdown.final.json +8 -3
- package/workflows/dev/schemas/task-breakdown.json +8 -3
- package/workflows/dev/schemas/tech-design.analysis.json +6 -5
- package/workflows/dev/schemas/tech-design.draft.json +14 -5
- package/workflows/dev/schemas/tech-design.final.json +39 -13
- package/workflows/dev/schemas/tech-design.json +34 -13
- package/workflows/dev/schemas/tech-design.research.json +21 -0
- package/workflows/dev/schemas/test-plan.json +17 -7
- package/workflows/dev/schemas/test-report.json +26 -9
- package/workflows/dev/schemas/user-stories.json +7 -3
- package/workflows/dev/tools/index.js +23 -0
- package/workflows/dev/workflow.json +234 -101
- package/build/core/docs.d.ts +0 -32
- package/build/core/docs.js +0 -91
- package/build/core/docs.js.map +0 -1
- package/build/core/workflow.d.ts +0 -33
- package/build/core/workflow.js +0 -140
- package/build/core/workflow.js.map +0 -1
- package/build/hooks/claude-code.d.ts +0 -20
- package/build/hooks/claude-code.js.map +0 -1
- package/build/hooks/content.d.ts +0 -43
- package/build/hooks/content.js.map +0 -1
- package/build/hooks/install.d.ts +0 -40
- package/build/hooks/install.js +0 -63
- package/build/hooks/install.js.map +0 -1
- package/build/hooks/openclaw.d.ts +0 -24
- package/build/hooks/openclaw.js.map +0 -1
- package/build/hooks/opencode.d.ts +0 -29
- package/build/hooks/opencode.js.map +0 -1
- package/build/tools/approve-doc.d.ts +0 -6
- package/build/tools/approve-doc.js +0 -108
- package/build/tools/approve-doc.js.map +0 -1
- package/build/tools/dispatch-role.d.ts +0 -16
- package/build/tools/dispatch-role.js +0 -277
- package/build/tools/dispatch-role.js.map +0 -1
- package/build/tools/doc-tools.d.ts +0 -16
- package/build/tools/doc-tools.js +0 -389
- package/build/tools/doc-tools.js.map +0 -1
- package/build/tools/override-tools.d.ts +0 -6
- package/build/tools/override-tools.js +0 -129
- package/build/tools/override-tools.js.map +0 -1
- package/build/tools/report-dispatch.js +0 -194
- package/build/tools/report-dispatch.js.map +0 -1
- package/build/tools/set-scale.d.ts +0 -6
- package/build/tools/set-scale.js +0 -107
- package/build/tools/set-scale.js.map +0 -1
- package/build/tools/setup-project.d.ts +0 -8
- package/build/tools/setup-project.js +0 -116
- package/build/tools/setup-project.js.map +0 -1
- package/build/tools/update-phase.d.ts +0 -12
- package/build/tools/update-phase.js +0 -159
- package/build/tools/update-phase.js.map +0 -1
- package/workflows/dev/roles/pm.md +0 -99
- package/workflows/dev/schemas/deploy.json +0 -20
- package/workflows/dev/schemas/fsd.json +0 -25
- package/workflows/dev/schemas/project-plan.json +0 -20
- package/workflows/dev/schemas/retrospective.json +0 -20
- package/workflows/dev/schemas/risk-assessment.json +0 -15
- package/workflows/dev/schemas/tech-design.api-contract.json +0 -20
package/build/core/dispatch.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dispatch & Session tracking — manages:
|
|
3
|
-
* <
|
|
4
|
-
* <
|
|
3
|
+
* <context_dir>/sessions.json
|
|
4
|
+
* <context_dir>/dispatches.json
|
|
5
|
+
*
|
|
6
|
+
* context_dir is typically iter-<n>/ or patch-<n>/ under the project data dir.
|
|
5
7
|
*
|
|
6
8
|
* Sessions represent agent instances (can be reused across dispatches).
|
|
7
9
|
* Dispatches represent individual task assignments to a role.
|
|
@@ -9,27 +11,26 @@
|
|
|
9
11
|
*/
|
|
10
12
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
11
13
|
import { join, dirname } from 'node:path';
|
|
12
|
-
import { getIterationDir } from './registry.js';
|
|
13
14
|
const SESSIONS_FILE = 'sessions.json';
|
|
14
15
|
const DISPATCHES_FILE = 'dispatches.json';
|
|
15
|
-
function sessionsPath(projectName, iteration) {
|
|
16
|
-
return join(
|
|
16
|
+
function sessionsPath(projectName, iteration, contextDir) {
|
|
17
|
+
return join(contextDir, SESSIONS_FILE);
|
|
17
18
|
}
|
|
18
|
-
function dispatchesPath(projectName, iteration) {
|
|
19
|
-
return join(
|
|
19
|
+
function dispatchesPath(projectName, iteration, contextDir) {
|
|
20
|
+
return join(contextDir, DISPATCHES_FILE);
|
|
20
21
|
}
|
|
21
22
|
// ─── Session CRUD ───
|
|
22
|
-
export async function readSessions(projectName, iteration) {
|
|
23
|
+
export async function readSessions(projectName, iteration, contextDir) {
|
|
23
24
|
try {
|
|
24
|
-
const content = await readFile(sessionsPath(projectName, iteration), 'utf-8');
|
|
25
|
+
const content = await readFile(sessionsPath(projectName, iteration, contextDir), 'utf-8');
|
|
25
26
|
return JSON.parse(content);
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
28
29
|
return [];
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
|
-
async function writeSessions(projectName, iteration, sessions) {
|
|
32
|
-
const filePath = sessionsPath(projectName, iteration);
|
|
32
|
+
async function writeSessions(projectName, iteration, sessions, contextDir) {
|
|
33
|
+
const filePath = sessionsPath(projectName, iteration, contextDir);
|
|
33
34
|
await mkdir(dirname(filePath), { recursive: true });
|
|
34
35
|
await writeFile(filePath, JSON.stringify(sessions, null, 2) + '\n', 'utf-8');
|
|
35
36
|
}
|
|
@@ -37,8 +38,8 @@ function nextSessionId(sessions) {
|
|
|
37
38
|
const num = sessions.length + 1;
|
|
38
39
|
return `ses-${String(num).padStart(3, '0')}`;
|
|
39
40
|
}
|
|
40
|
-
export async function createSession(projectName, iteration, role, agentType, label) {
|
|
41
|
-
const sessions = await readSessions(projectName, iteration);
|
|
41
|
+
export async function createSession(projectName, iteration, role, agentType, label, contextDir) {
|
|
42
|
+
const sessions = await readSessions(projectName, iteration, contextDir);
|
|
42
43
|
const now = new Date().toISOString();
|
|
43
44
|
const session = {
|
|
44
45
|
id: nextSessionId(sessions),
|
|
@@ -50,11 +51,11 @@ export async function createSession(projectName, iteration, role, agentType, lab
|
|
|
50
51
|
lastActiveAt: now,
|
|
51
52
|
};
|
|
52
53
|
sessions.push(session);
|
|
53
|
-
await writeSessions(projectName, iteration, sessions);
|
|
54
|
+
await writeSessions(projectName, iteration, sessions, contextDir);
|
|
54
55
|
return session;
|
|
55
56
|
}
|
|
56
|
-
export async function updateSession(projectName, iteration, sessionId, updates) {
|
|
57
|
-
const sessions = await readSessions(projectName, iteration);
|
|
57
|
+
export async function updateSession(projectName, iteration, sessionId, updates, contextDir) {
|
|
58
|
+
const sessions = await readSessions(projectName, iteration, contextDir);
|
|
58
59
|
const session = sessions.find((s) => s.id === sessionId);
|
|
59
60
|
if (!session) {
|
|
60
61
|
throw new Error(`Session "${sessionId}" not found in project "${projectName}"`);
|
|
@@ -68,15 +69,15 @@ export async function updateSession(projectName, iteration, sessionId, updates)
|
|
|
68
69
|
if (updates.label !== undefined)
|
|
69
70
|
session.label = updates.label;
|
|
70
71
|
session.lastActiveAt = new Date().toISOString();
|
|
71
|
-
await writeSessions(projectName, iteration, sessions);
|
|
72
|
+
await writeSessions(projectName, iteration, sessions, contextDir);
|
|
72
73
|
return session;
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* Find an idle session for a given role (for session reuse).
|
|
76
77
|
* Returns the most recently active idle session, or null if none found.
|
|
77
78
|
*/
|
|
78
|
-
export async function findIdleSession(projectName, iteration, role) {
|
|
79
|
-
const sessions = await readSessions(projectName, iteration);
|
|
79
|
+
export async function findIdleSession(projectName, iteration, role, contextDir) {
|
|
80
|
+
const sessions = await readSessions(projectName, iteration, contextDir);
|
|
80
81
|
const idle = sessions
|
|
81
82
|
.filter((s) => s.role === role && s.status === 'idle')
|
|
82
83
|
.sort((a, b) => b.lastActiveAt.localeCompare(a.lastActiveAt));
|
|
@@ -85,22 +86,22 @@ export async function findIdleSession(projectName, iteration, role) {
|
|
|
85
86
|
/**
|
|
86
87
|
* Find a session by its agent session ID (for correlating external sessions).
|
|
87
88
|
*/
|
|
88
|
-
export async function findSessionByAgentId(projectName, iteration, role, agentSessionId) {
|
|
89
|
-
const sessions = await readSessions(projectName, iteration);
|
|
89
|
+
export async function findSessionByAgentId(projectName, iteration, role, agentSessionId, contextDir) {
|
|
90
|
+
const sessions = await readSessions(projectName, iteration, contextDir);
|
|
90
91
|
return sessions.find((s) => s.role === role && s.agentSessionId === agentSessionId) ?? null;
|
|
91
92
|
}
|
|
92
93
|
// ─── Dispatch CRUD ───
|
|
93
|
-
export async function readDispatches(projectName, iteration) {
|
|
94
|
+
export async function readDispatches(projectName, iteration, contextDir) {
|
|
94
95
|
try {
|
|
95
|
-
const content = await readFile(dispatchesPath(projectName, iteration), 'utf-8');
|
|
96
|
+
const content = await readFile(dispatchesPath(projectName, iteration, contextDir), 'utf-8');
|
|
96
97
|
return JSON.parse(content);
|
|
97
98
|
}
|
|
98
99
|
catch {
|
|
99
100
|
return [];
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
|
-
async function writeDispatches(projectName, iteration, dispatches) {
|
|
103
|
-
const filePath = dispatchesPath(projectName, iteration);
|
|
103
|
+
async function writeDispatches(projectName, iteration, dispatches, contextDir) {
|
|
104
|
+
const filePath = dispatchesPath(projectName, iteration, contextDir);
|
|
104
105
|
await mkdir(dirname(filePath), { recursive: true });
|
|
105
106
|
await writeFile(filePath, JSON.stringify(dispatches, null, 2) + '\n', 'utf-8');
|
|
106
107
|
}
|
|
@@ -108,8 +109,8 @@ function nextDispatchId(dispatches) {
|
|
|
108
109
|
const num = dispatches.length + 1;
|
|
109
110
|
return `dispatch-${String(num).padStart(3, '0')}`;
|
|
110
111
|
}
|
|
111
|
-
export async function createDispatch(projectName, iteration, role, taskBrief, expectedOutputs, sessionId) {
|
|
112
|
-
const dispatches = await readDispatches(projectName, iteration);
|
|
112
|
+
export async function createDispatch(projectName, iteration, role, taskBrief, expectedOutputs, sessionId, contextDir, nodeId) {
|
|
113
|
+
const dispatches = await readDispatches(projectName, iteration, contextDir);
|
|
113
114
|
const now = new Date().toISOString();
|
|
114
115
|
const dispatch = {
|
|
115
116
|
id: nextDispatchId(dispatches),
|
|
@@ -120,13 +121,14 @@ export async function createDispatch(projectName, iteration, role, taskBrief, ex
|
|
|
120
121
|
createdAt: now,
|
|
121
122
|
updatedAt: now,
|
|
122
123
|
...(sessionId ? { sessionId } : {}),
|
|
124
|
+
...(nodeId ? { nodeId } : {}),
|
|
123
125
|
};
|
|
124
126
|
dispatches.push(dispatch);
|
|
125
|
-
await writeDispatches(projectName, iteration, dispatches);
|
|
127
|
+
await writeDispatches(projectName, iteration, dispatches, contextDir);
|
|
126
128
|
return dispatch;
|
|
127
129
|
}
|
|
128
|
-
export async function updateDispatch(projectName, iteration, dispatchId, updates) {
|
|
129
|
-
const dispatches = await readDispatches(projectName, iteration);
|
|
130
|
+
export async function updateDispatch(projectName, iteration, dispatchId, updates, contextDir) {
|
|
131
|
+
const dispatches = await readDispatches(projectName, iteration, contextDir);
|
|
130
132
|
const dispatch = dispatches.find((d) => d.id === dispatchId);
|
|
131
133
|
if (!dispatch) {
|
|
132
134
|
throw new Error(`Dispatch "${dispatchId}" not found in project "${projectName}"`);
|
|
@@ -143,14 +145,14 @@ export async function updateDispatch(projectName, iteration, dispatchId, updates
|
|
|
143
145
|
if (updates.note !== undefined)
|
|
144
146
|
dispatch.note = updates.note;
|
|
145
147
|
dispatch.updatedAt = now;
|
|
146
|
-
await writeDispatches(projectName, iteration, dispatches);
|
|
148
|
+
await writeDispatches(projectName, iteration, dispatches, contextDir);
|
|
147
149
|
return dispatch;
|
|
148
150
|
}
|
|
149
151
|
/**
|
|
150
152
|
* Get a single dispatch record by ID.
|
|
151
153
|
*/
|
|
152
|
-
export async function getDispatch(projectName, iteration, dispatchId) {
|
|
153
|
-
const dispatches = await readDispatches(projectName, iteration);
|
|
154
|
+
export async function getDispatch(projectName, iteration, dispatchId, contextDir) {
|
|
155
|
+
const dispatches = await readDispatches(projectName, iteration, contextDir);
|
|
154
156
|
return dispatches.find((d) => d.id === dispatchId) ?? null;
|
|
155
157
|
}
|
|
156
158
|
// ─── Dispatch State Machine ───
|
|
@@ -174,4 +176,12 @@ export function isValidTransition(from, to) {
|
|
|
174
176
|
export function isTerminalStatus(status) {
|
|
175
177
|
return DISPATCH_TRANSITIONS[status].length === 0;
|
|
176
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Check if a role has any running dispatches (status: 'dispatched' or 'running').
|
|
181
|
+
* Used by parallel dispatch logic to decide whether to force a new session.
|
|
182
|
+
*/
|
|
183
|
+
export async function hasRunningDispatch(projectName, iteration, role, contextDir) {
|
|
184
|
+
const dispatches = await readDispatches(projectName, iteration, contextDir);
|
|
185
|
+
return dispatches.some((d) => d.role === role && (d.status === 'dispatched' || d.status === 'running'));
|
|
186
|
+
}
|
|
177
187
|
//# sourceMappingURL=dispatch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/core/dispatch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/core/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue tracking — manages <data_dir>/<project_name>/issues.json
|
|
3
|
+
*
|
|
4
|
+
* Issues are project-level (not per-iteration/patch). They track problems
|
|
5
|
+
* discovered during testing or from user feedback, and can be linked to
|
|
6
|
+
* the patch or iteration that resolves them.
|
|
7
|
+
*/
|
|
8
|
+
import type { Issue, IssueResolvedBy, IssueSource, IssueStatus } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Read all issues for a project. Returns empty array if file doesn't exist.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readIssues(projectName: string): Promise<Issue[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new issue. Auto-generates an incremental ID.
|
|
15
|
+
*
|
|
16
|
+
* @returns The created issue
|
|
17
|
+
*/
|
|
18
|
+
export declare function createIssue(projectName: string, title: string, description: string, source: IssueSource, iteration: number): Promise<Issue>;
|
|
19
|
+
/**
|
|
20
|
+
* Update an existing issue.
|
|
21
|
+
* Supports partial updates: status, resolvedBy, closedAt.
|
|
22
|
+
*
|
|
23
|
+
* @returns The updated issue
|
|
24
|
+
*/
|
|
25
|
+
export declare function updateIssue(projectName: string, issueId: string, updates: {
|
|
26
|
+
status?: IssueStatus;
|
|
27
|
+
resolvedBy?: IssueResolvedBy;
|
|
28
|
+
}): Promise<Issue>;
|
|
29
|
+
export interface IssueFilters {
|
|
30
|
+
status?: IssueStatus;
|
|
31
|
+
source?: IssueSource;
|
|
32
|
+
iteration?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* List issues with optional filters.
|
|
36
|
+
*/
|
|
37
|
+
export declare function listIssues(projectName: string, filters?: IssueFilters): Promise<Issue[]>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue tracking — manages <data_dir>/<project_name>/issues.json
|
|
3
|
+
*
|
|
4
|
+
* Issues are project-level (not per-iteration/patch). They track problems
|
|
5
|
+
* discovered during testing or from user feedback, and can be linked to
|
|
6
|
+
* the patch or iteration that resolves them.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { getProjectDataDir } from './registry.js';
|
|
11
|
+
const ISSUES_FILE = 'issues.json';
|
|
12
|
+
function issuesPath(projectName) {
|
|
13
|
+
return join(getProjectDataDir(projectName), ISSUES_FILE);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read all issues for a project. Returns empty array if file doesn't exist.
|
|
17
|
+
*/
|
|
18
|
+
export async function readIssues(projectName) {
|
|
19
|
+
try {
|
|
20
|
+
const content = await readFile(issuesPath(projectName), 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Write issues array to disk.
|
|
29
|
+
*/
|
|
30
|
+
async function writeIssues(projectName, issues) {
|
|
31
|
+
await writeFile(issuesPath(projectName), JSON.stringify(issues, null, 2) + '\n', 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a new issue. Auto-generates an incremental ID.
|
|
35
|
+
*
|
|
36
|
+
* @returns The created issue
|
|
37
|
+
*/
|
|
38
|
+
export async function createIssue(projectName, title, description, source, iteration) {
|
|
39
|
+
const issues = await readIssues(projectName);
|
|
40
|
+
// Generate next ID
|
|
41
|
+
const maxNum = issues.reduce((max, iss) => {
|
|
42
|
+
const match = iss.id.match(/^issue-(\d+)$/);
|
|
43
|
+
return match ? Math.max(max, parseInt(match[1], 10)) : max;
|
|
44
|
+
}, 0);
|
|
45
|
+
const issue = {
|
|
46
|
+
id: `issue-${maxNum + 1}`,
|
|
47
|
+
title,
|
|
48
|
+
description,
|
|
49
|
+
source,
|
|
50
|
+
iteration,
|
|
51
|
+
status: 'open',
|
|
52
|
+
createdAt: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
issues.push(issue);
|
|
55
|
+
await writeIssues(projectName, issues);
|
|
56
|
+
return issue;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Update an existing issue.
|
|
60
|
+
* Supports partial updates: status, resolvedBy, closedAt.
|
|
61
|
+
*
|
|
62
|
+
* @returns The updated issue
|
|
63
|
+
*/
|
|
64
|
+
export async function updateIssue(projectName, issueId, updates) {
|
|
65
|
+
const issues = await readIssues(projectName);
|
|
66
|
+
const issue = issues.find((i) => i.id === issueId);
|
|
67
|
+
if (!issue) {
|
|
68
|
+
throw new Error(`Issue "${issueId}" not found.`);
|
|
69
|
+
}
|
|
70
|
+
if (updates.status !== undefined) {
|
|
71
|
+
issue.status = updates.status;
|
|
72
|
+
if (updates.status === 'closed') {
|
|
73
|
+
issue.closedAt = new Date().toISOString();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (updates.resolvedBy !== undefined) {
|
|
77
|
+
issue.resolvedBy = updates.resolvedBy;
|
|
78
|
+
}
|
|
79
|
+
await writeIssues(projectName, issues);
|
|
80
|
+
return issue;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* List issues with optional filters.
|
|
84
|
+
*/
|
|
85
|
+
export async function listIssues(projectName, filters) {
|
|
86
|
+
let issues = await readIssues(projectName);
|
|
87
|
+
if (filters) {
|
|
88
|
+
if (filters.status) {
|
|
89
|
+
issues = issues.filter((i) => i.status === filters.status);
|
|
90
|
+
}
|
|
91
|
+
if (filters.source) {
|
|
92
|
+
issues = issues.filter((i) => i.source === filters.source);
|
|
93
|
+
}
|
|
94
|
+
if (filters.iteration !== undefined) {
|
|
95
|
+
issues = issues.filter((i) => i.iteration === filters.iteration);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return issues;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/core/issues.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,62 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Override configuration —
|
|
2
|
+
* Override configuration — two-layer system: project overrides > workflow defaults.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Project-level overrides are stored in:
|
|
5
|
+
* <data_dir>/<project_name>/overrides.json
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Workflow defaults come from the workflow definition (artifactDefinitions, roles).
|
|
8
|
+
* The override system lets users customize per-project settings without modifying
|
|
9
|
+
* the workflow definition itself.
|
|
9
10
|
*/
|
|
10
|
-
import type { CapabilityOverride,
|
|
11
|
-
/**
|
|
12
|
-
* Read global overrides (<data_dir>/overrides.json).
|
|
13
|
-
*/
|
|
14
|
-
export declare function readGlobalOverrides(): Promise<OverrideConfig>;
|
|
11
|
+
import type { CapabilityOverride, ArtifactDefinition, OverrideConfig } from './types.js';
|
|
15
12
|
/**
|
|
16
13
|
* Read project-level overrides (<data_dir>/<project_name>/overrides.json).
|
|
17
14
|
*/
|
|
18
15
|
export declare function readProjectOverrides(projectName: string): Promise<OverrideConfig>;
|
|
19
|
-
/**
|
|
20
|
-
* Write global overrides.
|
|
21
|
-
*/
|
|
22
|
-
export declare function writeGlobalOverrides(config: OverrideConfig): Promise<void>;
|
|
23
16
|
/**
|
|
24
17
|
* Write project-level overrides.
|
|
25
18
|
*/
|
|
26
19
|
export declare function writeProjectOverrides(projectName: string, config: OverrideConfig): Promise<void>;
|
|
27
20
|
/**
|
|
28
|
-
* Get the
|
|
29
|
-
*
|
|
21
|
+
* Get the override config for a project.
|
|
22
|
+
* Returns the project-level overrides directly — no global merge.
|
|
30
23
|
*/
|
|
31
24
|
export declare function getMergedOverrides(projectName: string): Promise<OverrideConfig>;
|
|
32
25
|
/**
|
|
33
|
-
* Resolve whether a specific
|
|
26
|
+
* Resolve whether a specific artifact requires review.
|
|
34
27
|
*
|
|
35
|
-
* Priority: project override >
|
|
28
|
+
* Priority: project override > workflow default
|
|
36
29
|
*/
|
|
37
|
-
export declare function
|
|
30
|
+
export declare function resolveArtifactReview(artifactId: string, artifactDef: ArtifactDefinition, overrides: OverrideConfig): boolean;
|
|
38
31
|
/**
|
|
39
32
|
* Resolve the capability override for a specific role + capability.
|
|
40
33
|
* Returns null if no override is configured.
|
|
41
34
|
*/
|
|
42
35
|
export declare function resolveCapabilityOverride(roleId: string, capabilityId: string, overrides: OverrideConfig): CapabilityOverride | null;
|
|
43
36
|
/**
|
|
44
|
-
* Set a single role capability override at project
|
|
37
|
+
* Set a single role capability override at project level.
|
|
45
38
|
*/
|
|
46
|
-
export declare function setCapabilityOverride(
|
|
39
|
+
export declare function setCapabilityOverride(projectName: string, roleId: string, capabilityId: string, override: CapabilityOverride): Promise<void>;
|
|
47
40
|
/**
|
|
48
|
-
* Set review override for a specific
|
|
41
|
+
* Set review override for a specific artifact at project level.
|
|
49
42
|
*/
|
|
50
|
-
export declare function setReviewOverride(
|
|
43
|
+
export declare function setReviewOverride(projectName: string, artifactId: string, enabled: boolean): Promise<void>;
|
|
51
44
|
/**
|
|
52
45
|
* Resolve the agent/model configuration for a role.
|
|
53
|
-
* Returns { agent, model } from the
|
|
46
|
+
* Returns { agent, model } from the overrides, or undefined fields if not set.
|
|
54
47
|
*/
|
|
55
48
|
export declare function resolveRoleConfig(roleId: string, overrides: OverrideConfig): {
|
|
56
49
|
agent?: string;
|
|
57
50
|
model?: string;
|
|
58
51
|
};
|
|
59
52
|
/**
|
|
60
|
-
* Set agent/model config for a role at project
|
|
53
|
+
* Set agent/model config for a role at project level.
|
|
61
54
|
*/
|
|
62
|
-
export declare function setRoleAgentConfig(
|
|
55
|
+
export declare function setRoleAgentConfig(projectName: string, roleId: string, agent?: string, model?: string): Promise<void>;
|
package/build/core/overrides.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Override configuration —
|
|
2
|
+
* Override configuration — two-layer system: project overrides > workflow defaults.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Project-level overrides are stored in:
|
|
5
|
+
* <data_dir>/<project_name>/overrides.json
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Workflow defaults come from the workflow definition (artifactDefinitions, roles).
|
|
8
|
+
* The override system lets users customize per-project settings without modifying
|
|
9
|
+
* the workflow definition itself.
|
|
9
10
|
*/
|
|
10
11
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
11
12
|
import { join, dirname } from 'node:path';
|
|
12
|
-
import {
|
|
13
|
+
import { getProjectDataDir } from './registry.js';
|
|
13
14
|
const OVERRIDES_FILE = 'overrides.json';
|
|
14
15
|
/**
|
|
15
16
|
* Read an override config file. Returns empty config if file doesn't exist.
|
|
@@ -23,12 +24,6 @@ async function readOverrideFile(filePath) {
|
|
|
23
24
|
return {};
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Read global overrides (<data_dir>/overrides.json).
|
|
28
|
-
*/
|
|
29
|
-
export async function readGlobalOverrides() {
|
|
30
|
-
return readOverrideFile(join(getGlobalDir(), OVERRIDES_FILE));
|
|
31
|
-
}
|
|
32
27
|
/**
|
|
33
28
|
* Read project-level overrides (<data_dir>/<project_name>/overrides.json).
|
|
34
29
|
*/
|
|
@@ -42,12 +37,6 @@ async function writeOverrideFile(filePath, config) {
|
|
|
42
37
|
await mkdir(dirname(filePath), { recursive: true });
|
|
43
38
|
await writeFile(filePath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
44
39
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Write global overrides.
|
|
47
|
-
*/
|
|
48
|
-
export async function writeGlobalOverrides(config) {
|
|
49
|
-
await writeOverrideFile(join(getGlobalDir(), OVERRIDES_FILE), config);
|
|
50
|
-
}
|
|
51
40
|
/**
|
|
52
41
|
* Write project-level overrides.
|
|
53
42
|
*/
|
|
@@ -55,63 +44,23 @@ export async function writeProjectOverrides(projectName, config) {
|
|
|
55
44
|
await writeOverrideFile(join(getProjectDataDir(projectName), OVERRIDES_FILE), config);
|
|
56
45
|
}
|
|
57
46
|
/**
|
|
58
|
-
*
|
|
59
|
-
|
|
60
|
-
function mergeConfigs(lower, higher) {
|
|
61
|
-
const merged = {};
|
|
62
|
-
// Merge review: higher wins entirely if present
|
|
63
|
-
if (higher.review !== undefined) {
|
|
64
|
-
merged.review = higher.review;
|
|
65
|
-
}
|
|
66
|
-
else if (lower.review !== undefined) {
|
|
67
|
-
merged.review = lower.review;
|
|
68
|
-
}
|
|
69
|
-
// Merge roles: deep merge per role (agent, model, capabilities)
|
|
70
|
-
const lowerRoles = lower.roles ?? {};
|
|
71
|
-
const higherRoles = higher.roles ?? {};
|
|
72
|
-
const allRoleIds = new Set([...Object.keys(lowerRoles), ...Object.keys(higherRoles)]);
|
|
73
|
-
if (allRoleIds.size > 0) {
|
|
74
|
-
merged.roles = {};
|
|
75
|
-
for (const roleId of allRoleIds) {
|
|
76
|
-
const lo = lowerRoles[roleId] ?? {};
|
|
77
|
-
const hi = higherRoles[roleId] ?? {};
|
|
78
|
-
merged.roles[roleId] = {
|
|
79
|
-
...lo,
|
|
80
|
-
...hi,
|
|
81
|
-
// Deep merge capabilities
|
|
82
|
-
capabilities: {
|
|
83
|
-
...(lo.capabilities ?? {}),
|
|
84
|
-
...(hi.capabilities ?? {}),
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
// Clean up empty capabilities
|
|
88
|
-
if (Object.keys(merged.roles[roleId].capabilities).length === 0) {
|
|
89
|
-
delete merged.roles[roleId].capabilities;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return merged;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Get the fully merged override config for a project.
|
|
97
|
-
* Priority: project > global
|
|
47
|
+
* Get the override config for a project.
|
|
48
|
+
* Returns the project-level overrides directly — no global merge.
|
|
98
49
|
*/
|
|
99
50
|
export async function getMergedOverrides(projectName) {
|
|
100
|
-
|
|
101
|
-
const project = await readProjectOverrides(projectName);
|
|
102
|
-
return mergeConfigs(global, project);
|
|
51
|
+
return readProjectOverrides(projectName);
|
|
103
52
|
}
|
|
104
53
|
/**
|
|
105
|
-
* Resolve whether a specific
|
|
54
|
+
* Resolve whether a specific artifact requires review.
|
|
106
55
|
*
|
|
107
|
-
* Priority: project override >
|
|
56
|
+
* Priority: project override > workflow default
|
|
108
57
|
*/
|
|
109
|
-
export function
|
|
58
|
+
export function resolveArtifactReview(artifactId, artifactDef, overrides) {
|
|
110
59
|
const review = overrides.review;
|
|
111
|
-
// Override is a per-
|
|
60
|
+
// Override is a per-artifact record
|
|
112
61
|
if (typeof review === 'object' && review !== null) {
|
|
113
|
-
if (
|
|
114
|
-
return review[
|
|
62
|
+
if (artifactId in review) {
|
|
63
|
+
return review[artifactId];
|
|
115
64
|
}
|
|
116
65
|
// Not mentioned in override, fall through to workflow default
|
|
117
66
|
}
|
|
@@ -120,7 +69,7 @@ export function resolveDocReview(docId, docDef, overrides) {
|
|
|
120
69
|
return review;
|
|
121
70
|
}
|
|
122
71
|
// No override — use workflow default
|
|
123
|
-
return
|
|
72
|
+
return artifactDef.review ?? false;
|
|
124
73
|
}
|
|
125
74
|
/**
|
|
126
75
|
* Resolve the capability override for a specific role + capability.
|
|
@@ -130,10 +79,10 @@ export function resolveCapabilityOverride(roleId, capabilityId, overrides) {
|
|
|
130
79
|
return overrides.roles?.[roleId]?.capabilities?.[capabilityId] ?? null;
|
|
131
80
|
}
|
|
132
81
|
/**
|
|
133
|
-
* Set a single role capability override at project
|
|
82
|
+
* Set a single role capability override at project level.
|
|
134
83
|
*/
|
|
135
|
-
export async function setCapabilityOverride(
|
|
136
|
-
const config =
|
|
84
|
+
export async function setCapabilityOverride(projectName, roleId, capabilityId, override) {
|
|
85
|
+
const config = await readProjectOverrides(projectName);
|
|
137
86
|
if (!config.roles) {
|
|
138
87
|
config.roles = {};
|
|
139
88
|
}
|
|
@@ -144,33 +93,23 @@ export async function setCapabilityOverride(scope, projectName, roleId, capabili
|
|
|
144
93
|
config.roles[roleId].capabilities = {};
|
|
145
94
|
}
|
|
146
95
|
config.roles[roleId].capabilities[capabilityId] = override;
|
|
147
|
-
|
|
148
|
-
await writeGlobalOverrides(config);
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
await writeProjectOverrides(projectName, config);
|
|
152
|
-
}
|
|
96
|
+
await writeProjectOverrides(projectName, config);
|
|
153
97
|
}
|
|
154
98
|
/**
|
|
155
|
-
* Set review override for a specific
|
|
99
|
+
* Set review override for a specific artifact at project level.
|
|
156
100
|
*/
|
|
157
|
-
export async function setReviewOverride(
|
|
158
|
-
const config =
|
|
159
|
-
// Ensure review is a per-
|
|
101
|
+
export async function setReviewOverride(projectName, artifactId, enabled) {
|
|
102
|
+
const config = await readProjectOverrides(projectName);
|
|
103
|
+
// Ensure review is a per-artifact record
|
|
160
104
|
if (typeof config.review !== 'object' || config.review === null) {
|
|
161
105
|
config.review = {};
|
|
162
106
|
}
|
|
163
|
-
config.review[
|
|
164
|
-
|
|
165
|
-
await writeGlobalOverrides(config);
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
await writeProjectOverrides(projectName, config);
|
|
169
|
-
}
|
|
107
|
+
config.review[artifactId] = enabled;
|
|
108
|
+
await writeProjectOverrides(projectName, config);
|
|
170
109
|
}
|
|
171
110
|
/**
|
|
172
111
|
* Resolve the agent/model configuration for a role.
|
|
173
|
-
* Returns { agent, model } from the
|
|
112
|
+
* Returns { agent, model } from the overrides, or undefined fields if not set.
|
|
174
113
|
*/
|
|
175
114
|
export function resolveRoleConfig(roleId, overrides) {
|
|
176
115
|
const role = overrides.roles?.[roleId];
|
|
@@ -182,10 +121,10 @@ export function resolveRoleConfig(roleId, overrides) {
|
|
|
182
121
|
};
|
|
183
122
|
}
|
|
184
123
|
/**
|
|
185
|
-
* Set agent/model config for a role at project
|
|
124
|
+
* Set agent/model config for a role at project level.
|
|
186
125
|
*/
|
|
187
|
-
export async function setRoleAgentConfig(
|
|
188
|
-
const config =
|
|
126
|
+
export async function setRoleAgentConfig(projectName, roleId, agent, model) {
|
|
127
|
+
const config = await readProjectOverrides(projectName);
|
|
189
128
|
if (!config.roles) {
|
|
190
129
|
config.roles = {};
|
|
191
130
|
}
|
|
@@ -196,11 +135,6 @@ export async function setRoleAgentConfig(scope, projectName, roleId, agent, mode
|
|
|
196
135
|
config.roles[roleId].agent = agent;
|
|
197
136
|
if (model)
|
|
198
137
|
config.roles[roleId].model = model;
|
|
199
|
-
|
|
200
|
-
await writeGlobalOverrides(config);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
await writeProjectOverrides(projectName, config);
|
|
204
|
-
}
|
|
138
|
+
await writeProjectOverrides(projectName, config);
|
|
205
139
|
}
|
|
206
140
|
//# sourceMappingURL=overrides.js.map
|