maskweaver 0.8.3 → 0.8.4
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.ko.md +50 -14
- package/README.md +50 -14
- package/dist/plugin/tools/weave.d.ts.map +1 -1
- package/dist/plugin/tools/weave.js +234 -14
- package/dist/plugin/tools/weave.js.map +1 -1
- package/dist/shared/config.d.ts +14 -0
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +7 -0
- package/dist/shared/config.js.map +1 -1
- package/dist/shared-context/test/squad.test.js +2 -2
- package/dist/shared-context/test/squad.test.js.map +1 -1
- package/dist/shared-context/test/storage.test.js +3 -3
- package/dist/shared-context/test/storage.test.js.map +1 -1
- package/dist/shared-context/test/task.test.js +6 -6
- package/dist/shared-context/test/task.test.js.map +1 -1
- package/dist/weave/gdc.d.ts +59 -0
- package/dist/weave/gdc.d.ts.map +1 -0
- package/dist/weave/gdc.js +221 -0
- package/dist/weave/gdc.js.map +1 -0
- package/dist/weave/stages/research.d.ts +1 -1
- package/dist/weave/stages/research.d.ts.map +1 -1
- package/dist/weave/stages/research.js +225 -5
- package/dist/weave/stages/research.js.map +1 -1
- package/package.json +8 -2
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type GdcEnabledMode = boolean | 'auto';
|
|
2
|
+
export interface EffectiveGdcConfig {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
mode: GdcEnabledMode;
|
|
5
|
+
detected: boolean;
|
|
6
|
+
strictVerify: boolean;
|
|
7
|
+
binPath: string;
|
|
8
|
+
autoSyncOnPrepare: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface GdcMachineEnvelope {
|
|
11
|
+
ok?: boolean;
|
|
12
|
+
contractVersion?: string;
|
|
13
|
+
command?: string;
|
|
14
|
+
timestamp?: string;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
warnings?: unknown[];
|
|
17
|
+
errors?: unknown[];
|
|
18
|
+
meta?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface GdcMachineCommandResult {
|
|
21
|
+
command: string;
|
|
22
|
+
args: string[];
|
|
23
|
+
exitCode: number;
|
|
24
|
+
stdout: string;
|
|
25
|
+
stderr: string;
|
|
26
|
+
durationMs: number;
|
|
27
|
+
timedOut: boolean;
|
|
28
|
+
transportError?: string;
|
|
29
|
+
parseError?: string;
|
|
30
|
+
envelope?: GdcMachineEnvelope;
|
|
31
|
+
data?: unknown;
|
|
32
|
+
}
|
|
33
|
+
export declare function detectGdcWorkspace(basePath: string): boolean;
|
|
34
|
+
export declare function getEffectiveGdcConfig(basePath: string): EffectiveGdcConfig;
|
|
35
|
+
export declare function runGdcMachineCommand(options: {
|
|
36
|
+
basePath: string;
|
|
37
|
+
command: string;
|
|
38
|
+
args?: string[];
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
maxOutputChars?: number;
|
|
41
|
+
config?: EffectiveGdcConfig;
|
|
42
|
+
}): Promise<GdcMachineCommandResult>;
|
|
43
|
+
export declare function countGdcCheckIssues(data: unknown): {
|
|
44
|
+
errors: number;
|
|
45
|
+
warnings: number;
|
|
46
|
+
infos: number;
|
|
47
|
+
issueCount: number;
|
|
48
|
+
};
|
|
49
|
+
export declare function getGraphNodeIds(data: unknown): string[];
|
|
50
|
+
export declare function getGraphEdges(data: unknown): Array<{
|
|
51
|
+
from: string;
|
|
52
|
+
to: string;
|
|
53
|
+
}>;
|
|
54
|
+
export declare function getStatsNodeSummary(data: unknown): {
|
|
55
|
+
total?: number;
|
|
56
|
+
implemented?: number;
|
|
57
|
+
tested?: number;
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=gdc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gdc.d.ts","sourceRoot":"","sources":["../../src/weave/gdc.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IAC/B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAgCD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAO5D;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAc1E;AA8CD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC/B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAsEnC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACtB,CA0BA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAYvD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAahF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CASA"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { execFile } from 'node:child_process';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
import { getGdcConfig } from '../shared/config.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
function asObject(value) {
|
|
8
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
9
|
+
return null;
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function asArray(value) {
|
|
13
|
+
return Array.isArray(value) ? value : [];
|
|
14
|
+
}
|
|
15
|
+
function asNumber(value) {
|
|
16
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
17
|
+
return value;
|
|
18
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
19
|
+
const parsed = Number(value);
|
|
20
|
+
if (Number.isFinite(parsed))
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
function isMachineEnvelope(value) {
|
|
26
|
+
const obj = asObject(value);
|
|
27
|
+
if (!obj)
|
|
28
|
+
return false;
|
|
29
|
+
return (Object.prototype.hasOwnProperty.call(obj, 'data')
|
|
30
|
+
|| Object.prototype.hasOwnProperty.call(obj, 'ok')
|
|
31
|
+
|| Object.prototype.hasOwnProperty.call(obj, 'contractVersion')
|
|
32
|
+
|| Object.prototype.hasOwnProperty.call(obj, 'warnings')
|
|
33
|
+
|| Object.prototype.hasOwnProperty.call(obj, 'errors'));
|
|
34
|
+
}
|
|
35
|
+
export function detectGdcWorkspace(basePath) {
|
|
36
|
+
const gdcDir = path.join(basePath, '.gdc');
|
|
37
|
+
return (fs.existsSync(gdcDir)
|
|
38
|
+
|| fs.existsSync(path.join(gdcDir, 'config.yaml'))
|
|
39
|
+
|| fs.existsSync(path.join(gdcDir, 'nodes')));
|
|
40
|
+
}
|
|
41
|
+
export function getEffectiveGdcConfig(basePath) {
|
|
42
|
+
const config = getGdcConfig(basePath);
|
|
43
|
+
const mode = (config?.enabled ?? 'auto');
|
|
44
|
+
const detected = detectGdcWorkspace(basePath);
|
|
45
|
+
const enabled = mode === true || (mode !== false && detected);
|
|
46
|
+
return {
|
|
47
|
+
enabled,
|
|
48
|
+
mode,
|
|
49
|
+
detected,
|
|
50
|
+
strictVerify: config?.strictVerify ?? false,
|
|
51
|
+
binPath: config?.binPath?.trim() || 'gdc',
|
|
52
|
+
autoSyncOnPrepare: config?.autoSyncOnPrepare ?? true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function parseMachineOutput(stdout) {
|
|
56
|
+
const text = stdout.trim();
|
|
57
|
+
if (!text) {
|
|
58
|
+
return { parseError: 'empty stdout' };
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(text);
|
|
62
|
+
if (isMachineEnvelope(parsed)) {
|
|
63
|
+
const envelope = parsed;
|
|
64
|
+
return { envelope, data: envelope.data };
|
|
65
|
+
}
|
|
66
|
+
return { data: parsed };
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
+
return { parseError: message };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function splitCommand(commandText) {
|
|
74
|
+
const trimmed = commandText.trim();
|
|
75
|
+
if (!trimmed)
|
|
76
|
+
return [];
|
|
77
|
+
const tokens = trimmed.match(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^\s]+/g) || [];
|
|
78
|
+
return tokens
|
|
79
|
+
.map(token => token.trim())
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.map(token => {
|
|
82
|
+
if ((token.startsWith('"') && token.endsWith('"')) || (token.startsWith("'") && token.endsWith("'"))) {
|
|
83
|
+
return token.slice(1, -1);
|
|
84
|
+
}
|
|
85
|
+
return token;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function toTail(text, maxChars) {
|
|
89
|
+
if (text.length <= maxChars)
|
|
90
|
+
return text;
|
|
91
|
+
return text.slice(text.length - maxChars);
|
|
92
|
+
}
|
|
93
|
+
export async function runGdcMachineCommand(options) {
|
|
94
|
+
const cfg = options.config || getEffectiveGdcConfig(options.basePath);
|
|
95
|
+
const timeoutMs = options.timeoutMs ?? 90_000;
|
|
96
|
+
const maxOutputChars = options.maxOutputChars ?? 200_000;
|
|
97
|
+
const requestedArgs = options.args ? [...options.args] : [];
|
|
98
|
+
if (!requestedArgs.includes('--machine')) {
|
|
99
|
+
requestedArgs.push('--machine');
|
|
100
|
+
}
|
|
101
|
+
const commandParts = splitCommand(cfg.binPath);
|
|
102
|
+
const binary = commandParts[0] || 'gdc';
|
|
103
|
+
const binaryArgs = commandParts.slice(1);
|
|
104
|
+
const fullArgs = [...binaryArgs, options.command, ...requestedArgs];
|
|
105
|
+
const start = Date.now();
|
|
106
|
+
try {
|
|
107
|
+
const { stdout, stderr } = await execFileAsync(binary, fullArgs, {
|
|
108
|
+
cwd: options.basePath,
|
|
109
|
+
timeout: timeoutMs,
|
|
110
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
111
|
+
windowsHide: true,
|
|
112
|
+
});
|
|
113
|
+
const stdoutText = toTail(String(stdout || '').trim(), maxOutputChars);
|
|
114
|
+
const stderrText = toTail(String(stderr || '').trim(), maxOutputChars);
|
|
115
|
+
const parsed = parseMachineOutput(stdoutText);
|
|
116
|
+
return {
|
|
117
|
+
command: options.command,
|
|
118
|
+
args: requestedArgs,
|
|
119
|
+
exitCode: 0,
|
|
120
|
+
stdout: stdoutText,
|
|
121
|
+
stderr: stderrText,
|
|
122
|
+
durationMs: Date.now() - start,
|
|
123
|
+
timedOut: false,
|
|
124
|
+
envelope: parsed.envelope,
|
|
125
|
+
data: parsed.data,
|
|
126
|
+
parseError: parsed.parseError,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
const rawCode = error?.code;
|
|
131
|
+
const exitCode = typeof rawCode === 'number'
|
|
132
|
+
? rawCode
|
|
133
|
+
: rawCode === 'ENOENT'
|
|
134
|
+
? 127
|
|
135
|
+
: 1;
|
|
136
|
+
const stdoutText = toTail(String(error?.stdout || '').trim(), maxOutputChars);
|
|
137
|
+
const stderrText = toTail(String(error?.stderr || '').trim(), maxOutputChars);
|
|
138
|
+
const timedOut = Boolean(error?.killed)
|
|
139
|
+
|| /timed?\s*out/i.test(String(error?.message || ''));
|
|
140
|
+
const parsed = parseMachineOutput(stdoutText);
|
|
141
|
+
const transportError = rawCode === 'ENOENT'
|
|
142
|
+
? `GDC binary not found: ${cfg.binPath}`
|
|
143
|
+
: (error instanceof Error ? error.message : String(error));
|
|
144
|
+
return {
|
|
145
|
+
command: options.command,
|
|
146
|
+
args: requestedArgs,
|
|
147
|
+
exitCode,
|
|
148
|
+
stdout: stdoutText,
|
|
149
|
+
stderr: stderrText,
|
|
150
|
+
durationMs: Date.now() - start,
|
|
151
|
+
timedOut,
|
|
152
|
+
transportError,
|
|
153
|
+
envelope: parsed.envelope,
|
|
154
|
+
data: parsed.data,
|
|
155
|
+
parseError: parsed.parseError,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export function countGdcCheckIssues(data) {
|
|
160
|
+
const payload = asObject(data) || {};
|
|
161
|
+
const summary = asObject(payload.summary) || {};
|
|
162
|
+
const summaryErrors = asNumber(summary.error) ?? 0;
|
|
163
|
+
const summaryWarnings = asNumber(summary.warning) ?? 0;
|
|
164
|
+
const summaryInfos = asNumber(summary.info) ?? 0;
|
|
165
|
+
const issues = asArray(payload.issues);
|
|
166
|
+
let issueErrors = 0;
|
|
167
|
+
let issueWarnings = 0;
|
|
168
|
+
let issueInfos = 0;
|
|
169
|
+
for (const issue of issues) {
|
|
170
|
+
const item = asObject(issue);
|
|
171
|
+
const severity = String(item?.severity || '').toLowerCase();
|
|
172
|
+
if (severity === 'error')
|
|
173
|
+
issueErrors += 1;
|
|
174
|
+
else if (severity === 'warning' || severity === 'warn')
|
|
175
|
+
issueWarnings += 1;
|
|
176
|
+
else if (severity === 'info')
|
|
177
|
+
issueInfos += 1;
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
errors: Math.max(summaryErrors, issueErrors),
|
|
181
|
+
warnings: Math.max(summaryWarnings, issueWarnings),
|
|
182
|
+
infos: Math.max(summaryInfos, issueInfos),
|
|
183
|
+
issueCount: issues.length,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
export function getGraphNodeIds(data) {
|
|
187
|
+
const payload = asObject(data);
|
|
188
|
+
const nodes = asArray(payload?.nodes);
|
|
189
|
+
const ids = new Set();
|
|
190
|
+
for (const node of nodes) {
|
|
191
|
+
const item = asObject(node);
|
|
192
|
+
const id = typeof item?.id === 'string' ? item.id : '';
|
|
193
|
+
if (id)
|
|
194
|
+
ids.add(id);
|
|
195
|
+
}
|
|
196
|
+
return Array.from(ids);
|
|
197
|
+
}
|
|
198
|
+
export function getGraphEdges(data) {
|
|
199
|
+
const payload = asObject(data);
|
|
200
|
+
const edges = asArray(payload?.edges);
|
|
201
|
+
const result = [];
|
|
202
|
+
for (const edge of edges) {
|
|
203
|
+
const item = asObject(edge);
|
|
204
|
+
const from = typeof item?.from === 'string' ? item.from : '';
|
|
205
|
+
const to = typeof item?.to === 'string' ? item.to : '';
|
|
206
|
+
if (from && to)
|
|
207
|
+
result.push({ from, to });
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
export function getStatsNodeSummary(data) {
|
|
212
|
+
const payload = asObject(data);
|
|
213
|
+
const nodes = asObject(payload?.nodes);
|
|
214
|
+
const byStatus = asObject(nodes?.byStatus);
|
|
215
|
+
return {
|
|
216
|
+
total: asNumber(nodes?.total),
|
|
217
|
+
implemented: asNumber(byStatus?.implemented),
|
|
218
|
+
tested: asNumber(byStatus?.tested),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=gdc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gdc.js","sourceRoot":"","sources":["../../src/weave/gdc.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,6 @@ export interface ResearchResult {
|
|
|
17
17
|
summary: string;
|
|
18
18
|
report: string;
|
|
19
19
|
}
|
|
20
|
-
export declare function buildResearchReport(options: ResearchOptions): string
|
|
20
|
+
export declare function buildResearchReport(options: ResearchOptions): Promise<string>;
|
|
21
21
|
export declare function writeResearchReport(options: ResearchOptions): Promise<ResearchResult>;
|
|
22
22
|
//# sourceMappingURL=research.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"research.d.ts","sourceRoot":"","sources":["../../../src/weave/stages/research.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"research.d.ts","sourceRoot":"","sources":["../../../src/weave/stages/research.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUhD,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AA8tBD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAgHnF;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA2B3F"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from 'node:fs';
|
|
8
8
|
import * as path from 'node:path';
|
|
9
|
+
import { getEffectiveGdcConfig, runGdcMachineCommand, countGdcCheckIssues, getGraphNodeIds, getGraphEdges, getStatsNodeSummary, } from '../gdc.js';
|
|
9
10
|
const WORKSPACE_IGNORED_DIRS = new Set([
|
|
10
11
|
'.git',
|
|
11
12
|
'.idea',
|
|
@@ -26,6 +27,10 @@ const WORKSPACE_IGNORED_DIRS = new Set([
|
|
|
26
27
|
'target',
|
|
27
28
|
'out',
|
|
28
29
|
]);
|
|
30
|
+
const WORKSPACE_ALLOWED_DOT_DIRS = new Set([
|
|
31
|
+
'.github',
|
|
32
|
+
'.gdc',
|
|
33
|
+
]);
|
|
29
34
|
const TEXT_EXTENSIONS = new Set([
|
|
30
35
|
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
31
36
|
'.json', '.yaml', '.yml', '.md', '.txt',
|
|
@@ -147,7 +152,7 @@ function collectWorkspaceFiles(basePath, maxFiles = MAX_WORKSPACE_FILES) {
|
|
|
147
152
|
if (entry.isDirectory()) {
|
|
148
153
|
if (WORKSPACE_IGNORED_DIRS.has(entry.name))
|
|
149
154
|
continue;
|
|
150
|
-
if (entry.name.startsWith('.') && entry.name
|
|
155
|
+
if (entry.name.startsWith('.') && !WORKSPACE_ALLOWED_DOT_DIRS.has(entry.name))
|
|
151
156
|
continue;
|
|
152
157
|
stack.push(fullPath);
|
|
153
158
|
continue;
|
|
@@ -297,7 +302,199 @@ function findRelatedTests(testFiles, featureNeedles) {
|
|
|
297
302
|
}
|
|
298
303
|
return uniq(related).slice(0, 10);
|
|
299
304
|
}
|
|
300
|
-
function
|
|
305
|
+
function listFilesRecursive(rootDir, exts) {
|
|
306
|
+
const files = [];
|
|
307
|
+
const stack = [rootDir];
|
|
308
|
+
while (stack.length > 0) {
|
|
309
|
+
const current = stack.pop();
|
|
310
|
+
let entries = [];
|
|
311
|
+
try {
|
|
312
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
for (const entry of entries) {
|
|
318
|
+
const fullPath = path.join(current, entry.name);
|
|
319
|
+
if (entry.isSymbolicLink())
|
|
320
|
+
continue;
|
|
321
|
+
if (entry.isDirectory()) {
|
|
322
|
+
stack.push(fullPath);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (!entry.isFile())
|
|
326
|
+
continue;
|
|
327
|
+
if (exts) {
|
|
328
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
329
|
+
if (!exts.has(ext))
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
files.push(fullPath);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return files;
|
|
336
|
+
}
|
|
337
|
+
function containsNeedle(target, needles) {
|
|
338
|
+
const lower = target.toLowerCase();
|
|
339
|
+
return needles.some(needle => lower.includes(needle));
|
|
340
|
+
}
|
|
341
|
+
async function analyzeGdcContext(basePath, intake) {
|
|
342
|
+
const gdcDir = path.join(basePath, '.gdc');
|
|
343
|
+
const configPath = path.join(gdcDir, 'config.yaml');
|
|
344
|
+
const graphDbPath = path.join(gdcDir, 'graph.db');
|
|
345
|
+
const nodesDir = path.join(gdcDir, 'nodes');
|
|
346
|
+
const hasGdcDir = fs.existsSync(gdcDir);
|
|
347
|
+
const hasConfig = fs.existsSync(configPath);
|
|
348
|
+
const hasNodes = fs.existsSync(nodesDir);
|
|
349
|
+
const hasGraphDb = fs.existsSync(graphDbPath);
|
|
350
|
+
const detected = hasGdcDir || hasConfig || hasNodes;
|
|
351
|
+
const gdcRuntime = getEffectiveGdcConfig(basePath);
|
|
352
|
+
if (!detected) {
|
|
353
|
+
return {
|
|
354
|
+
detected: false,
|
|
355
|
+
gateEnabled: gdcRuntime.enabled,
|
|
356
|
+
nodeSpecFiles: 0,
|
|
357
|
+
hasGraphDb: false,
|
|
358
|
+
sampleNodes: [],
|
|
359
|
+
machineSignals: [],
|
|
360
|
+
candidateReuseNodes: [],
|
|
361
|
+
dependencyBlastRadius: ['GDC metadata not detected in this workspace.'],
|
|
362
|
+
driftSignals: ['No GDC spec/graph available. Drift analysis skipped.'],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
const nodeSpecFiles = hasNodes
|
|
366
|
+
? listFilesRecursive(nodesDir, new Set(['.yaml', '.yml']))
|
|
367
|
+
: [];
|
|
368
|
+
const featureNeedles = buildFeatureNeedles(intake);
|
|
369
|
+
const sampleNodes = nodeSpecFiles
|
|
370
|
+
.map(file => toRelativePath(basePath, file))
|
|
371
|
+
.sort((a, b) => a.localeCompare(b))
|
|
372
|
+
.slice(0, 12);
|
|
373
|
+
let candidateReuseNodes = nodeSpecFiles
|
|
374
|
+
.filter(file => {
|
|
375
|
+
const normalized = file.replace(/\\/g, '/').toLowerCase();
|
|
376
|
+
return featureNeedles.some(needle => normalized.includes(needle));
|
|
377
|
+
})
|
|
378
|
+
.map(file => `\`${toRelativePath(basePath, file)}\``)
|
|
379
|
+
.slice(0, 12);
|
|
380
|
+
const machineSignals = [];
|
|
381
|
+
let statsResult = null;
|
|
382
|
+
let graphResult = null;
|
|
383
|
+
let checkResult = null;
|
|
384
|
+
if (gdcRuntime.enabled) {
|
|
385
|
+
[statsResult, graphResult, checkResult] = await Promise.all([
|
|
386
|
+
runGdcMachineCommand({
|
|
387
|
+
basePath,
|
|
388
|
+
command: 'stats',
|
|
389
|
+
config: gdcRuntime,
|
|
390
|
+
timeoutMs: 30_000,
|
|
391
|
+
}),
|
|
392
|
+
runGdcMachineCommand({
|
|
393
|
+
basePath,
|
|
394
|
+
command: 'graph',
|
|
395
|
+
args: ['--format', 'json'],
|
|
396
|
+
config: gdcRuntime,
|
|
397
|
+
timeoutMs: 45_000,
|
|
398
|
+
}),
|
|
399
|
+
runGdcMachineCommand({
|
|
400
|
+
basePath,
|
|
401
|
+
command: 'check',
|
|
402
|
+
config: gdcRuntime,
|
|
403
|
+
timeoutMs: 45_000,
|
|
404
|
+
}),
|
|
405
|
+
]);
|
|
406
|
+
machineSignals.push(`stats exit=${statsResult.exitCode}`);
|
|
407
|
+
machineSignals.push(`graph exit=${graphResult.exitCode}`);
|
|
408
|
+
machineSignals.push(`check exit=${checkResult.exitCode}`);
|
|
409
|
+
const statsSummary = getStatsNodeSummary(statsResult.data);
|
|
410
|
+
if (typeof statsSummary.total === 'number') {
|
|
411
|
+
machineSignals.push(`stats nodes.total=${statsSummary.total}`);
|
|
412
|
+
}
|
|
413
|
+
const graphNodeIds = getGraphNodeIds(graphResult.data);
|
|
414
|
+
if (graphNodeIds.length > 0) {
|
|
415
|
+
machineSignals.push(`graph nodes=${graphNodeIds.length}`);
|
|
416
|
+
}
|
|
417
|
+
const graphMatchedNodes = graphNodeIds
|
|
418
|
+
.filter(nodeId => containsNeedle(nodeId, featureNeedles))
|
|
419
|
+
.slice(0, 12)
|
|
420
|
+
.map(nodeId => `\`${nodeId}\``);
|
|
421
|
+
if (graphMatchedNodes.length > 0) {
|
|
422
|
+
candidateReuseNodes = uniq([...graphMatchedNodes, ...candidateReuseNodes]).slice(0, 12);
|
|
423
|
+
}
|
|
424
|
+
const checkCounts = countGdcCheckIssues(checkResult.data);
|
|
425
|
+
if (checkCounts.issueCount > 0 || checkResult.exitCode === 2) {
|
|
426
|
+
machineSignals.push(`check issues=${checkCounts.issueCount}`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
let dependencyBlastRadius = candidateReuseNodes.length > 0
|
|
430
|
+
? [
|
|
431
|
+
`Candidate node specs touching requested features: ${candidateReuseNodes.slice(0, 5).join(', ')}`,
|
|
432
|
+
'Run `gdc trace <node> --direction both --machine` to measure full dependency impact.',
|
|
433
|
+
]
|
|
434
|
+
: [
|
|
435
|
+
'No direct node filename matches found for requested features.',
|
|
436
|
+
'Run `gdc query <feature>` then `gdc trace <node> --direction both --machine` for graph-level impact.',
|
|
437
|
+
];
|
|
438
|
+
if (graphResult) {
|
|
439
|
+
const edges = getGraphEdges(graphResult.data);
|
|
440
|
+
if (edges.length > 0 && candidateReuseNodes.length > 0) {
|
|
441
|
+
const degree = new Map();
|
|
442
|
+
for (const edge of edges) {
|
|
443
|
+
degree.set(edge.from, (degree.get(edge.from) || 0) + 1);
|
|
444
|
+
degree.set(edge.to, (degree.get(edge.to) || 0) + 1);
|
|
445
|
+
}
|
|
446
|
+
const ranked = candidateReuseNodes
|
|
447
|
+
.map(token => token.replace(/`/g, ''))
|
|
448
|
+
.map(nodeId => ({ nodeId, score: degree.get(nodeId) || 0 }))
|
|
449
|
+
.sort((a, b) => b.score - a.score || a.nodeId.localeCompare(b.nodeId))
|
|
450
|
+
.slice(0, 5);
|
|
451
|
+
if (ranked.length > 0) {
|
|
452
|
+
dependencyBlastRadius = [
|
|
453
|
+
`Graph neighbors for candidate nodes: ${ranked.map(item => `\`${item.nodeId}\`(${item.score})`).join(', ')}`,
|
|
454
|
+
'Higher degree nodes usually imply broader dependency impact.',
|
|
455
|
+
];
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
const driftSignals = [];
|
|
460
|
+
if (!hasConfig)
|
|
461
|
+
driftSignals.push('`.gdc/config.yaml` missing: spec/runtime alignment checks may be incomplete.');
|
|
462
|
+
if (!hasGraphDb)
|
|
463
|
+
driftSignals.push('`.gdc/graph.db` missing: run `gdc sync` before `gdc check`.');
|
|
464
|
+
if (nodeSpecFiles.length === 0)
|
|
465
|
+
driftSignals.push('No `.gdc/nodes/*.yaml` specs found.');
|
|
466
|
+
if (checkResult) {
|
|
467
|
+
const checkCounts = countGdcCheckIssues(checkResult.data);
|
|
468
|
+
if (checkResult.exitCode === 2 || checkCounts.errors > 0) {
|
|
469
|
+
driftSignals.push(`GDC check reports blocking issues (errors=${checkCounts.errors}, warnings=${checkCounts.warnings}).`);
|
|
470
|
+
}
|
|
471
|
+
else if (checkResult.exitCode === 0) {
|
|
472
|
+
driftSignals.push(`GDC check clean (errors=${checkCounts.errors}, warnings=${checkCounts.warnings}, info=${checkCounts.infos}).`);
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
driftSignals.push(`GDC check command failed (exit=${checkResult.exitCode}).`);
|
|
476
|
+
}
|
|
477
|
+
if (checkResult.parseError) {
|
|
478
|
+
driftSignals.push(`Machine output parse warning: ${normalizeLine(checkResult.parseError, 120)}`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (driftSignals.length === 0) {
|
|
482
|
+
driftSignals.push('GDC metadata detected. Run `gdc check --machine` to confirm spec/implementation drift.');
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
detected: true,
|
|
486
|
+
gateEnabled: gdcRuntime.enabled,
|
|
487
|
+
configPath: hasConfig ? toRelativePath(basePath, configPath) : undefined,
|
|
488
|
+
nodeSpecFiles: nodeSpecFiles.length,
|
|
489
|
+
hasGraphDb,
|
|
490
|
+
sampleNodes,
|
|
491
|
+
machineSignals,
|
|
492
|
+
candidateReuseNodes,
|
|
493
|
+
dependencyBlastRadius,
|
|
494
|
+
driftSignals,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async function analyzeWorkspaceContext(basePath, intake) {
|
|
301
498
|
const workspaceFiles = collectWorkspaceFiles(basePath);
|
|
302
499
|
const codeFiles = workspaceFiles.filter(isCodeFile);
|
|
303
500
|
const testFiles = workspaceFiles.filter(isTestFile);
|
|
@@ -416,7 +613,9 @@ function analyzeWorkspaceContext(basePath, intake) {
|
|
|
416
613
|
'next.config.js',
|
|
417
614
|
'docker-compose.yml',
|
|
418
615
|
'.github/workflows',
|
|
616
|
+
'.gdc/config.yaml',
|
|
419
617
|
].filter(rel => fs.existsSync(path.join(basePath, rel)));
|
|
618
|
+
const gdc = await analyzeGdcContext(basePath, intake);
|
|
420
619
|
return {
|
|
421
620
|
scannedFiles: workspaceFiles.length,
|
|
422
621
|
codeFiles: codeFiles.length,
|
|
@@ -429,9 +628,10 @@ function analyzeWorkspaceContext(basePath, intake) {
|
|
|
429
628
|
reproductionFlow,
|
|
430
629
|
beforeContext,
|
|
431
630
|
afterContext,
|
|
631
|
+
gdc,
|
|
432
632
|
};
|
|
433
633
|
}
|
|
434
|
-
export function buildResearchReport(options) {
|
|
634
|
+
export async function buildResearchReport(options) {
|
|
435
635
|
const basePath = options.basePath || process.cwd();
|
|
436
636
|
const now = new Date().toISOString();
|
|
437
637
|
const featureLines = uniq(top(options.intake.features, 12));
|
|
@@ -456,7 +656,7 @@ export function buildResearchReport(options) {
|
|
|
456
656
|
const envIssues = top(options.intake.environment?.issues || [], 10).map(issue => {
|
|
457
657
|
return `${issue.severity.toUpperCase()} - ${issue.title}: ${issue.prevention}`;
|
|
458
658
|
});
|
|
459
|
-
const workspace = analyzeWorkspaceContext(basePath, options.intake);
|
|
659
|
+
const workspace = await analyzeWorkspaceContext(basePath, options.intake);
|
|
460
660
|
const workspaceScope = [
|
|
461
661
|
`Scanned files: ${workspace.scannedFiles} (code: ${workspace.codeFiles}, tests: ${workspace.testFiles})`,
|
|
462
662
|
`Research scope: current workspace only (\`${toRelativePath(basePath, basePath)}\`)`,
|
|
@@ -472,6 +672,21 @@ export function buildResearchReport(options) {
|
|
|
472
672
|
const snippet = candidate.snippet ? ` | ${candidate.snippet}` : '';
|
|
473
673
|
return `\`${rel}\` (${featurePart})${snippet}`;
|
|
474
674
|
});
|
|
675
|
+
const gdcNodeCoverage = workspace.gdc.detected
|
|
676
|
+
? [
|
|
677
|
+
`Detected: yes`,
|
|
678
|
+
`Gate enabled: ${workspace.gdc.gateEnabled ? 'yes' : 'no'}`,
|
|
679
|
+
`Node specs: ${workspace.gdc.nodeSpecFiles}`,
|
|
680
|
+
`Graph DB present: ${workspace.gdc.hasGraphDb ? 'yes' : 'no'}`,
|
|
681
|
+
...(workspace.gdc.configPath ? [`Config: \`${workspace.gdc.configPath}\``] : ['Config: (missing)']),
|
|
682
|
+
...(workspace.gdc.sampleNodes.length > 0
|
|
683
|
+
? [`Sample nodes: ${workspace.gdc.sampleNodes.map(node => `\`${node}\``).join(', ')}`]
|
|
684
|
+
: ['Sample nodes: (none)']),
|
|
685
|
+
]
|
|
686
|
+
: ['Detected: no', 'No `.gdc` metadata found in workspace.'];
|
|
687
|
+
const gdcMachineSignals = workspace.gdc.machineSignals.length > 0
|
|
688
|
+
? workspace.gdc.machineSignals
|
|
689
|
+
: ['No GDC machine-command data collected.'];
|
|
475
690
|
const lines = [];
|
|
476
691
|
lines.push('# Weave Research Report');
|
|
477
692
|
lines.push('');
|
|
@@ -500,6 +715,11 @@ export function buildResearchReport(options) {
|
|
|
500
715
|
formatList(lines, 'Problem Reproduction Flow', workspace.reproductionFlow);
|
|
501
716
|
formatList(lines, 'Before Context (Current State)', workspace.beforeContext);
|
|
502
717
|
formatList(lines, 'After Context (Target Intent)', workspace.afterContext);
|
|
718
|
+
formatList(lines, 'GDC Node Coverage', gdcNodeCoverage);
|
|
719
|
+
formatList(lines, 'GDC Machine Signals', gdcMachineSignals);
|
|
720
|
+
formatList(lines, 'Dependency Blast Radius', workspace.gdc.dependencyBlastRadius);
|
|
721
|
+
formatList(lines, 'Existing Spec vs Implementation Drift', workspace.gdc.driftSignals);
|
|
722
|
+
formatList(lines, 'Candidate Reuse Nodes', workspace.gdc.candidateReuseNodes);
|
|
503
723
|
lines.push('## Suggested Next Steps');
|
|
504
724
|
lines.push('');
|
|
505
725
|
lines.push('1. Preserve reuse candidates first; avoid implementing duplicates unless behavior diverges.');
|
|
@@ -515,7 +735,7 @@ export async function writeResearchReport(options) {
|
|
|
515
735
|
const outputPath = options.outputPath
|
|
516
736
|
? (path.isAbsolute(options.outputPath) ? options.outputPath : path.join(basePath, options.outputPath))
|
|
517
737
|
: path.join(tasksDir, 'research.md');
|
|
518
|
-
const report = buildResearchReport(options);
|
|
738
|
+
const report = await buildResearchReport(options);
|
|
519
739
|
fs.writeFileSync(outputPath, `${report}\n`, 'utf-8');
|
|
520
740
|
const rel = toRelativePath(basePath, outputPath);
|
|
521
741
|
const summary = [
|