musubix3 0.1.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/.github/plugin/marketplace.json +16 -0
- package/.github/skills/sdd-change/SKILL.md +78 -0
- package/.github/skills/sdd-design/SKILL.md +26 -0
- package/.github/skills/sdd-formal-codegraph/SKILL.md +53 -0
- package/.github/skills/sdd-implementation/SKILL.md +54 -0
- package/.github/skills/sdd-knowledge/SKILL.md +24 -0
- package/.github/skills/sdd-quality/SKILL.md +69 -0
- package/.github/skills/sdd-requirements/SKILL.md +42 -0
- package/.github/skills/sdd-traceability/SKILL.md +28 -0
- package/CHANGELOG.md +152 -0
- package/LICENSE +21 -0
- package/README-ja.md +573 -0
- package/README.md +639 -0
- package/assets/ADR-0001.md +15 -0
- package/assets/constitution.md +17 -0
- package/assets/design.md +13 -0
- package/assets/requirements.md +15 -0
- package/dist/packages/analysis/src/adapters.d.ts +12 -0
- package/dist/packages/analysis/src/adapters.js +167 -0
- package/dist/packages/analysis/src/adapters.js.map +1 -0
- package/dist/packages/analysis/src/attestation.d.ts +50 -0
- package/dist/packages/analysis/src/attestation.js +474 -0
- package/dist/packages/analysis/src/attestation.js.map +1 -0
- package/dist/packages/analysis/src/change.d.ts +53 -0
- package/dist/packages/analysis/src/change.js +337 -0
- package/dist/packages/analysis/src/change.js.map +1 -0
- package/dist/packages/analysis/src/config.d.ts +104 -0
- package/dist/packages/analysis/src/config.js +456 -0
- package/dist/packages/analysis/src/config.js.map +1 -0
- package/dist/packages/analysis/src/files.d.ts +13 -0
- package/dist/packages/analysis/src/files.js +103 -0
- package/dist/packages/analysis/src/files.js.map +1 -0
- package/dist/packages/analysis/src/formal.d.ts +82 -0
- package/dist/packages/analysis/src/formal.js +579 -0
- package/dist/packages/analysis/src/formal.js.map +1 -0
- package/dist/packages/analysis/src/gate.d.ts +56 -0
- package/dist/packages/analysis/src/gate.js +484 -0
- package/dist/packages/analysis/src/gate.js.map +1 -0
- package/dist/packages/analysis/src/graph.d.ts +52 -0
- package/dist/packages/analysis/src/graph.js +737 -0
- package/dist/packages/analysis/src/graph.js.map +1 -0
- package/dist/packages/analysis/src/index.d.ts +17 -0
- package/dist/packages/analysis/src/index.js +18 -0
- package/dist/packages/analysis/src/index.js.map +1 -0
- package/dist/packages/analysis/src/knowledge.d.ts +29 -0
- package/dist/packages/analysis/src/knowledge.js +95 -0
- package/dist/packages/analysis/src/knowledge.js.map +1 -0
- package/dist/packages/analysis/src/model-correspondence.d.ts +45 -0
- package/dist/packages/analysis/src/model-correspondence.js +310 -0
- package/dist/packages/analysis/src/model-correspondence.js.map +1 -0
- package/dist/packages/analysis/src/mutation.d.ts +54 -0
- package/dist/packages/analysis/src/mutation.js +299 -0
- package/dist/packages/analysis/src/mutation.js.map +1 -0
- package/dist/packages/analysis/src/order.d.ts +23 -0
- package/dist/packages/analysis/src/order.js +89 -0
- package/dist/packages/analysis/src/order.js.map +1 -0
- package/dist/packages/analysis/src/performance.d.ts +65 -0
- package/dist/packages/analysis/src/performance.js +319 -0
- package/dist/packages/analysis/src/performance.js.map +1 -0
- package/dist/packages/analysis/src/process.d.ts +14 -0
- package/dist/packages/analysis/src/process.js +79 -0
- package/dist/packages/analysis/src/process.js.map +1 -0
- package/dist/packages/analysis/src/tdd.d.ts +65 -0
- package/dist/packages/analysis/src/tdd.js +353 -0
- package/dist/packages/analysis/src/tdd.js.map +1 -0
- package/dist/packages/analysis/src/trace.d.ts +45 -0
- package/dist/packages/analysis/src/trace.js +242 -0
- package/dist/packages/analysis/src/trace.js.map +1 -0
- package/dist/packages/analysis/src/workflow.d.ts +59 -0
- package/dist/packages/analysis/src/workflow.js +405 -0
- package/dist/packages/analysis/src/workflow.js.map +1 -0
- package/dist/packages/cli/src/install.d.ts +15 -0
- package/dist/packages/cli/src/install.js +71 -0
- package/dist/packages/cli/src/install.js.map +1 -0
- package/dist/packages/cli/src/main.d.ts +3 -0
- package/dist/packages/cli/src/main.js +364 -0
- package/dist/packages/cli/src/main.js.map +1 -0
- package/dist/packages/domain/src/constitution.d.ts +3 -0
- package/dist/packages/domain/src/constitution.js +46 -0
- package/dist/packages/domain/src/constitution.js.map +1 -0
- package/dist/packages/domain/src/design.d.ts +8 -0
- package/dist/packages/domain/src/design.js +59 -0
- package/dist/packages/domain/src/design.js.map +1 -0
- package/dist/packages/domain/src/index.d.ts +5 -0
- package/dist/packages/domain/src/index.js +6 -0
- package/dist/packages/domain/src/index.js.map +1 -0
- package/dist/packages/domain/src/markdown.d.ts +16 -0
- package/dist/packages/domain/src/markdown.js +72 -0
- package/dist/packages/domain/src/markdown.js.map +1 -0
- package/dist/packages/domain/src/requirements.d.ts +3 -0
- package/dist/packages/domain/src/requirements.js +195 -0
- package/dist/packages/domain/src/requirements.js.map +1 -0
- package/dist/packages/domain/src/types.d.ts +100 -0
- package/dist/packages/domain/src/types.js +14 -0
- package/dist/packages/domain/src/types.js.map +1 -0
- package/package.json +59 -0
- package/plugin.json +9 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
import { error } from '../../domain/src/index.js';
|
|
4
|
+
import { digest, exists, readText, within, writeJson } from './files.js';
|
|
5
|
+
export const workflowVerificationLimits = {
|
|
6
|
+
maxBytes: 100_000_000,
|
|
7
|
+
maxLineBytes: 1_000_000,
|
|
8
|
+
maxEvents: 1_000_000,
|
|
9
|
+
};
|
|
10
|
+
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
|
+
const starts = new Set(['tool.execution_start', 'tool.execution_started', 'tool_use']);
|
|
12
|
+
const completes = new Set(['tool.execution_complete', 'tool.execution_completed', 'tool_result']);
|
|
13
|
+
function timestampMs(value) {
|
|
14
|
+
const parsed = Date.parse(value);
|
|
15
|
+
return Number.isNaN(parsed) ? Number.POSITIVE_INFINITY : parsed;
|
|
16
|
+
}
|
|
17
|
+
function canonical(value) {
|
|
18
|
+
if (Array.isArray(value))
|
|
19
|
+
return `[${value.map(canonical).join(',')}]`;
|
|
20
|
+
if (value && typeof value === 'object') {
|
|
21
|
+
return `{${Object.entries(value)
|
|
22
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
23
|
+
.map(([key, nested]) => `${JSON.stringify(key)}:${canonical(nested)}`).join(',')}}`;
|
|
24
|
+
}
|
|
25
|
+
return JSON.stringify(value);
|
|
26
|
+
}
|
|
27
|
+
function eventsSha256(events) {
|
|
28
|
+
return digest(JSON.stringify(events));
|
|
29
|
+
}
|
|
30
|
+
export function workflowEvidenceHead(workflow) {
|
|
31
|
+
const verification = workflow?.verification;
|
|
32
|
+
if (!verification)
|
|
33
|
+
return null;
|
|
34
|
+
if (!verification.mode && !verification.transcriptSha256 && !verification.sessionId) {
|
|
35
|
+
return digest(`${verification.eventsSha256}:${verification.sourceSha256}`);
|
|
36
|
+
}
|
|
37
|
+
return digest(canonical({
|
|
38
|
+
eventsSha256: verification.eventsSha256,
|
|
39
|
+
sourceSha256: verification.sourceSha256,
|
|
40
|
+
transcriptSha256: verification.transcriptSha256 ?? null,
|
|
41
|
+
mode: verification.mode ?? 'compatible',
|
|
42
|
+
sessionId: verification.sessionId ?? null,
|
|
43
|
+
exitCode: verification.exitCode ?? null,
|
|
44
|
+
terminalAt: verification.terminalAt ?? null,
|
|
45
|
+
eventCount: verification.eventCount ?? null,
|
|
46
|
+
invocations: verification.invocations,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
export async function loadWorkflow(root) {
|
|
50
|
+
const path = '.musubix/evidence/workflow.json';
|
|
51
|
+
if (!await exists(within(root, path)))
|
|
52
|
+
return null;
|
|
53
|
+
const value = JSON.parse(await readText(root, path));
|
|
54
|
+
if (value.schemaVersion !== 1 || !Array.isArray(value.events))
|
|
55
|
+
throw new Error('Invalid workflow evidence.');
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
export async function recordWorkflow(root, event) {
|
|
59
|
+
if (!/^[a-z0-9-]+$/.test(event.skill))
|
|
60
|
+
throw new Error('Workflow skill must be a lowercase kebab-case identifier.');
|
|
61
|
+
if (!/^[a-z0-9-]+$/.test(event.phase))
|
|
62
|
+
throw new Error('Workflow phase must be a lowercase kebab-case identifier.');
|
|
63
|
+
const current = await loadWorkflow(root) ?? { schemaVersion: 1, events: [] };
|
|
64
|
+
delete current.verification;
|
|
65
|
+
current.events.push({
|
|
66
|
+
skill: event.skill,
|
|
67
|
+
version: '0.1.0',
|
|
68
|
+
provenance: 'self-reported',
|
|
69
|
+
phase: event.phase,
|
|
70
|
+
status: event.status,
|
|
71
|
+
...(event.reason ? { reason: event.reason } : {}),
|
|
72
|
+
...(event.command ? { commandSha256: digest(event.command) } : {}),
|
|
73
|
+
recordedAt: new Date().toISOString(),
|
|
74
|
+
});
|
|
75
|
+
await writeJson(root, '.musubix/evidence/workflow.json', current);
|
|
76
|
+
return current;
|
|
77
|
+
}
|
|
78
|
+
export async function verifyWorkflowLog(root, logText, options = { mode: 'compatible' }) {
|
|
79
|
+
return verifyWorkflowChunks(root, (async function* () {
|
|
80
|
+
yield Buffer.from(logText);
|
|
81
|
+
})(), options);
|
|
82
|
+
}
|
|
83
|
+
export async function verifyWorkflowLogFile(root, path, options = { mode: 'compatible' }) {
|
|
84
|
+
return verifyWorkflowChunks(root, createReadStream(path), options);
|
|
85
|
+
}
|
|
86
|
+
async function verifyWorkflowChunks(root, chunks, options) {
|
|
87
|
+
const current = await loadWorkflow(root);
|
|
88
|
+
if (!current?.events.length)
|
|
89
|
+
throw new Error('No workflow declarations are available to verify.');
|
|
90
|
+
if (!['compatible', 'strict'].includes(options.mode))
|
|
91
|
+
throw new Error('Workflow verification mode must be compatible or strict.');
|
|
92
|
+
if (options.expectedSessionId && !uuid.test(options.expectedSessionId))
|
|
93
|
+
throw new Error('Expected workflow session ID must be a UUID.');
|
|
94
|
+
const maxBytes = options.maxBytes ?? workflowVerificationLimits.maxBytes;
|
|
95
|
+
const maxLineBytes = options.maxLineBytes ?? workflowVerificationLimits.maxLineBytes;
|
|
96
|
+
const maxEvents = options.maxEvents ?? workflowVerificationLimits.maxEvents;
|
|
97
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1)
|
|
98
|
+
throw new Error('Workflow maximum byte limit must be a positive integer.');
|
|
99
|
+
if (!Number.isSafeInteger(maxLineBytes) || maxLineBytes < 1)
|
|
100
|
+
throw new Error('Workflow maximum line byte limit must be a positive integer.');
|
|
101
|
+
if (!Number.isSafeInteger(maxEvents) || maxEvents < 1)
|
|
102
|
+
throw new Error('Workflow maximum event limit must be a positive integer.');
|
|
103
|
+
const sourceHash = createHash('sha256');
|
|
104
|
+
const transcriptHash = createHash('sha256');
|
|
105
|
+
transcriptHash.update('[');
|
|
106
|
+
let totalBytes = 0;
|
|
107
|
+
let lineNumber = 1;
|
|
108
|
+
let lineParts = [];
|
|
109
|
+
let lineBytes = 0;
|
|
110
|
+
let parsedCount = 0;
|
|
111
|
+
let resultCount = 0;
|
|
112
|
+
let lastParsedWasResult = false;
|
|
113
|
+
let terminalRecord;
|
|
114
|
+
const invocationsById = new Map();
|
|
115
|
+
const completions = new Map();
|
|
116
|
+
const toolStarts = new Map();
|
|
117
|
+
const toolCompletions = new Set();
|
|
118
|
+
let lastToolTimestamp = Number.NEGATIVE_INFINITY;
|
|
119
|
+
const processLine = (bytes, line) => {
|
|
120
|
+
if (bytes.at(-1) === 0x0d)
|
|
121
|
+
bytes = bytes.subarray(0, -1);
|
|
122
|
+
let text;
|
|
123
|
+
try {
|
|
124
|
+
text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
throw new Error(`Workflow transcript line ${line} must contain valid UTF-8.`);
|
|
128
|
+
}
|
|
129
|
+
const lineText = text;
|
|
130
|
+
if (!lineText.trim())
|
|
131
|
+
return;
|
|
132
|
+
let event;
|
|
133
|
+
try {
|
|
134
|
+
event = JSON.parse(lineText);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
if (options.mode === 'strict') {
|
|
138
|
+
throw new Error(`Workflow transcript line ${line} must contain valid JSON.`);
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!event || typeof event !== 'object' || Array.isArray(event)) {
|
|
143
|
+
if (options.mode === 'strict')
|
|
144
|
+
throw new Error(`Workflow transcript line ${line} must be a JSON object.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
parsedCount += 1;
|
|
148
|
+
if (parsedCount > maxEvents) {
|
|
149
|
+
throw new Error(`Workflow transcript exceeds the maximum event count of ${maxEvents}.`);
|
|
150
|
+
}
|
|
151
|
+
const record = event;
|
|
152
|
+
transcriptHash.update(parsedCount === 1 ? canonical(record) : `,${canonical(record)}`);
|
|
153
|
+
lastParsedWasResult = record.type === 'result';
|
|
154
|
+
if (lastParsedWasResult) {
|
|
155
|
+
resultCount += 1;
|
|
156
|
+
terminalRecord = record;
|
|
157
|
+
}
|
|
158
|
+
const data = record.data && typeof record.data === 'object'
|
|
159
|
+
? record.data
|
|
160
|
+
: record;
|
|
161
|
+
const type = String(record.type ?? '');
|
|
162
|
+
const timestampValue = record.timestamp ?? data.timestamp;
|
|
163
|
+
const timestamp = typeof timestampValue === 'string' ? timestampValue : '';
|
|
164
|
+
const time = Date.parse(timestamp);
|
|
165
|
+
if (options.mode === 'strict') {
|
|
166
|
+
if (!type)
|
|
167
|
+
throw new Error(`Workflow transcript line ${line} has no event type.`);
|
|
168
|
+
if (!timestamp || Number.isNaN(time))
|
|
169
|
+
throw new Error(`Workflow transcript line ${line} has an invalid timestamp.`);
|
|
170
|
+
}
|
|
171
|
+
const toolCallId = data.toolCallId ?? data.callId ?? record.toolCallId;
|
|
172
|
+
if (starts.has(type)) {
|
|
173
|
+
if (typeof toolCallId !== 'string' || !toolCallId || !timestamp) {
|
|
174
|
+
if (options.mode === 'strict')
|
|
175
|
+
throw new Error(`Tool start on line ${line} requires a toolCallId and timestamp.`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (options.mode === 'strict' && toolStarts.has(toolCallId)) {
|
|
179
|
+
throw new Error(`Tool call ${toolCallId} has more than one start event.`);
|
|
180
|
+
}
|
|
181
|
+
lastToolTimestamp = Math.max(lastToolTimestamp, time);
|
|
182
|
+
toolStarts.set(toolCallId, { timestamp, index: parsedCount - 1 });
|
|
183
|
+
const toolName = data.toolName ?? data.name ?? record.toolName;
|
|
184
|
+
let args = {};
|
|
185
|
+
if (data.arguments && typeof data.arguments === 'object')
|
|
186
|
+
args = data.arguments;
|
|
187
|
+
else if (typeof data.arguments === 'string') {
|
|
188
|
+
try {
|
|
189
|
+
args = JSON.parse(data.arguments);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
args = {};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (data.input && typeof data.input === 'object')
|
|
196
|
+
args = data.input;
|
|
197
|
+
if (toolName === 'skill' && typeof args.skill === 'string' && !invocationsById.has(toolCallId)) {
|
|
198
|
+
invocationsById.set(toolCallId, { skill: args.skill, toolCallId, invokedAt: timestamp });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (completes.has(type)) {
|
|
202
|
+
if (typeof toolCallId !== 'string' || !toolCallId || !timestamp) {
|
|
203
|
+
if (options.mode === 'strict')
|
|
204
|
+
throw new Error(`Tool completion on line ${line} requires a toolCallId and timestamp.`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const start = toolStarts.get(toolCallId);
|
|
208
|
+
if (options.mode === 'strict') {
|
|
209
|
+
if (!start)
|
|
210
|
+
throw new Error(`Tool call ${toolCallId} completed without a matching start.`);
|
|
211
|
+
if (toolCompletions.has(toolCallId))
|
|
212
|
+
throw new Error(`Tool call ${toolCallId} has more than one completion event.`);
|
|
213
|
+
if (start.index >= parsedCount - 1 || Date.parse(start.timestamp) > time) {
|
|
214
|
+
throw new Error(`Tool call ${toolCallId} violates event timestamp order.`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
lastToolTimestamp = Math.max(lastToolTimestamp, time);
|
|
218
|
+
toolCompletions.add(toolCallId);
|
|
219
|
+
const success = data.success ?? record.success;
|
|
220
|
+
if (options.mode === 'strict' && typeof success !== 'boolean') {
|
|
221
|
+
throw new Error(`Tool call ${toolCallId} completion must declare boolean success.`);
|
|
222
|
+
}
|
|
223
|
+
completions.set(toolCallId, { completedAt: timestamp, status: success === false ? 'failed' : 'completed' });
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
for await (const value of chunks) {
|
|
227
|
+
const chunk = Buffer.from(value);
|
|
228
|
+
totalBytes += chunk.byteLength;
|
|
229
|
+
if (totalBytes > maxBytes) {
|
|
230
|
+
throw new Error(`Workflow transcript exceeds the maximum total size of ${maxBytes} bytes.`);
|
|
231
|
+
}
|
|
232
|
+
sourceHash.update(chunk);
|
|
233
|
+
let start = 0;
|
|
234
|
+
for (let index = chunk.indexOf(0x0a); index !== -1; index = chunk.indexOf(0x0a, start)) {
|
|
235
|
+
const part = chunk.subarray(start, index);
|
|
236
|
+
lineBytes += part.byteLength;
|
|
237
|
+
if (lineBytes > maxLineBytes) {
|
|
238
|
+
throw new Error(`Workflow transcript line ${lineNumber} exceeds the maximum size of ${maxLineBytes} bytes.`);
|
|
239
|
+
}
|
|
240
|
+
if (part.byteLength)
|
|
241
|
+
lineParts.push(part);
|
|
242
|
+
processLine(Buffer.concat(lineParts, lineBytes), lineNumber);
|
|
243
|
+
lineNumber += 1;
|
|
244
|
+
lineParts = [];
|
|
245
|
+
lineBytes = 0;
|
|
246
|
+
start = index + 1;
|
|
247
|
+
}
|
|
248
|
+
const remainder = chunk.subarray(start);
|
|
249
|
+
lineBytes += remainder.byteLength;
|
|
250
|
+
if (lineBytes > maxLineBytes) {
|
|
251
|
+
throw new Error(`Workflow transcript line ${lineNumber} exceeds the maximum size of ${maxLineBytes} bytes.`);
|
|
252
|
+
}
|
|
253
|
+
if (remainder.byteLength)
|
|
254
|
+
lineParts.push(remainder);
|
|
255
|
+
}
|
|
256
|
+
processLine(Buffer.concat(lineParts, lineBytes), lineNumber);
|
|
257
|
+
transcriptHash.update(']');
|
|
258
|
+
if (options.mode === 'strict' && !parsedCount)
|
|
259
|
+
throw new Error('Strict workflow verification requires a complete Copilot JSONL transcript.');
|
|
260
|
+
let terminal;
|
|
261
|
+
if (options.mode === 'strict') {
|
|
262
|
+
if (resultCount !== 1)
|
|
263
|
+
throw new Error('Strict workflow verification requires exactly one terminal result event.');
|
|
264
|
+
if (!lastParsedWasResult)
|
|
265
|
+
throw new Error('The terminal result event must be the final JSONL event.');
|
|
266
|
+
const timestamp = terminalRecord.timestamp;
|
|
267
|
+
const sessionId = terminalRecord.sessionId;
|
|
268
|
+
const exitCode = terminalRecord.exitCode;
|
|
269
|
+
if (typeof timestamp !== 'string' || Number.isNaN(Date.parse(timestamp)) || Date.parse(timestamp) < lastToolTimestamp) {
|
|
270
|
+
throw new Error('The terminal result event violates event timestamp order.');
|
|
271
|
+
}
|
|
272
|
+
if (typeof sessionId !== 'string' || !uuid.test(sessionId)) {
|
|
273
|
+
throw new Error('The terminal result event must declare a UUID sessionId.');
|
|
274
|
+
}
|
|
275
|
+
if (exitCode !== 0)
|
|
276
|
+
throw new Error('The terminal result event must declare exitCode 0.');
|
|
277
|
+
if (options.expectedSessionId && sessionId.toLowerCase() !== options.expectedSessionId.toLowerCase()) {
|
|
278
|
+
throw new Error(`Transcript session ID ${sessionId} does not match expected session ID ${options.expectedSessionId}.`);
|
|
279
|
+
}
|
|
280
|
+
const now = (options.now ?? (() => new Date()))().getTime();
|
|
281
|
+
const terminalTime = Date.parse(timestamp);
|
|
282
|
+
if (options.maxFutureSkewSeconds !== undefined
|
|
283
|
+
&& terminalTime > now + options.maxFutureSkewSeconds * 1000) {
|
|
284
|
+
throw new Error('The terminal workflow transcript timestamp is beyond the allowed future skew.');
|
|
285
|
+
}
|
|
286
|
+
if (options.maxAgeSeconds !== undefined && now - terminalTime > options.maxAgeSeconds * 1000) {
|
|
287
|
+
throw new Error('The terminal workflow transcript is older than the configured maximum age.');
|
|
288
|
+
}
|
|
289
|
+
const incomplete = [...toolStarts.keys()].find((toolCallId) => !toolCompletions.has(toolCallId));
|
|
290
|
+
if (incomplete)
|
|
291
|
+
throw new Error(`Tool call ${incomplete} has a start event without a completion.`);
|
|
292
|
+
terminal = { timestamp, sessionId, exitCode };
|
|
293
|
+
}
|
|
294
|
+
const invocations = [...invocationsById.values()]
|
|
295
|
+
.map((start) => ({ ...start, ...(completions.get(start.toolCallId) ?? { status: 'incomplete' }) }))
|
|
296
|
+
.sort((a, b) => timestampMs(a.invokedAt) - timestampMs(b.invokedAt) || a.toolCallId.localeCompare(b.toolCallId));
|
|
297
|
+
if (!invocations.length)
|
|
298
|
+
throw new Error('No Copilot Skill invocation events were found in the log.');
|
|
299
|
+
current.verification = {
|
|
300
|
+
mode: options.mode,
|
|
301
|
+
sourceSha256: sourceHash.digest('hex'),
|
|
302
|
+
...(options.mode === 'strict' ? {
|
|
303
|
+
transcriptSha256: transcriptHash.digest('hex'),
|
|
304
|
+
sessionId: terminal.sessionId,
|
|
305
|
+
exitCode: terminal.exitCode,
|
|
306
|
+
terminalAt: terminal.timestamp,
|
|
307
|
+
eventCount: parsedCount,
|
|
308
|
+
} : {}),
|
|
309
|
+
eventsSha256: eventsSha256(current.events),
|
|
310
|
+
verifiedAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
311
|
+
invocations,
|
|
312
|
+
};
|
|
313
|
+
await writeJson(root, '.musubix/evidence/workflow.json', current);
|
|
314
|
+
return current;
|
|
315
|
+
}
|
|
316
|
+
export async function validateWorkflow(root, options = { mode: 'compatible' }) {
|
|
317
|
+
const workflow = await loadWorkflow(root);
|
|
318
|
+
if (!workflow?.events.length)
|
|
319
|
+
return { present: false, verified: false, events: 0, skills: 0, diagnostics: [] };
|
|
320
|
+
const diagnostics = [];
|
|
321
|
+
if (!workflow.verification) {
|
|
322
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_UNVERIFIED', 'Workflow declarations have not been reconciled with a Copilot session log.'));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
if (options.mode === 'strict') {
|
|
326
|
+
const verification = workflow.verification;
|
|
327
|
+
if (verification.mode !== 'strict'
|
|
328
|
+
|| !verification.transcriptSha256 || !/^[a-f0-9]{64}$/i.test(verification.transcriptSha256)
|
|
329
|
+
|| !verification.sessionId || !uuid.test(verification.sessionId)
|
|
330
|
+
|| verification.exitCode !== 0
|
|
331
|
+
|| !verification.terminalAt || Number.isNaN(Date.parse(verification.terminalAt))
|
|
332
|
+
|| !Number.isInteger(verification.eventCount) || verification.eventCount < 1) {
|
|
333
|
+
diagnostics.push(error('WORKFLOW_TRANSCRIPT_INCOMPLETE', 'Strict workflow verification requires complete terminal transcript evidence.'));
|
|
334
|
+
}
|
|
335
|
+
else if (options.expectedSessionId
|
|
336
|
+
&& verification.sessionId.toLowerCase() !== options.expectedSessionId.toLowerCase()) {
|
|
337
|
+
diagnostics.push(error('WORKFLOW_SESSION_MISMATCH', `Verified session ${verification.sessionId} does not match configured session ${options.expectedSessionId}.`));
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
const now = (options.now ?? (() => new Date()))().getTime();
|
|
341
|
+
const terminalTime = Date.parse(verification.terminalAt);
|
|
342
|
+
if (options.maxFutureSkewSeconds !== undefined
|
|
343
|
+
&& terminalTime > now + options.maxFutureSkewSeconds * 1000) {
|
|
344
|
+
diagnostics.push(error('WORKFLOW_TRANSCRIPT_FUTURE', 'Verified workflow transcript is beyond the configured future clock skew.'));
|
|
345
|
+
}
|
|
346
|
+
if (options.maxAgeSeconds !== undefined && now - terminalTime > options.maxAgeSeconds * 1000) {
|
|
347
|
+
diagnostics.push(error('WORKFLOW_TRANSCRIPT_EXPIRED', 'Verified workflow transcript is older than the configured maximum age.'));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (workflow.verification.eventsSha256 !== eventsSha256(workflow.events)) {
|
|
352
|
+
diagnostics.push(error('WORKFLOW_VERIFICATION_STALE', 'Workflow declarations changed after Skill invocation verification.'));
|
|
353
|
+
}
|
|
354
|
+
const duplicateCalls = workflow.verification.invocations
|
|
355
|
+
.filter((invocation, index, all) => all.findIndex((candidate) => candidate.toolCallId === invocation.toolCallId) !== index);
|
|
356
|
+
for (const duplicate of duplicateCalls) {
|
|
357
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_REUSED', `Tool call ${duplicate.toolCallId} appears more than once in invocation evidence.`));
|
|
358
|
+
}
|
|
359
|
+
const used = new Set();
|
|
360
|
+
let previousIndex = -1;
|
|
361
|
+
for (const event of workflow.events.filter((candidate) => candidate.status === 'completed')) {
|
|
362
|
+
const recordedAt = timestampMs(event.recordedAt);
|
|
363
|
+
const eligible = workflow.verification.invocations
|
|
364
|
+
.map((invocation, index) => ({ invocation, index }))
|
|
365
|
+
.filter(({ invocation }) => invocation.skill === event.skill && timestampMs(invocation.invokedAt) <= recordedAt);
|
|
366
|
+
const match = eligible.find(({ invocation, index }) => !used.has(invocation.toolCallId)
|
|
367
|
+
&& index > previousIndex
|
|
368
|
+
&& invocation.status === 'completed'
|
|
369
|
+
&& !!invocation.completedAt
|
|
370
|
+
&& timestampMs(invocation.completedAt) <= recordedAt);
|
|
371
|
+
if (!match) {
|
|
372
|
+
if (eligible.some(({ invocation }) => invocation.status === 'incomplete')) {
|
|
373
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_INCOMPLETE', `${event.skill}:${event.phase} only has an incomplete Skill invocation.`));
|
|
374
|
+
}
|
|
375
|
+
else if (eligible.some(({ invocation }) => invocation.status === 'failed')) {
|
|
376
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_FAILED', `${event.skill}:${event.phase} only has a failed Skill invocation.`));
|
|
377
|
+
}
|
|
378
|
+
else if (eligible.some(({ invocation }) => used.has(invocation.toolCallId))) {
|
|
379
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_REUSED', `${event.skill}:${event.phase} would reuse an invocation already bound to another declaration.`));
|
|
380
|
+
}
|
|
381
|
+
else if (eligible.some(({ index }) => index <= previousIndex)) {
|
|
382
|
+
diagnostics.push(error('WORKFLOW_INVOCATION_ORDER', `${event.skill}:${event.phase} would bind Skill invocations out of declaration order.`));
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
diagnostics.push(error('WORKFLOW_SKILL_NOT_INVOKED', `${event.skill}:${event.phase} has no matching earlier completed Copilot Skill invocation.`));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
used.add(match.invocation.toolCallId);
|
|
390
|
+
previousIndex = match.index;
|
|
391
|
+
}
|
|
392
|
+
if (!match) {
|
|
393
|
+
diagnostics.push(error('WORKFLOW_BINDING_MISSING', `${event.skill}:${event.phase} is not one-to-one bound to completed invocation evidence.`));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
present: true,
|
|
399
|
+
verified: !diagnostics.length,
|
|
400
|
+
events: workflow.events.length,
|
|
401
|
+
skills: new Set(workflow.events.map((event) => event.skill)).size,
|
|
402
|
+
diagnostics,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../../../packages/analysis/src/workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Runner } from '../../analysis/src/index.js';
|
|
2
|
+
export declare const skillNames: readonly ["sdd-change", "sdd-requirements", "sdd-design", "sdd-implementation", "sdd-traceability", "sdd-quality", "sdd-knowledge", "sdd-formal-codegraph"];
|
|
3
|
+
export interface InstallAction {
|
|
4
|
+
path: string;
|
|
5
|
+
action: 'create' | 'replace' | 'preserve' | 'unchanged' | 'merge';
|
|
6
|
+
}
|
|
7
|
+
export declare function install(root: string, packageRoot: string, options?: {
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
force?: boolean;
|
|
10
|
+
feature?: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
dryRun: boolean;
|
|
13
|
+
actions: InstallAction[];
|
|
14
|
+
}>;
|
|
15
|
+
export declare function pluginInstall(packageRoot: string, runner?: Runner): Promise<Awaited<ReturnType<Runner>>>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readdir, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { buildTrace, defaultConfig, defaultPolicyBaseline, exists, readText, safePath, writeJson, writeText, runProcess } from '../../analysis/src/index.js';
|
|
4
|
+
export const skillNames = ['sdd-change', 'sdd-requirements', 'sdd-design', 'sdd-implementation', 'sdd-traceability', 'sdd-quality', 'sdd-knowledge', 'sdd-formal-codegraph'];
|
|
5
|
+
export async function install(root, packageRoot, options = {}) {
|
|
6
|
+
root = resolve(root);
|
|
7
|
+
const feature = options.feature ?? 'example';
|
|
8
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(feature))
|
|
9
|
+
throw new Error('Feature slug must be lowercase kebab-case.');
|
|
10
|
+
const planned = new Map();
|
|
11
|
+
for (const name of skillNames) {
|
|
12
|
+
const directory = `.github/skills/${name}`;
|
|
13
|
+
const entries = await readdir(resolve(packageRoot, directory), { withFileTypes: true });
|
|
14
|
+
// Bundled skills intentionally contain no executable scripts.
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
if (!entry.isFile())
|
|
17
|
+
throw new Error(`Unexpected skill asset: ${directory}/${entry.name}`);
|
|
18
|
+
planned.set(`${directory}/${entry.name}`, await readText(packageRoot, `${directory}/${entry.name}`));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
planned.set('.musubix/config.json', `${JSON.stringify(defaultConfig, null, 2)}\n`);
|
|
22
|
+
planned.set('.musubix/policy-baseline.json', `${JSON.stringify(defaultPolicyBaseline, null, 2)}\n`);
|
|
23
|
+
planned.set('.musubix/constitution.md', await readText(packageRoot, 'assets/constitution.md'));
|
|
24
|
+
const featureAsset = async (name) => (await readText(packageRoot, `assets/${name}.md`))
|
|
25
|
+
.replace(/feature: example/g, `feature: ${feature}`)
|
|
26
|
+
.replace(/(REQ|DES)-EXAMPLE-/g, `$1-${feature.toUpperCase()}-`);
|
|
27
|
+
planned.set(`.musubix/features/${feature}/requirements.md`, await featureAsset('requirements'));
|
|
28
|
+
planned.set(`.musubix/features/${feature}/design.md`, await featureAsset('design'));
|
|
29
|
+
planned.set('.musubix/decisions/ADR-0001.md', await readText(packageRoot, 'assets/ADR-0001.md'));
|
|
30
|
+
planned.set('.musubix/evidence/quality.json', `${JSON.stringify({ schemaVersion: 1, status: 'skipped', generatedAt: null, checks: [], reason: 'No checks have run. Configure commands and run musubix3 gate.' }, null, 2)}\n`);
|
|
31
|
+
const actions = [];
|
|
32
|
+
const writes = new Map();
|
|
33
|
+
for (const [path, content] of planned) {
|
|
34
|
+
const absolute = await safePath(root, path);
|
|
35
|
+
const present = await exists(absolute);
|
|
36
|
+
const equal = present && await readText(root, path) === content;
|
|
37
|
+
const action = !present ? 'create' : equal ? 'unchanged' : options.force ? 'replace' : 'preserve';
|
|
38
|
+
actions.push({ path, action });
|
|
39
|
+
if (action === 'create' || action === 'replace')
|
|
40
|
+
writes.set(path, content);
|
|
41
|
+
}
|
|
42
|
+
const ignorePath = await safePath(root, '.gitignore');
|
|
43
|
+
const oldIgnore = await exists(ignorePath) ? await readText(root, '.gitignore') : '';
|
|
44
|
+
if (!oldIgnore.split(/\r?\n/).some((line) => line.trim() === '/.musubix/cache/')) {
|
|
45
|
+
writes.set('.gitignore', `${oldIgnore}${oldIgnore && !oldIgnore.endsWith('\n') ? '\n' : ''}\n# musubix3 generated caches\n/.musubix/cache/\n`);
|
|
46
|
+
actions.push({ path: '.gitignore', action: oldIgnore ? 'merge' : 'create' });
|
|
47
|
+
}
|
|
48
|
+
else
|
|
49
|
+
actions.push({ path: '.gitignore', action: 'unchanged' });
|
|
50
|
+
const tracePath = `.musubix/features/${feature}/trace.json`;
|
|
51
|
+
const traceExists = await exists(await safePath(root, tracePath));
|
|
52
|
+
const generateTrace = !traceExists || options.force;
|
|
53
|
+
actions.push({ path: tracePath, action: !traceExists ? 'create' : options.force ? 'replace' : 'preserve' });
|
|
54
|
+
const cachePath = await safePath(root, '.musubix/cache');
|
|
55
|
+
if (!options.dryRun) {
|
|
56
|
+
await mkdir(root, { recursive: true });
|
|
57
|
+
for (const [path, text] of writes)
|
|
58
|
+
await writeText(root, path, text);
|
|
59
|
+
await mkdir(cachePath, { recursive: true });
|
|
60
|
+
if (generateTrace) {
|
|
61
|
+
const trace = await buildTrace(root, false);
|
|
62
|
+
await writeJson(root, tracePath, trace);
|
|
63
|
+
await writeJson(root, '.musubix/cache/trace.json', trace);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { dryRun: options.dryRun ?? false, actions };
|
|
67
|
+
}
|
|
68
|
+
export async function pluginInstall(packageRoot, runner = runProcess) {
|
|
69
|
+
return runner('copilot', ['plugin', 'install', resolve(packageRoot)], { cwd: resolve(packageRoot), timeoutMs: 120_000 });
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../packages/cli/src/install.ts"],"names":[],"mappings":"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"}
|