@s_s/harmonia 1.1.1 → 1.3.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 +413 -205
- package/build/core/dispatch.d.ts +16 -13
- package/build/core/dispatch.js +38 -33
- package/build/core/dispatch.js.map +1 -1
- package/build/core/docs.d.ts +15 -11
- package/build/core/docs.js +24 -19
- package/build/core/docs.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/registry.d.ts +63 -6
- package/build/core/registry.js +109 -8
- package/build/core/registry.js.map +1 -1
- package/build/core/reviews.d.ts +9 -8
- package/build/core/reviews.js +22 -20
- package/build/core/reviews.js.map +1 -1
- package/build/core/state.d.ts +18 -10
- package/build/core/state.js +50 -27
- package/build/core/state.js.map +1 -1
- package/build/core/steps.d.ts +8 -7
- package/build/core/steps.js +21 -19
- package/build/core/steps.js.map +1 -1
- package/build/core/types.d.ts +32 -1
- package/build/index.js +34 -3
- package/build/index.js.map +1 -1
- package/build/setup/templates.js +79 -3
- package/build/setup/templates.js.map +1 -1
- package/build/tools/approve-doc.js +9 -2
- package/build/tools/approve-doc.js.map +1 -1
- package/build/tools/dispatch-role.js +8 -4
- package/build/tools/dispatch-role.js.map +1 -1
- package/build/tools/doc-tools.js +100 -21
- package/build/tools/doc-tools.js.map +1 -1
- package/build/tools/get-project-status.js +108 -17
- package/build/tools/get-project-status.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 +13 -0
- package/build/tools/iteration-start.js +103 -0
- package/build/tools/iteration-start.js.map +1 -0
- package/build/tools/patch-start.d.ts +14 -0
- package/build/tools/patch-start.js +97 -0
- package/build/tools/patch-start.js.map +1 -0
- package/build/tools/project-init.d.ts +5 -1
- package/build/tools/project-init.js +28 -14
- package/build/tools/project-init.js.map +1 -1
- package/build/tools/report-dispatch.js +23 -19
- package/build/tools/report-dispatch.js.map +1 -1
- package/build/tools/set-scale.js +7 -4
- package/build/tools/set-scale.js.map +1 -1
- package/build/tools/update-phase.js +11 -7
- package/build/tools/update-phase.js.map +1 -1
- package/build/tools/utils.d.ts +34 -0
- package/build/tools/utils.js +61 -0
- package/build/tools/utils.js.map +1 -0
- package/package.json +1 -1
package/build/core/registry.d.ts
CHANGED
|
@@ -12,11 +12,19 @@
|
|
|
12
12
|
* ├── registry.json # { projects: { "my-app": { dir: "/path/to/src", ... } } }
|
|
13
13
|
* ├── overrides.json # global overrides (optional)
|
|
14
14
|
* ├── my-app/
|
|
15
|
-
* │ ├── state.json
|
|
16
|
-
* │ ├── docs/
|
|
17
|
-
* │ ├── reviews.json
|
|
18
15
|
* │ ├── overrides.json # project-level overrides (optional)
|
|
19
|
-
* │
|
|
16
|
+
* │ ├── issues.json # project-level issue tracking (optional)
|
|
17
|
+
* │ ├── iter-1/
|
|
18
|
+
* │ │ ├── state.json
|
|
19
|
+
* │ │ ├── docs/
|
|
20
|
+
* │ │ ├── reviews.json
|
|
21
|
+
* │ │ └── ...
|
|
22
|
+
* │ ├── iter-2/
|
|
23
|
+
* │ │ └── ...
|
|
24
|
+
* │ ├── patch-1/
|
|
25
|
+
* │ │ ├── state.json # type: "patch", clarify/design skipped
|
|
26
|
+
* │ │ ├── docs/
|
|
27
|
+
* │ │ └── ...
|
|
20
28
|
* └── another-project/
|
|
21
29
|
* └── ...
|
|
22
30
|
*/
|
|
@@ -27,6 +35,16 @@ export interface ProjectEntry {
|
|
|
27
35
|
workflow: string;
|
|
28
36
|
/** When the project was registered */
|
|
29
37
|
createdAt: string;
|
|
38
|
+
/** Currently active iteration number (starts at 1, 0 means no iteration started yet) */
|
|
39
|
+
currentIteration: number;
|
|
40
|
+
/** Total number of iterations created so far */
|
|
41
|
+
totalIterations: number;
|
|
42
|
+
/** Currently active patch number (starts at 1, 0 means no patch started yet) */
|
|
43
|
+
currentPatch: number;
|
|
44
|
+
/** Total number of patches created so far */
|
|
45
|
+
totalPatches: number;
|
|
46
|
+
/** Active context identifier, e.g. "iter-1" or "patch-2". Empty string means no context. */
|
|
47
|
+
activeContext: string;
|
|
30
48
|
}
|
|
31
49
|
export interface Registry {
|
|
32
50
|
projects: Record<string, ProjectEntry>;
|
|
@@ -56,6 +74,8 @@ export declare function readRegistry(): Promise<Registry>;
|
|
|
56
74
|
export declare function writeRegistry(registry: Registry): Promise<void>;
|
|
57
75
|
/**
|
|
58
76
|
* Register a new project. Creates the project data directory.
|
|
77
|
+
* Note: Does NOT create iteration directories or state files.
|
|
78
|
+
* Use startIteration() after registration to begin the first iteration.
|
|
59
79
|
*/
|
|
60
80
|
export declare function registerProject(projectName: string, projectDir: string, workflow: string): Promise<void>;
|
|
61
81
|
/**
|
|
@@ -67,6 +87,43 @@ export declare function getProject(projectName: string): Promise<ProjectEntry |
|
|
|
67
87
|
*/
|
|
68
88
|
export declare function listProjects(): Promise<string[]>;
|
|
69
89
|
/**
|
|
70
|
-
* Remove a project from the registry
|
|
90
|
+
* Remove a project from the registry.
|
|
91
|
+
* By default, also deletes the project data directory.
|
|
92
|
+
* Pass keepData: true to only remove the registry entry.
|
|
71
93
|
*/
|
|
72
|
-
export declare function unregisterProject(projectName: string): Promise<void>;
|
|
94
|
+
export declare function unregisterProject(projectName: string, keepData?: boolean): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Get the iteration directory for a specific project iteration.
|
|
97
|
+
* Pure path concatenation — does NOT check if the directory exists.
|
|
98
|
+
*/
|
|
99
|
+
export declare function getIterationDir(projectName: string, iteration: number): string;
|
|
100
|
+
/**
|
|
101
|
+
* Start a new iteration for a project.
|
|
102
|
+
* Creates the iteration directory (with docs/ subdirectory) and updates the registry.
|
|
103
|
+
*
|
|
104
|
+
* @returns The new iteration number
|
|
105
|
+
*/
|
|
106
|
+
export declare function startIteration(projectName: string): Promise<number>;
|
|
107
|
+
/**
|
|
108
|
+
* Get the patch directory for a specific project patch.
|
|
109
|
+
* Pure path concatenation — does NOT check if the directory exists.
|
|
110
|
+
*/
|
|
111
|
+
export declare function getPatchDir(projectName: string, patch: number): string;
|
|
112
|
+
/**
|
|
113
|
+
* Start a new patch for a project.
|
|
114
|
+
* Creates the patch directory (with docs/ subdirectory) and updates the registry.
|
|
115
|
+
*
|
|
116
|
+
* @returns The new patch number
|
|
117
|
+
*/
|
|
118
|
+
export declare function startPatch(projectName: string): Promise<number>;
|
|
119
|
+
/**
|
|
120
|
+
* Resolve the active context directory for a project.
|
|
121
|
+
* Parses activeContext string (e.g. "iter-1", "patch-2") into an absolute path.
|
|
122
|
+
*
|
|
123
|
+
* @returns { dir: string, type: 'iteration' | 'patch', number: number } or null if no active context
|
|
124
|
+
*/
|
|
125
|
+
export declare function resolveContextDir(projectName: string, activeContext: string): {
|
|
126
|
+
dir: string;
|
|
127
|
+
type: 'iteration' | 'patch';
|
|
128
|
+
number: number;
|
|
129
|
+
} | null;
|
package/build/core/registry.js
CHANGED
|
@@ -12,11 +12,19 @@
|
|
|
12
12
|
* ├── registry.json # { projects: { "my-app": { dir: "/path/to/src", ... } } }
|
|
13
13
|
* ├── overrides.json # global overrides (optional)
|
|
14
14
|
* ├── my-app/
|
|
15
|
-
* │ ├── state.json
|
|
16
|
-
* │ ├── docs/
|
|
17
|
-
* │ ├── reviews.json
|
|
18
15
|
* │ ├── overrides.json # project-level overrides (optional)
|
|
19
|
-
* │
|
|
16
|
+
* │ ├── issues.json # project-level issue tracking (optional)
|
|
17
|
+
* │ ├── iter-1/
|
|
18
|
+
* │ │ ├── state.json
|
|
19
|
+
* │ │ ├── docs/
|
|
20
|
+
* │ │ ├── reviews.json
|
|
21
|
+
* │ │ └── ...
|
|
22
|
+
* │ ├── iter-2/
|
|
23
|
+
* │ │ └── ...
|
|
24
|
+
* │ ├── patch-1/
|
|
25
|
+
* │ │ ├── state.json # type: "patch", clarify/design skipped
|
|
26
|
+
* │ │ ├── docs/
|
|
27
|
+
* │ │ └── ...
|
|
20
28
|
* └── another-project/
|
|
21
29
|
* └── ...
|
|
22
30
|
*/
|
|
@@ -67,6 +75,8 @@ export async function writeRegistry(registry) {
|
|
|
67
75
|
}
|
|
68
76
|
/**
|
|
69
77
|
* Register a new project. Creates the project data directory.
|
|
78
|
+
* Note: Does NOT create iteration directories or state files.
|
|
79
|
+
* Use startIteration() after registration to begin the first iteration.
|
|
70
80
|
*/
|
|
71
81
|
export async function registerProject(projectName, projectDir, workflow) {
|
|
72
82
|
const registry = await readRegistry();
|
|
@@ -77,10 +87,15 @@ export async function registerProject(projectName, projectDir, workflow) {
|
|
|
77
87
|
dir: projectDir,
|
|
78
88
|
workflow,
|
|
79
89
|
createdAt: new Date().toISOString(),
|
|
90
|
+
currentIteration: 0,
|
|
91
|
+
totalIterations: 0,
|
|
92
|
+
currentPatch: 0,
|
|
93
|
+
totalPatches: 0,
|
|
94
|
+
activeContext: '',
|
|
80
95
|
};
|
|
81
|
-
// Create project data directory
|
|
96
|
+
// Create project data directory under global dir
|
|
82
97
|
const dataDir = getProjectDataDir(projectName);
|
|
83
|
-
await mkdir(
|
|
98
|
+
await mkdir(dataDir, { recursive: true });
|
|
84
99
|
// Create the project source directory if it doesn't exist
|
|
85
100
|
await mkdir(projectDir, { recursive: true });
|
|
86
101
|
await writeRegistry(registry);
|
|
@@ -100,11 +115,97 @@ export async function listProjects() {
|
|
|
100
115
|
return Object.keys(registry.projects);
|
|
101
116
|
}
|
|
102
117
|
/**
|
|
103
|
-
* Remove a project from the registry
|
|
118
|
+
* Remove a project from the registry.
|
|
119
|
+
* By default, also deletes the project data directory.
|
|
120
|
+
* Pass keepData: true to only remove the registry entry.
|
|
104
121
|
*/
|
|
105
|
-
export async function unregisterProject(projectName) {
|
|
122
|
+
export async function unregisterProject(projectName, keepData = false) {
|
|
106
123
|
const registry = await readRegistry();
|
|
107
124
|
delete registry.projects[projectName];
|
|
108
125
|
await writeRegistry(registry);
|
|
126
|
+
if (!keepData) {
|
|
127
|
+
const { rm } = await import('node:fs/promises');
|
|
128
|
+
const dataDir = getProjectDataDir(projectName);
|
|
129
|
+
await rm(dataDir, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the iteration directory for a specific project iteration.
|
|
134
|
+
* Pure path concatenation — does NOT check if the directory exists.
|
|
135
|
+
*/
|
|
136
|
+
export function getIterationDir(projectName, iteration) {
|
|
137
|
+
return join(getProjectDataDir(projectName), `iter-${iteration}`);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Start a new iteration for a project.
|
|
141
|
+
* Creates the iteration directory (with docs/ subdirectory) and updates the registry.
|
|
142
|
+
*
|
|
143
|
+
* @returns The new iteration number
|
|
144
|
+
*/
|
|
145
|
+
export async function startIteration(projectName) {
|
|
146
|
+
const registry = await readRegistry();
|
|
147
|
+
const entry = registry.projects[projectName];
|
|
148
|
+
if (!entry) {
|
|
149
|
+
throw new Error(`Project "${projectName}" not found in registry.`);
|
|
150
|
+
}
|
|
151
|
+
const newIteration = entry.totalIterations + 1;
|
|
152
|
+
entry.currentIteration = newIteration;
|
|
153
|
+
entry.totalIterations = newIteration;
|
|
154
|
+
entry.activeContext = `iter-${newIteration}`;
|
|
155
|
+
// Create iteration directory with docs subdirectory
|
|
156
|
+
const iterDir = getIterationDir(projectName, newIteration);
|
|
157
|
+
await mkdir(join(iterDir, 'docs'), { recursive: true });
|
|
158
|
+
await writeRegistry(registry);
|
|
159
|
+
return newIteration;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the patch directory for a specific project patch.
|
|
163
|
+
* Pure path concatenation — does NOT check if the directory exists.
|
|
164
|
+
*/
|
|
165
|
+
export function getPatchDir(projectName, patch) {
|
|
166
|
+
return join(getProjectDataDir(projectName), `patch-${patch}`);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Start a new patch for a project.
|
|
170
|
+
* Creates the patch directory (with docs/ subdirectory) and updates the registry.
|
|
171
|
+
*
|
|
172
|
+
* @returns The new patch number
|
|
173
|
+
*/
|
|
174
|
+
export async function startPatch(projectName) {
|
|
175
|
+
const registry = await readRegistry();
|
|
176
|
+
const entry = registry.projects[projectName];
|
|
177
|
+
if (!entry) {
|
|
178
|
+
throw new Error(`Project "${projectName}" not found in registry.`);
|
|
179
|
+
}
|
|
180
|
+
const newPatch = entry.totalPatches + 1;
|
|
181
|
+
entry.currentPatch = newPatch;
|
|
182
|
+
entry.totalPatches = newPatch;
|
|
183
|
+
entry.activeContext = `patch-${newPatch}`;
|
|
184
|
+
// Create patch directory with docs subdirectory
|
|
185
|
+
const patchDir = getPatchDir(projectName, newPatch);
|
|
186
|
+
await mkdir(join(patchDir, 'docs'), { recursive: true });
|
|
187
|
+
await writeRegistry(registry);
|
|
188
|
+
return newPatch;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve the active context directory for a project.
|
|
192
|
+
* Parses activeContext string (e.g. "iter-1", "patch-2") into an absolute path.
|
|
193
|
+
*
|
|
194
|
+
* @returns { dir: string, type: 'iteration' | 'patch', number: number } or null if no active context
|
|
195
|
+
*/
|
|
196
|
+
export function resolveContextDir(projectName, activeContext) {
|
|
197
|
+
if (!activeContext)
|
|
198
|
+
return null;
|
|
199
|
+
const iterMatch = activeContext.match(/^iter-(\d+)$/);
|
|
200
|
+
if (iterMatch) {
|
|
201
|
+
const num = parseInt(iterMatch[1], 10);
|
|
202
|
+
return { dir: getIterationDir(projectName, num), type: 'iteration', number: num };
|
|
203
|
+
}
|
|
204
|
+
const patchMatch = activeContext.match(/^patch-(\d+)$/);
|
|
205
|
+
if (patchMatch) {
|
|
206
|
+
const num = parseInt(patchMatch[1], 10);
|
|
207
|
+
return { dir: getPatchDir(projectName, num), type: 'patch', number: num };
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
109
210
|
}
|
|
110
211
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"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"}
|
package/build/core/reviews.d.ts
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Document review state management — <
|
|
2
|
+
* Document review state management — <context_dir>/reviews.json
|
|
3
3
|
*
|
|
4
4
|
* Tracks which documents are pending review, approved, or rejected.
|
|
5
|
+
* All public functions accept an optional contextDir parameter.
|
|
5
6
|
*/
|
|
6
7
|
import type { DocReviewState } from './types.js';
|
|
7
8
|
/**
|
|
8
|
-
* Read the reviews state for a project.
|
|
9
|
+
* Read the reviews state for a project context.
|
|
9
10
|
*/
|
|
10
|
-
export declare function readReviews(projectName: string): Promise<Record<string, DocReviewState>>;
|
|
11
|
+
export declare function readReviews(projectName: string, iteration: number, contextDir?: string): Promise<Record<string, DocReviewState>>;
|
|
11
12
|
/**
|
|
12
13
|
* Submit a document for review. Sets status to "pending".
|
|
13
14
|
*/
|
|
14
|
-
export declare function submitForReview(projectName: string, docId: string): Promise<DocReviewState>;
|
|
15
|
+
export declare function submitForReview(projectName: string, iteration: number, docId: string, contextDir?: string): Promise<DocReviewState>;
|
|
15
16
|
/**
|
|
16
17
|
* Approve or reject a document review.
|
|
17
18
|
*/
|
|
18
|
-
export declare function resolveReview(projectName: string, docId: string, status: 'approved' | 'rejected', comment?: string): Promise<DocReviewState>;
|
|
19
|
+
export declare function resolveReview(projectName: string, iteration: number, docId: string, status: 'approved' | 'rejected', comment?: string, contextDir?: string): Promise<DocReviewState>;
|
|
19
20
|
/**
|
|
20
21
|
* Get the review state for a specific document.
|
|
21
22
|
*/
|
|
22
|
-
export declare function getDocReview(projectName: string, docId: string): Promise<DocReviewState | null>;
|
|
23
|
+
export declare function getDocReview(projectName: string, iteration: number, docId: string, contextDir?: string): Promise<DocReviewState | null>;
|
|
23
24
|
/**
|
|
24
|
-
* Get all pending reviews for a project.
|
|
25
|
+
* Get all pending reviews for a project context.
|
|
25
26
|
*/
|
|
26
|
-
export declare function getPendingReviews(projectName: string): Promise<DocReviewState[]>;
|
|
27
|
+
export declare function getPendingReviews(projectName: string, iteration: number, contextDir?: string): Promise<DocReviewState[]>;
|
package/build/core/reviews.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Document review state management — <
|
|
2
|
+
* Document review state management — <context_dir>/reviews.json
|
|
3
3
|
*
|
|
4
4
|
* Tracks which documents are pending review, approved, or rejected.
|
|
5
|
+
* All public functions accept an optional contextDir parameter.
|
|
5
6
|
*/
|
|
6
7
|
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
7
8
|
import { join, dirname } from 'node:path';
|
|
8
|
-
import {
|
|
9
|
+
import { getIterationDir } from './registry.js';
|
|
9
10
|
const REVIEWS_FILE = 'reviews.json';
|
|
10
|
-
function reviewsPath(projectName) {
|
|
11
|
-
|
|
11
|
+
function reviewsPath(projectName, iteration, contextDir) {
|
|
12
|
+
const base = contextDir ?? getIterationDir(projectName, iteration);
|
|
13
|
+
return join(base, REVIEWS_FILE);
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
|
-
* Read the reviews state for a project.
|
|
16
|
+
* Read the reviews state for a project context.
|
|
15
17
|
*/
|
|
16
|
-
export async function readReviews(projectName) {
|
|
18
|
+
export async function readReviews(projectName, iteration, contextDir) {
|
|
17
19
|
try {
|
|
18
|
-
const content = await readFile(reviewsPath(projectName), 'utf-8');
|
|
20
|
+
const content = await readFile(reviewsPath(projectName, iteration, contextDir), 'utf-8');
|
|
19
21
|
const data = JSON.parse(content);
|
|
20
22
|
return data.docs ?? {};
|
|
21
23
|
}
|
|
@@ -26,8 +28,8 @@ export async function readReviews(projectName) {
|
|
|
26
28
|
/**
|
|
27
29
|
* Write reviews state to disk.
|
|
28
30
|
*/
|
|
29
|
-
async function writeReviews(projectName, docs) {
|
|
30
|
-
const filePath = reviewsPath(projectName);
|
|
31
|
+
async function writeReviews(projectName, iteration, docs, contextDir) {
|
|
32
|
+
const filePath = reviewsPath(projectName, iteration, contextDir);
|
|
31
33
|
await mkdir(dirname(filePath), { recursive: true });
|
|
32
34
|
const data = { docs };
|
|
33
35
|
await writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
@@ -35,22 +37,22 @@ async function writeReviews(projectName, docs) {
|
|
|
35
37
|
/**
|
|
36
38
|
* Submit a document for review. Sets status to "pending".
|
|
37
39
|
*/
|
|
38
|
-
export async function submitForReview(projectName, docId) {
|
|
39
|
-
const reviews = await readReviews(projectName);
|
|
40
|
+
export async function submitForReview(projectName, iteration, docId, contextDir) {
|
|
41
|
+
const reviews = await readReviews(projectName, iteration, contextDir);
|
|
40
42
|
const state = {
|
|
41
43
|
docId,
|
|
42
44
|
status: 'pending',
|
|
43
45
|
submittedAt: new Date().toISOString(),
|
|
44
46
|
};
|
|
45
47
|
reviews[docId] = state;
|
|
46
|
-
await writeReviews(projectName, reviews);
|
|
48
|
+
await writeReviews(projectName, iteration, reviews, contextDir);
|
|
47
49
|
return state;
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* Approve or reject a document review.
|
|
51
53
|
*/
|
|
52
|
-
export async function resolveReview(projectName, docId, status, comment) {
|
|
53
|
-
const reviews = await readReviews(projectName);
|
|
54
|
+
export async function resolveReview(projectName, iteration, docId, status, comment, contextDir) {
|
|
55
|
+
const reviews = await readReviews(projectName, iteration, contextDir);
|
|
54
56
|
const existing = reviews[docId];
|
|
55
57
|
if (!existing) {
|
|
56
58
|
throw new Error(`No review pending for document "${docId}". Submit it for review first.`);
|
|
@@ -63,21 +65,21 @@ export async function resolveReview(projectName, docId, status, comment) {
|
|
|
63
65
|
if (comment) {
|
|
64
66
|
existing.comment = comment;
|
|
65
67
|
}
|
|
66
|
-
await writeReviews(projectName, reviews);
|
|
68
|
+
await writeReviews(projectName, iteration, reviews, contextDir);
|
|
67
69
|
return existing;
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
72
|
* Get the review state for a specific document.
|
|
71
73
|
*/
|
|
72
|
-
export async function getDocReview(projectName, docId) {
|
|
73
|
-
const reviews = await readReviews(projectName);
|
|
74
|
+
export async function getDocReview(projectName, iteration, docId, contextDir) {
|
|
75
|
+
const reviews = await readReviews(projectName, iteration, contextDir);
|
|
74
76
|
return reviews[docId] ?? null;
|
|
75
77
|
}
|
|
76
78
|
/**
|
|
77
|
-
* Get all pending reviews for a project.
|
|
79
|
+
* Get all pending reviews for a project context.
|
|
78
80
|
*/
|
|
79
|
-
export async function getPendingReviews(projectName) {
|
|
80
|
-
const reviews = await readReviews(projectName);
|
|
81
|
+
export async function getPendingReviews(projectName, iteration, contextDir) {
|
|
82
|
+
const reviews = await readReviews(projectName, iteration, contextDir);
|
|
81
83
|
return Object.values(reviews).filter((r) => r.status === 'pending');
|
|
82
84
|
}
|
|
83
85
|
//# sourceMappingURL=reviews.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reviews.js","sourceRoot":"","sources":["../../src/core/reviews.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reviews.js","sourceRoot":"","sources":["../../src/core/reviews.ts"],"names":[],"mappings":"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"}
|
package/build/core/state.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project state management — manages
|
|
2
|
+
* Project state management — manages state.json within iteration/patch directories.
|
|
3
|
+
*
|
|
4
|
+
* All functions accept an optional `contextDir` parameter. When provided, it is used
|
|
5
|
+
* directly as the directory containing state.json. When omitted, the directory is
|
|
6
|
+
* resolved from `getIterationDir(projectName, iteration)` for backward compatibility.
|
|
3
7
|
*/
|
|
4
|
-
import type { PhaseStatus, ProjectScale, ProjectState, LoadedWorkflow } from './types.js';
|
|
8
|
+
import type { ContextType, PhaseStatus, ProjectScale, ProjectState, LoadedWorkflow } from './types.js';
|
|
5
9
|
/**
|
|
6
10
|
* Error thrown when a tool requires scale but it hasn't been set yet.
|
|
7
11
|
*/
|
|
@@ -10,27 +14,31 @@ export declare class ScaleNotSetError extends Error {
|
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* Initialize a new project state file.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* For iteration mode (default): all phases start normally (first = in_progress, rest = pending).
|
|
19
|
+
* For patch mode: clarify/design are marked as "skipped", first non-skipped phase is in_progress,
|
|
20
|
+
* scale is set to "small" automatically.
|
|
21
|
+
*
|
|
22
|
+
* @param contextDir - Optional explicit directory. If omitted, uses getIterationDir().
|
|
15
23
|
*/
|
|
16
|
-
export declare function initProjectState(projectName: string, projectDir: string, workflow: LoadedWorkflow): Promise<ProjectState>;
|
|
24
|
+
export declare function initProjectState(projectName: string, projectDir: string, workflow: LoadedWorkflow, iteration: number, type?: ContextType, contextDir?: string): Promise<ProjectState>;
|
|
17
25
|
/**
|
|
18
26
|
* Read the current project state.
|
|
19
27
|
*/
|
|
20
|
-
export declare function readState(projectName: string): Promise<ProjectState>;
|
|
28
|
+
export declare function readState(projectName: string, iteration: number, contextDir?: string): Promise<ProjectState>;
|
|
21
29
|
/**
|
|
22
30
|
* Write project state to disk.
|
|
23
31
|
*/
|
|
24
|
-
export declare function writeState(projectName: string, state: ProjectState): Promise<void>;
|
|
32
|
+
export declare function writeState(projectName: string, iteration: number, state: ProjectState, contextDir?: string): Promise<void>;
|
|
25
33
|
/**
|
|
26
34
|
* Update a specific phase's status.
|
|
27
35
|
*/
|
|
28
|
-
export declare function updatePhaseStatus(projectName: string, phaseId: string, status: PhaseStatus, blockedReason?: string): Promise<ProjectState>;
|
|
36
|
+
export declare function updatePhaseStatus(projectName: string, iteration: number, phaseId: string, status: PhaseStatus, blockedReason?: string, contextDir?: string): Promise<ProjectState>;
|
|
29
37
|
/**
|
|
30
38
|
* Check if a project state file exists.
|
|
31
39
|
*/
|
|
32
|
-
export declare function projectStateExists(projectName: string): Promise<boolean>;
|
|
40
|
+
export declare function projectStateExists(projectName: string, iteration: number, contextDir?: string): Promise<boolean>;
|
|
33
41
|
/**
|
|
34
42
|
* Set the project scale. Scale is immutable once set.
|
|
35
43
|
*/
|
|
36
|
-
export declare function setScale(projectName: string, scale: ProjectScale): Promise<ProjectState>;
|
|
44
|
+
export declare function setScale(projectName: string, iteration: number, scale: ProjectScale, contextDir?: string): Promise<ProjectState>;
|
package/build/core/state.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project state management — manages
|
|
2
|
+
* Project state management — manages state.json within iteration/patch directories.
|
|
3
|
+
*
|
|
4
|
+
* All functions accept an optional `contextDir` parameter. When provided, it is used
|
|
5
|
+
* directly as the directory containing state.json. When omitted, the directory is
|
|
6
|
+
* resolved from `getIterationDir(projectName, iteration)` for backward compatibility.
|
|
3
7
|
*/
|
|
4
8
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
9
|
import { join, dirname } from 'node:path';
|
|
6
|
-
import {
|
|
10
|
+
import { getIterationDir } from './registry.js';
|
|
7
11
|
/**
|
|
8
12
|
* Error thrown when a tool requires scale but it hasn't been set yet.
|
|
9
13
|
*/
|
|
@@ -14,47 +18,65 @@ export class ScaleNotSetError extends Error {
|
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
const STATE_FILE = 'state.json';
|
|
17
|
-
function
|
|
18
|
-
return
|
|
21
|
+
function resolveDir(projectName, iteration, contextDir) {
|
|
22
|
+
return contextDir ?? getIterationDir(projectName, iteration);
|
|
19
23
|
}
|
|
24
|
+
function statePath(projectName, iteration, contextDir) {
|
|
25
|
+
return join(resolveDir(projectName, iteration, contextDir), STATE_FILE);
|
|
26
|
+
}
|
|
27
|
+
/** Phases to skip in patch mode (clarify and design) */
|
|
28
|
+
const PATCH_SKIP_PHASES = new Set(['clarify', 'design']);
|
|
20
29
|
/**
|
|
21
30
|
* Initialize a new project state file.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
31
|
+
*
|
|
32
|
+
* For iteration mode (default): all phases start normally (first = in_progress, rest = pending).
|
|
33
|
+
* For patch mode: clarify/design are marked as "skipped", first non-skipped phase is in_progress,
|
|
34
|
+
* scale is set to "small" automatically.
|
|
35
|
+
*
|
|
36
|
+
* @param contextDir - Optional explicit directory. If omitted, uses getIterationDir().
|
|
24
37
|
*/
|
|
25
|
-
export async function initProjectState(projectName, projectDir, workflow) {
|
|
38
|
+
export async function initProjectState(projectName, projectDir, workflow, iteration, type = 'iteration', contextDir) {
|
|
26
39
|
const now = new Date().toISOString();
|
|
27
40
|
const phases = workflow.definition.phases;
|
|
28
|
-
const
|
|
41
|
+
const isPatch = type === 'patch';
|
|
42
|
+
// Find the first non-skipped phase
|
|
43
|
+
const firstActiveIndex = isPatch ? phases.findIndex((p) => !PATCH_SKIP_PHASES.has(p.id)) : 0;
|
|
44
|
+
const firstPhaseId = phases[firstActiveIndex]?.id ?? phases[0]?.id ?? '';
|
|
29
45
|
const state = {
|
|
30
46
|
projectName,
|
|
31
47
|
projectDir,
|
|
32
48
|
workflow: workflow.definition.name,
|
|
33
|
-
|
|
49
|
+
type,
|
|
50
|
+
iteration,
|
|
51
|
+
scale: isPatch ? 'small' : null,
|
|
34
52
|
currentPhase: firstPhaseId,
|
|
35
|
-
phases: phases.map((p, i) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
phases: phases.map((p, i) => {
|
|
54
|
+
if (isPatch && PATCH_SKIP_PHASES.has(p.id)) {
|
|
55
|
+
return { id: p.id, status: 'skipped' };
|
|
56
|
+
}
|
|
57
|
+
if (i === firstActiveIndex) {
|
|
58
|
+
return { id: p.id, status: 'in_progress', startedAt: now };
|
|
59
|
+
}
|
|
60
|
+
return { id: p.id, status: 'pending' };
|
|
61
|
+
}),
|
|
40
62
|
createdAt: now,
|
|
41
63
|
updatedAt: now,
|
|
42
64
|
};
|
|
43
|
-
await writeState(projectName, state);
|
|
65
|
+
await writeState(projectName, iteration, state, contextDir);
|
|
44
66
|
return state;
|
|
45
67
|
}
|
|
46
68
|
/**
|
|
47
69
|
* Read the current project state.
|
|
48
70
|
*/
|
|
49
|
-
export async function readState(projectName) {
|
|
50
|
-
const content = await readFile(statePath(projectName), 'utf-8');
|
|
71
|
+
export async function readState(projectName, iteration, contextDir) {
|
|
72
|
+
const content = await readFile(statePath(projectName, iteration, contextDir), 'utf-8');
|
|
51
73
|
return JSON.parse(content);
|
|
52
74
|
}
|
|
53
75
|
/**
|
|
54
76
|
* Write project state to disk.
|
|
55
77
|
*/
|
|
56
|
-
export async function writeState(projectName, state) {
|
|
57
|
-
const filePath = statePath(projectName);
|
|
78
|
+
export async function writeState(projectName, iteration, state, contextDir) {
|
|
79
|
+
const filePath = statePath(projectName, iteration, contextDir);
|
|
58
80
|
await mkdir(dirname(filePath), { recursive: true });
|
|
59
81
|
state.updatedAt = new Date().toISOString();
|
|
60
82
|
await writeFile(filePath, JSON.stringify(state, null, 2) + '\n', 'utf-8');
|
|
@@ -62,8 +84,8 @@ export async function writeState(projectName, state) {
|
|
|
62
84
|
/**
|
|
63
85
|
* Update a specific phase's status.
|
|
64
86
|
*/
|
|
65
|
-
export async function updatePhaseStatus(projectName, phaseId, status, blockedReason) {
|
|
66
|
-
const state = await readState(projectName);
|
|
87
|
+
export async function updatePhaseStatus(projectName, iteration, phaseId, status, blockedReason, contextDir) {
|
|
88
|
+
const state = await readState(projectName, iteration, contextDir);
|
|
67
89
|
const phase = state.phases.find((p) => p.id === phaseId);
|
|
68
90
|
if (!phase) {
|
|
69
91
|
throw new Error(`Phase "${phaseId}" not found in project state`);
|
|
@@ -85,6 +107,7 @@ export async function updatePhaseStatus(projectName, phaseId, status, blockedRea
|
|
|
85
107
|
state.currentPhase = phaseId;
|
|
86
108
|
}
|
|
87
109
|
// If completing a phase, auto-advance currentPhase to the next pending one
|
|
110
|
+
// (skip over phases that are already "skipped")
|
|
88
111
|
if (status === 'completed') {
|
|
89
112
|
const idx = state.phases.findIndex((p) => p.id === phaseId);
|
|
90
113
|
const next = state.phases.find((p, i) => i > idx && p.status === 'pending');
|
|
@@ -94,15 +117,15 @@ export async function updatePhaseStatus(projectName, phaseId, status, blockedRea
|
|
|
94
117
|
state.currentPhase = next.id;
|
|
95
118
|
}
|
|
96
119
|
}
|
|
97
|
-
await writeState(projectName, state);
|
|
120
|
+
await writeState(projectName, iteration, state, contextDir);
|
|
98
121
|
return state;
|
|
99
122
|
}
|
|
100
123
|
/**
|
|
101
124
|
* Check if a project state file exists.
|
|
102
125
|
*/
|
|
103
|
-
export async function projectStateExists(projectName) {
|
|
126
|
+
export async function projectStateExists(projectName, iteration, contextDir) {
|
|
104
127
|
try {
|
|
105
|
-
await readFile(statePath(projectName), 'utf-8');
|
|
128
|
+
await readFile(statePath(projectName, iteration, contextDir), 'utf-8');
|
|
106
129
|
return true;
|
|
107
130
|
}
|
|
108
131
|
catch {
|
|
@@ -112,13 +135,13 @@ export async function projectStateExists(projectName) {
|
|
|
112
135
|
/**
|
|
113
136
|
* Set the project scale. Scale is immutable once set.
|
|
114
137
|
*/
|
|
115
|
-
export async function setScale(projectName, scale) {
|
|
116
|
-
const state = await readState(projectName);
|
|
138
|
+
export async function setScale(projectName, iteration, scale, contextDir) {
|
|
139
|
+
const state = await readState(projectName, iteration, contextDir);
|
|
117
140
|
if (state.scale !== null) {
|
|
118
141
|
throw new Error(`Scale 已设定为 "${state.scale}",不可更改。如需调整规模,请重新评估 PRD。`);
|
|
119
142
|
}
|
|
120
143
|
state.scale = scale;
|
|
121
|
-
await writeState(projectName, state);
|
|
144
|
+
await writeState(projectName, iteration, state, contextDir);
|
|
122
145
|
return state;
|
|
123
146
|
}
|
|
124
147
|
//# sourceMappingURL=state.js.map
|
package/build/core/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD;;GAEG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACvC,YAAY,WAAmB;QAC3B,KAAK,CAAC,OAAO,WAAW,yDAAyD,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACnC,CAAC;CACJ;AAED,MAAM,UAAU,GAAG,YAAY,CAAC;AAEhC,SAAS,UAAU,CAAC,WAAmB,EAAE,SAAiB,EAAE,UAAmB;IAC3E,OAAO,UAAU,IAAI,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,SAAS,CAAC,WAAmB,EAAE,SAAiB,EAAE,UAAmB;IAC1E,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;AAC5E,CAAC;AAED,wDAAwD;AACxD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAClC,WAAmB,EACnB,UAAkB,EAClB,QAAwB,EACxB,SAAiB,EACjB,OAAoB,WAAW,EAC/B,UAAmB;IAEnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,KAAK,OAAO,CAAC;IAEjC,mCAAmC;IACnC,MAAM,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;IAEzE,MAAM,KAAK,GAAiB;QACxB,WAAW;QACX,UAAU;QACV,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI;QAClC,IAAI;QACJ,SAAS;QACT,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC/B,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACxB,IAAI,OAAO,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBACzC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,SAAkB,EAAE,CAAC;YACpD,CAAC;YACD,IAAI,CAAC,KAAK,gBAAgB,EAAE,CAAC;gBACzB,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,aAAsB,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;YACxE,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,SAAkB,EAAE,CAAC;QACpD,CAAC,CAAC;QACF,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACjB,CAAC;IAEF,MAAM,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,WAAmB,EAAE,SAAiB,EAAE,UAAmB;IACvF,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,WAAmB,EACnB,SAAiB,EACjB,KAAmB,EACnB,UAAmB;IAEnB,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,WAAmB,EACnB,SAAiB,EACjB,OAAe,EACf,MAAmB,EACnB,aAAsB,EACtB,UAAmB;IAEnB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IAEzD,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,UAAU,OAAO,8BAA8B,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IAEtB,IAAI,MAAM,KAAK,aAAa,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QAC/C,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;IAC1B,CAAC;IACD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QACzB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;QACxB,OAAO,KAAK,CAAC,aAAa,CAAC;IAC/B,CAAC;IACD,IAAI,MAAM,KAAK,SAAS,IAAI,aAAa,EAAE,CAAC;QACxC,KAAK,CAAC,aAAa,GAAG,aAAa,CAAC;IACxC,CAAC;IAED,mDAAmD;IACnD,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC;IACjC,CAAC;IAED,2EAA2E;IAC3E,gDAAgD;IAChD,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC5E,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC;YAC5B,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;YACrB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC;QACjC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACpC,WAAmB,EACnB,SAAiB,EACjB,UAAmB;IAEnB,IAAI,CAAC;QACD,MAAM,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC1B,WAAmB,EACnB,SAAiB,EACjB,KAAmB,EACnB,UAAmB;IAEnB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,CAAC,KAAK,0BAA0B,CAAC,CAAC;IAC1E,CAAC;IACD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,MAAM,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC;AACjB,CAAC"}
|