@devtrack-solution/codesdd 1.2.3 → 1.2.4-rc3
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/.sdd/skills/curated/devtrack-api/SKILL.md +12 -5
- package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +8 -0
- package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +8 -0
- package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +8 -0
- package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +8 -0
- package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +8 -0
- package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +4 -2
- package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +10 -0
- package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +2 -2
- package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +55 -0
- package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +13 -13
- package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +2 -3
- package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +1 -1
- package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +41 -0
- package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +7 -9
- package/README.md +159 -5
- package/dist/applications/sdd/index.d.ts +16 -0
- package/dist/applications/sdd/index.js +16 -0
- package/dist/commands/config.js +171 -10
- package/dist/commands/sdd/execution.js +345 -15
- package/dist/commands/sdd/plugin.js +5 -0
- package/dist/commands/sdd/shared.d.ts +1 -0
- package/dist/commands/sdd/shared.js +10 -0
- package/dist/commands/sdd.js +38 -3
- package/dist/core/cli/command-matrix.js +9 -0
- package/dist/core/cli-command-quality.js +9 -0
- package/dist/core/completions/command-registry.js +45 -0
- package/dist/core/config-schema.d.ts +18 -1
- package/dist/core/config-schema.js +48 -5
- package/dist/core/global-config.d.ts +16 -0
- package/dist/core/sdd/agent-binding.d.ts +10 -10
- package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
- package/dist/core/sdd/agent-runtime-contract.js +200 -0
- package/dist/core/sdd/check.d.ts +2 -0
- package/dist/core/sdd/check.js +40 -2
- package/dist/core/sdd/coordination/coordination-adapters.d.ts +15 -8
- package/dist/core/sdd/coordination/coordination-adapters.js +43 -15
- package/dist/core/sdd/coordination/index.d.ts +1 -0
- package/dist/core/sdd/coordination/index.js +1 -0
- package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
- package/dist/core/sdd/coordination/redis-runtime.js +698 -0
- package/dist/core/sdd/deepagent-contracts.d.ts +98 -4
- package/dist/core/sdd/deepagent-contracts.js +62 -0
- package/dist/core/sdd/default-bootstrap-files.d.ts +2 -2
- package/dist/core/sdd/default-bootstrap-files.js +14 -8
- package/dist/core/sdd/default-skills.js +108 -4
- package/dist/core/sdd/devtrack-api-appliance.d.ts +8 -1
- package/dist/core/sdd/devtrack-api-appliance.js +46 -23
- package/dist/core/sdd/docs-sync.js +21 -15
- package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
- package/dist/core/sdd/domain/capability-diff.js +200 -0
- package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
- package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
- package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
- package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
- package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
- package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
- package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
- package/dist/core/sdd/foundation-layer-manifest.js +117 -0
- package/dist/core/sdd/intent-guard.d.ts +22 -0
- package/dist/core/sdd/intent-guard.js +67 -0
- package/dist/core/sdd/json-schema.js +9 -1
- package/dist/core/sdd/legacy-operations.js +76 -1
- package/dist/core/sdd/migrate-workspace.js +39 -0
- package/dist/core/sdd/package-security-gates.d.ts +21 -0
- package/dist/core/sdd/package-security-gates.js +119 -0
- package/dist/core/sdd/package-structure-gate.js +3 -8
- package/dist/core/sdd/parallel-feat-automation.d.ts +181 -3
- package/dist/core/sdd/parallel-feat-automation.js +212 -0
- package/dist/core/sdd/plugin-broker.d.ts +223 -4
- package/dist/core/sdd/plugin-broker.js +10 -0
- package/dist/core/sdd/plugin-cli.d.ts +30 -0
- package/dist/core/sdd/plugin-cli.js +70 -3
- package/dist/core/sdd/plugin-evidence.d.ts +73 -0
- package/dist/core/sdd/plugin-manifest.d.ts +69 -1
- package/dist/core/sdd/plugin-manifest.js +10 -0
- package/dist/core/sdd/plugin-policy-pack.d.ts +1 -1
- package/dist/core/sdd/plugin-registry.d.ts +141 -5
- package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
- package/dist/core/sdd/plugin-sdk-contract.js +268 -0
- package/dist/core/sdd/plugin-skill-binding.d.ts +1 -1
- package/dist/core/sdd/quality-validation.d.ts +84 -11
- package/dist/core/sdd/release-readiness.d.ts +19 -0
- package/dist/core/sdd/release-readiness.js +472 -0
- package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
- package/dist/core/sdd/runtime-boundary-contract.js +90 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
- package/dist/core/sdd/services/agent-run.service.d.ts +38 -6
- package/dist/core/sdd/services/agent-run.service.js +73 -1
- package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
- package/dist/core/sdd/services/capability-diff.service.js +26 -0
- package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
- package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
- package/dist/core/sdd/services/context.service.d.ts +43 -340
- package/dist/core/sdd/services/context.service.js +323 -9
- package/dist/core/sdd/services/finalize.service.d.ts +25 -0
- package/dist/core/sdd/services/finalize.service.js +178 -16
- package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
- package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
- package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
- package/dist/core/sdd/state.d.ts +1 -0
- package/dist/core/sdd/state.js +251 -29
- package/dist/core/sdd/store/sdd-stores.js +2 -2
- package/dist/core/sdd/structural-health.d.ts +13 -13
- package/dist/core/sdd/types.d.ts +27 -12
- package/dist/core/sdd/types.js +4 -0
- package/dist/core/sdd/views.js +17 -0
- package/dist/core/sdd/workspace-schemas.d.ts +387 -7
- package/dist/core/sdd/workspace-schemas.js +196 -64
- package/dist/domains/sdd/index.d.ts +6 -0
- package/dist/domains/sdd/index.js +6 -0
- package/dist/infrastructures/sdd/index.d.ts +7 -0
- package/dist/infrastructures/sdd/index.js +6 -0
- package/dist/presentations/cli/sdd/index.d.ts +3 -0
- package/dist/presentations/cli/sdd/index.js +3 -0
- package/dist/shared/sdd/index.d.ts +3 -0
- package/dist/shared/sdd/index.js +2 -0
- package/package.json +9 -6
- package/schemas/sdd/2-plan.schema.json +207 -2
- package/schemas/sdd/5-quality.schema.json +281 -25
- package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
- package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
- package/schemas/sdd/codesdd-plugin.schema.json +171 -0
- package/schemas/sdd/deepagent-run-request.schema.json +316 -0
- package/schemas/sdd/parallel-feat-automation-plan.schema.json +89 -0
- package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
- package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
- package/schemas/sdd/plugin-artifact-manifest.schema.json +109 -0
- package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
- package/schemas/sdd/plugin-evidence-manifest.schema.json +109 -0
- package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
- package/schemas/sdd/plugin-package-governance.schema.json +74 -0
- package/schemas/sdd/plugin-registry.schema.json +171 -0
- package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +109 -0
- package/schemas/sdd/quality-evidence-bundle.schema.json +109 -0
- package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
- package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
- package/schemas/sdd/workspace-catalog.schema.json +3776 -398
|
@@ -1,11 +1,48 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { existsSync, promises as fs } from "node:fs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import { parse } from "yaml";
|
|
5
|
+
import { createProjectFingerprint, ensureGlobalCacheLayout } from "../../global-config.js";
|
|
4
6
|
import { CLI_NAME } from "../../branding.js";
|
|
5
|
-
import { loadStateSnapshot } from "../state.js";
|
|
7
|
+
import { loadStateSnapshot, nowIso } from "../state.js";
|
|
6
8
|
import { bundlesForSkills, getRuntime, relProjectPath, coreDocRef, planningDocRef, featureActiveDir, activeDocNamesForLayout, unresolvedDependencies, lockConflictWithActive, featureReadiness, gateSatisfied, detectContextType, pathExists, listAdrRefs } from "../legacy-operations.js";
|
|
7
9
|
import { normalizeSddEntityRef } from "../entity-reference.js";
|
|
8
10
|
import { workspacePlanSchema, workspaceSpecSchema } from "../workspace-schemas.js";
|
|
11
|
+
export const CONTEXT_PACK_BUDGET_MODES = ['compact', 'standard', 'full'];
|
|
12
|
+
const UNLIMITED = Number.POSITIVE_INFINITY;
|
|
13
|
+
const CONTEXT_PACK_CACHE_SCHEMA_VERSION = 2;
|
|
14
|
+
const CONTEXT_PACK_BUDGET_PROFILES = {
|
|
15
|
+
compact: {
|
|
16
|
+
maxReadOrder: 8,
|
|
17
|
+
maxCoreDocs: 6,
|
|
18
|
+
maxRelevantContracts: 40,
|
|
19
|
+
maxRelevantServices: 5,
|
|
20
|
+
maxServiceContracts: 12,
|
|
21
|
+
maxPredecessorOutputs: 5,
|
|
22
|
+
maxRelatedFeatures: 50,
|
|
23
|
+
maxRelatedDebates: 20,
|
|
24
|
+
},
|
|
25
|
+
standard: {
|
|
26
|
+
maxReadOrder: UNLIMITED,
|
|
27
|
+
maxCoreDocs: UNLIMITED,
|
|
28
|
+
maxRelevantContracts: UNLIMITED,
|
|
29
|
+
maxRelevantServices: UNLIMITED,
|
|
30
|
+
maxServiceContracts: UNLIMITED,
|
|
31
|
+
maxPredecessorOutputs: UNLIMITED,
|
|
32
|
+
maxRelatedFeatures: UNLIMITED,
|
|
33
|
+
maxRelatedDebates: UNLIMITED,
|
|
34
|
+
},
|
|
35
|
+
full: {
|
|
36
|
+
maxReadOrder: UNLIMITED,
|
|
37
|
+
maxCoreDocs: UNLIMITED,
|
|
38
|
+
maxRelevantContracts: UNLIMITED,
|
|
39
|
+
maxRelevantServices: UNLIMITED,
|
|
40
|
+
maxServiceContracts: UNLIMITED,
|
|
41
|
+
maxPredecessorOutputs: UNLIMITED,
|
|
42
|
+
maxRelatedFeatures: UNLIMITED,
|
|
43
|
+
maxRelatedDebates: UNLIMITED,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
9
46
|
async function readYamlWorkspaceDoc(filePath, schema) {
|
|
10
47
|
const content = await fs.readFile(filePath, 'utf-8').catch(() => '');
|
|
11
48
|
if (!content.trim())
|
|
@@ -60,7 +97,8 @@ export class ContextService {
|
|
|
60
97
|
constructor(stores) {
|
|
61
98
|
this.stores = stores;
|
|
62
99
|
}
|
|
63
|
-
async execute(projectRoot, ref) {
|
|
100
|
+
async execute(projectRoot, ref, options = {}) {
|
|
101
|
+
const budgetMode = options.budgetMode ?? 'standard';
|
|
64
102
|
const { config, paths } = await getRuntime(projectRoot);
|
|
65
103
|
const snapshot = await loadStateSnapshot(paths, config);
|
|
66
104
|
const normalizedRef = normalizeSddEntityRef(ref);
|
|
@@ -68,6 +106,16 @@ export class ContextService {
|
|
|
68
106
|
if (!type) {
|
|
69
107
|
throw new Error(`Referencia ${ref} invalida. Use FEAT/EPIC/RAD/FGAP/TD.`);
|
|
70
108
|
}
|
|
109
|
+
const cacheRef = await buildContextPackCacheRef(paths, normalizedRef, type, budgetMode);
|
|
110
|
+
const cached = await readContextPackCache(cacheRef);
|
|
111
|
+
if (cached) {
|
|
112
|
+
return attachContextPackCacheMetadata(cached, cacheRef, true);
|
|
113
|
+
}
|
|
114
|
+
const finishContextPack = async (context) => {
|
|
115
|
+
const budgeted = applyContextPackBudget(context, budgetMode);
|
|
116
|
+
await writeContextPackCache(cacheRef, budgeted);
|
|
117
|
+
return attachContextPackCacheMetadata(budgeted, cacheRef, false);
|
|
118
|
+
};
|
|
71
119
|
const coreDocs = [
|
|
72
120
|
coreDocRef(paths, 'index.md'),
|
|
73
121
|
coreDocRef(paths, 'arquitetura.md'),
|
|
@@ -147,7 +195,7 @@ export class ContextService {
|
|
|
147
195
|
? relProjectPath(paths, path.join(paths.projectRoot, workspace.workspace_path, docNames.quality))
|
|
148
196
|
: '';
|
|
149
197
|
const requiredSkillEvidence = item.recommended_skills.filter(Boolean);
|
|
150
|
-
return {
|
|
198
|
+
return finishContextPack({
|
|
151
199
|
sdd_pack_version: 1,
|
|
152
200
|
target_id: normalizedRef,
|
|
153
201
|
target_type: type,
|
|
@@ -212,14 +260,14 @@ export class ContextService {
|
|
|
212
260
|
lock_conflicts_with: lockConflicts,
|
|
213
261
|
readiness: featureReadiness(item, snapshot.backlog.items),
|
|
214
262
|
core_docs: coreDocs,
|
|
215
|
-
};
|
|
263
|
+
});
|
|
216
264
|
}
|
|
217
265
|
if (type === 'RAD' || type === 'EPIC') {
|
|
218
266
|
const radar = snapshot.discoveryIndex.records.find((record) => record.id === normalizedRef && (record.type === 'RAD' || record.type === 'EPIC'));
|
|
219
267
|
if (!radar)
|
|
220
268
|
throw new Error(`Epic/Radar ${normalizedRef} nao encontrado.`);
|
|
221
269
|
const relatedFeatures = snapshot.backlog.items.filter((item) => (item.origin_type === 'radar' || item.origin_type === 'epic') && item.origin_ref === normalizedRef);
|
|
222
|
-
return {
|
|
270
|
+
return finishContextPack({
|
|
223
271
|
sdd_pack_version: 1,
|
|
224
272
|
target_id: normalizedRef,
|
|
225
273
|
target_type: type,
|
|
@@ -236,13 +284,13 @@ export class ContextService {
|
|
|
236
284
|
planningDocRef(paths, 'backlog-graph.md'),
|
|
237
285
|
],
|
|
238
286
|
core_docs: coreDocs,
|
|
239
|
-
};
|
|
287
|
+
});
|
|
240
288
|
}
|
|
241
289
|
if (type === 'FGAP') {
|
|
242
290
|
const gap = snapshot.frontendGaps?.items.find((item) => item.id === normalizedRef);
|
|
243
291
|
if (!gap)
|
|
244
292
|
throw new Error(`Gap de frontend ${normalizedRef} nao encontrado.`);
|
|
245
|
-
return {
|
|
293
|
+
return finishContextPack({
|
|
246
294
|
sdd_pack_version: 1,
|
|
247
295
|
target_id: normalizedRef,
|
|
248
296
|
target_type: type,
|
|
@@ -257,12 +305,12 @@ export class ContextService {
|
|
|
257
305
|
planningDocRef(paths, 'frontend-gaps.md'),
|
|
258
306
|
],
|
|
259
307
|
core_docs: coreDocs,
|
|
260
|
-
};
|
|
308
|
+
});
|
|
261
309
|
}
|
|
262
310
|
const debt = snapshot.techDebt.items.find((item) => item.id === normalizedRef);
|
|
263
311
|
if (!debt)
|
|
264
312
|
throw new Error(`Divida tecnica ${normalizedRef} nao encontrada.`);
|
|
265
|
-
return {
|
|
313
|
+
return finishContextPack({
|
|
266
314
|
sdd_pack_version: 1,
|
|
267
315
|
target_id: normalizedRef,
|
|
268
316
|
target_type: type,
|
|
@@ -274,7 +322,273 @@ export class ContextService {
|
|
|
274
322
|
planningDocRef(paths, 'tech-debt.md'),
|
|
275
323
|
],
|
|
276
324
|
core_docs: coreDocs,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async function buildContextPackCacheRef(paths, ref, type, mode) {
|
|
329
|
+
const projectFingerprint = createProjectFingerprint(paths.projectRoot);
|
|
330
|
+
const sourceFingerprint = await buildContextSourceFingerprint(paths, ref);
|
|
331
|
+
const key = createHash('sha256')
|
|
332
|
+
.update(JSON.stringify([CONTEXT_PACK_CACHE_SCHEMA_VERSION, projectFingerprint, ref, type, mode, sourceFingerprint]))
|
|
333
|
+
.digest('hex')
|
|
334
|
+
.slice(0, 32);
|
|
335
|
+
const cacheRoot = path.join(ensureGlobalCacheLayout().projects, projectFingerprint, 'context-summary');
|
|
336
|
+
const cacheFilePath = path.join(cacheRoot, `${key}.json`);
|
|
337
|
+
return {
|
|
338
|
+
schema_version: CONTEXT_PACK_CACHE_SCHEMA_VERSION,
|
|
339
|
+
enabled: true,
|
|
340
|
+
key,
|
|
341
|
+
project_fingerprint: projectFingerprint,
|
|
342
|
+
source_fingerprint: sourceFingerprint,
|
|
343
|
+
cache_path: displayCachePath(cacheFilePath),
|
|
344
|
+
cache_file_path: cacheFilePath,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
async function buildContextSourceFingerprint(paths, ref) {
|
|
348
|
+
const hash = createHash('sha256');
|
|
349
|
+
const stateFiles = Object.values(paths.stateFiles);
|
|
350
|
+
for (const filePath of stateFiles.sort()) {
|
|
351
|
+
await hashFileIfPresent(hash, filePath);
|
|
352
|
+
}
|
|
353
|
+
const workspaceFiles = await listContextWorkspaceFiles(paths, ref);
|
|
354
|
+
for (const filePath of workspaceFiles.sort()) {
|
|
355
|
+
await hashFileIfPresent(hash, filePath);
|
|
356
|
+
}
|
|
357
|
+
return hash.digest('hex').slice(0, 32);
|
|
358
|
+
}
|
|
359
|
+
async function listContextWorkspaceFiles(paths, ref) {
|
|
360
|
+
const workspaceRoots = [paths.activeDir, paths.plannedDir, paths.archivedDir].map((root) => path.join(root, ref));
|
|
361
|
+
const files = [];
|
|
362
|
+
for (const workspaceRoot of workspaceRoots) {
|
|
363
|
+
const names = await fs.readdir(workspaceRoot).catch(() => []);
|
|
364
|
+
for (const name of names) {
|
|
365
|
+
if (name.endsWith('.yaml') || name.endsWith('.yml') || name.endsWith('.md')) {
|
|
366
|
+
files.push(path.join(workspaceRoot, name));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return files;
|
|
371
|
+
}
|
|
372
|
+
async function hashFileIfPresent(hash, filePath) {
|
|
373
|
+
const content = await fs.readFile(filePath).catch(() => null);
|
|
374
|
+
if (!content)
|
|
375
|
+
return;
|
|
376
|
+
hash.update(filePath);
|
|
377
|
+
hash.update('\0');
|
|
378
|
+
hash.update(content);
|
|
379
|
+
hash.update('\0');
|
|
380
|
+
}
|
|
381
|
+
async function readContextPackCache(cacheRef) {
|
|
382
|
+
const content = await fs.readFile(cacheRef.cache_file_path, 'utf-8').catch(() => '');
|
|
383
|
+
if (!content.trim())
|
|
384
|
+
return null;
|
|
385
|
+
try {
|
|
386
|
+
const entry = JSON.parse(content);
|
|
387
|
+
if (entry.schema_version !== CONTEXT_PACK_CACHE_SCHEMA_VERSION ||
|
|
388
|
+
entry.key !== cacheRef.key ||
|
|
389
|
+
entry.project_fingerprint !== cacheRef.project_fingerprint ||
|
|
390
|
+
entry.source_fingerprint !== cacheRef.source_fingerprint ||
|
|
391
|
+
!isRecord(entry.context)) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
return entry.context;
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async function writeContextPackCache(cacheRef, context) {
|
|
401
|
+
const entry = {
|
|
402
|
+
schema_version: CONTEXT_PACK_CACHE_SCHEMA_VERSION,
|
|
403
|
+
key: cacheRef.key,
|
|
404
|
+
project_fingerprint: cacheRef.project_fingerprint,
|
|
405
|
+
source_fingerprint: cacheRef.source_fingerprint,
|
|
406
|
+
created_at: nowIso(),
|
|
407
|
+
context,
|
|
408
|
+
};
|
|
409
|
+
await fs.mkdir(path.dirname(cacheRef.cache_file_path), { recursive: true });
|
|
410
|
+
await fs.writeFile(cacheRef.cache_file_path, JSON.stringify(entry), 'utf-8').catch(() => undefined);
|
|
411
|
+
}
|
|
412
|
+
function attachContextPackCacheMetadata(context, cacheRef, hit) {
|
|
413
|
+
const { cache_file_path: _cacheFilePath, ...publicCacheRef } = cacheRef;
|
|
414
|
+
const result = {
|
|
415
|
+
...context,
|
|
416
|
+
context_cache: {
|
|
417
|
+
...publicCacheRef,
|
|
418
|
+
hit,
|
|
419
|
+
refreshed_at: nowIso(),
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
result.context_budget = {
|
|
423
|
+
...result.context_budget,
|
|
424
|
+
estimated_chars_after_budget: estimatePayloadChars(result),
|
|
425
|
+
};
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
function displayCachePath(filePath) {
|
|
429
|
+
const homeDir = process.env.HOME ? path.resolve(process.env.HOME) : '';
|
|
430
|
+
const resolved = path.resolve(filePath);
|
|
431
|
+
if (!homeDir || !resolved.startsWith(`${homeDir}${path.sep}`)) {
|
|
432
|
+
return resolved;
|
|
433
|
+
}
|
|
434
|
+
return path.join('~', path.relative(homeDir, resolved));
|
|
435
|
+
}
|
|
436
|
+
function applyContextPackBudget(context, mode) {
|
|
437
|
+
const profile = CONTEXT_PACK_BUDGET_PROFILES[mode];
|
|
438
|
+
const estimatedBefore = estimatePayloadChars(context);
|
|
439
|
+
const dedupedFields = [];
|
|
440
|
+
const truncatedFields = [];
|
|
441
|
+
const budgeted = { ...context };
|
|
442
|
+
const targetRef = typeof context.target_id === 'string' ? context.target_id : '<REF>';
|
|
443
|
+
const omittedFields = [];
|
|
444
|
+
budgeted.read_order = dedupeArrayField(budgeted.read_order, 'read_order', dedupedFields);
|
|
445
|
+
budgeted.core_docs = dedupeArrayField(budgeted.core_docs, 'core_docs', dedupedFields);
|
|
446
|
+
budgeted.relevant_contracts = dedupeArrayField(budgeted.relevant_contracts, 'relevant_contracts', dedupedFields);
|
|
447
|
+
budgeted.predecessor_outputs = dedupeArrayField(budgeted.predecessor_outputs, 'predecessor_outputs', dedupedFields);
|
|
448
|
+
budgeted.related_features = dedupeArrayField(budgeted.related_features, 'related_features', dedupedFields);
|
|
449
|
+
budgeted.related_debates = dedupeArrayField(budgeted.related_debates, 'related_debates', dedupedFields);
|
|
450
|
+
budgeted.relevant_services = dedupeRelevantServices(budgeted.relevant_services, dedupedFields);
|
|
451
|
+
budgeted.read_order = trimArrayField(budgeted.read_order, profile.maxReadOrder, 'read_order', truncatedFields, omittedFields);
|
|
452
|
+
budgeted.core_docs = trimArrayField(budgeted.core_docs, profile.maxCoreDocs, 'core_docs', truncatedFields, omittedFields);
|
|
453
|
+
budgeted.relevant_contracts = trimArrayField(budgeted.relevant_contracts, profile.maxRelevantContracts, 'relevant_contracts', truncatedFields, omittedFields);
|
|
454
|
+
budgeted.relevant_services = trimRelevantServices(trimArrayField(budgeted.relevant_services, profile.maxRelevantServices, 'relevant_services', truncatedFields, omittedFields), profile.maxServiceContracts, truncatedFields, omittedFields);
|
|
455
|
+
budgeted.predecessor_outputs = trimArrayField(budgeted.predecessor_outputs, profile.maxPredecessorOutputs, 'predecessor_outputs', truncatedFields, omittedFields);
|
|
456
|
+
budgeted.related_features = trimArrayField(budgeted.related_features, profile.maxRelatedFeatures, 'related_features', truncatedFields, omittedFields);
|
|
457
|
+
budgeted.related_debates = trimArrayField(budgeted.related_debates, profile.maxRelatedDebates, 'related_debates', truncatedFields, omittedFields);
|
|
458
|
+
const result = {
|
|
459
|
+
...budgeted,
|
|
460
|
+
context_budget: {
|
|
461
|
+
mode,
|
|
462
|
+
estimated_chars_before_budget: estimatedBefore,
|
|
463
|
+
estimated_chars_after_budget: 0,
|
|
464
|
+
deduped_fields: dedupedFields,
|
|
465
|
+
truncated_fields: Array.from(new Set(truncatedFields)),
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
if (omittedFields.length > 0) {
|
|
469
|
+
result.progressive_disclosure = {
|
|
470
|
+
mode,
|
|
471
|
+
reveal_command: `${CLI_NAME} sdd context ${targetRef} --full --json`,
|
|
472
|
+
omitted_fields: mergeDisclosureHints(omittedFields),
|
|
277
473
|
};
|
|
278
474
|
}
|
|
475
|
+
result.context_budget.estimated_chars_after_budget = estimatePayloadChars(result);
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
function dedupeArrayField(value, fieldName, dedupedFields) {
|
|
479
|
+
if (!Array.isArray(value) || value.length <= 1) {
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
const seen = new Set();
|
|
483
|
+
const deduped = [];
|
|
484
|
+
for (const entry of value) {
|
|
485
|
+
const key = stableContextKey(entry);
|
|
486
|
+
if (seen.has(key))
|
|
487
|
+
continue;
|
|
488
|
+
seen.add(key);
|
|
489
|
+
deduped.push(entry);
|
|
490
|
+
}
|
|
491
|
+
if (deduped.length < value.length) {
|
|
492
|
+
dedupedFields.push({
|
|
493
|
+
field: fieldName,
|
|
494
|
+
before: value.length,
|
|
495
|
+
after: deduped.length,
|
|
496
|
+
removed: value.length - deduped.length,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return deduped;
|
|
500
|
+
}
|
|
501
|
+
function dedupeRelevantServices(value, dedupedFields) {
|
|
502
|
+
const services = dedupeArrayField(value, 'relevant_services', dedupedFields);
|
|
503
|
+
if (!Array.isArray(services)) {
|
|
504
|
+
return services;
|
|
505
|
+
}
|
|
506
|
+
return services.map((service, index) => {
|
|
507
|
+
if (!isRecord(service) || !Array.isArray(service.contracts)) {
|
|
508
|
+
return service;
|
|
509
|
+
}
|
|
510
|
+
const field = `relevant_services[${index}].contracts`;
|
|
511
|
+
return {
|
|
512
|
+
...service,
|
|
513
|
+
contracts: dedupeArrayField(service.contracts, field, dedupedFields),
|
|
514
|
+
};
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
function trimArrayField(value, maxItems, fieldName, truncatedFields, omittedFields) {
|
|
518
|
+
if (!Array.isArray(value) || !Number.isFinite(maxItems) || value.length <= maxItems) {
|
|
519
|
+
return value;
|
|
520
|
+
}
|
|
521
|
+
truncatedFields.push(fieldName);
|
|
522
|
+
omittedFields.push({
|
|
523
|
+
field: fieldName,
|
|
524
|
+
omitted_count: value.length - maxItems,
|
|
525
|
+
reason: 'budget',
|
|
526
|
+
});
|
|
527
|
+
return value.slice(0, maxItems);
|
|
528
|
+
}
|
|
529
|
+
function trimRelevantServices(value, maxServiceContracts, truncatedFields, omittedFields) {
|
|
530
|
+
if (!Array.isArray(value) || !Number.isFinite(maxServiceContracts)) {
|
|
531
|
+
return value;
|
|
532
|
+
}
|
|
533
|
+
let truncated = false;
|
|
534
|
+
const services = value.map((service) => {
|
|
535
|
+
if (!isRecord(service) || !Array.isArray(service.contracts)) {
|
|
536
|
+
return service;
|
|
537
|
+
}
|
|
538
|
+
if (service.contracts.length <= maxServiceContracts) {
|
|
539
|
+
return service;
|
|
540
|
+
}
|
|
541
|
+
truncated = true;
|
|
542
|
+
omittedFields.push({
|
|
543
|
+
field: 'relevant_services.contracts',
|
|
544
|
+
omitted_count: service.contracts.length - maxServiceContracts,
|
|
545
|
+
reason: 'budget',
|
|
546
|
+
});
|
|
547
|
+
return {
|
|
548
|
+
...service,
|
|
549
|
+
contracts: service.contracts.slice(0, maxServiceContracts),
|
|
550
|
+
};
|
|
551
|
+
});
|
|
552
|
+
if (truncated) {
|
|
553
|
+
truncatedFields.push('relevant_services.contracts');
|
|
554
|
+
}
|
|
555
|
+
return services;
|
|
556
|
+
}
|
|
557
|
+
function mergeDisclosureHints(hints) {
|
|
558
|
+
const byField = new Map();
|
|
559
|
+
for (const hint of hints) {
|
|
560
|
+
const existing = byField.get(hint.field);
|
|
561
|
+
if (!existing) {
|
|
562
|
+
byField.set(hint.field, { ...hint });
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
existing.omitted_count += hint.omitted_count;
|
|
566
|
+
}
|
|
567
|
+
return Array.from(byField.values());
|
|
568
|
+
}
|
|
569
|
+
function stableContextKey(value) {
|
|
570
|
+
if (typeof value === 'string')
|
|
571
|
+
return value;
|
|
572
|
+
if (typeof value === 'number' || typeof value === 'boolean' || value === null) {
|
|
573
|
+
return JSON.stringify(value);
|
|
574
|
+
}
|
|
575
|
+
return JSON.stringify(sortContextValue(value));
|
|
576
|
+
}
|
|
577
|
+
function sortContextValue(value) {
|
|
578
|
+
if (Array.isArray(value)) {
|
|
579
|
+
return value.map(sortContextValue);
|
|
580
|
+
}
|
|
581
|
+
if (!isRecord(value)) {
|
|
582
|
+
return value;
|
|
583
|
+
}
|
|
584
|
+
return Object.fromEntries(Object.keys(value)
|
|
585
|
+
.sort()
|
|
586
|
+
.map((key) => [key, sortContextValue(value[key])]));
|
|
587
|
+
}
|
|
588
|
+
function estimatePayloadChars(value) {
|
|
589
|
+
return JSON.stringify(value).length;
|
|
590
|
+
}
|
|
591
|
+
function isRecord(value) {
|
|
592
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
279
593
|
}
|
|
280
594
|
//# sourceMappingURL=context.service.js.map
|
|
@@ -17,6 +17,7 @@ export declare class FinalizeService {
|
|
|
17
17
|
finalized: string[];
|
|
18
18
|
unblocked: string[];
|
|
19
19
|
pending: number;
|
|
20
|
+
post_finalize_replan: PostFinalizeReplan;
|
|
20
21
|
updated_core_docs: string[];
|
|
21
22
|
updated_readme: boolean;
|
|
22
23
|
updated_agent_guide: boolean;
|
|
@@ -73,6 +74,22 @@ export type Q95Ledger = {
|
|
|
73
74
|
axes: Record<Q95AxisKey, Q95AxisResult>;
|
|
74
75
|
next_best_action: string;
|
|
75
76
|
};
|
|
77
|
+
export type PostFinalizeReplan = {
|
|
78
|
+
rank: 'impact';
|
|
79
|
+
generated_at: string;
|
|
80
|
+
finalized: string[];
|
|
81
|
+
unlocked: string[];
|
|
82
|
+
ready: Array<{
|
|
83
|
+
id: string;
|
|
84
|
+
title: string;
|
|
85
|
+
recommended_skills: string[];
|
|
86
|
+
score: number;
|
|
87
|
+
reasons: string[];
|
|
88
|
+
}>;
|
|
89
|
+
waves: string[][];
|
|
90
|
+
blocked_count: number;
|
|
91
|
+
conflicts_count: number;
|
|
92
|
+
};
|
|
76
93
|
export declare function computeQ95Ledger(paths: SddPaths, config: SddRuntimeConfig, feature: BacklogItem, document: WorkspaceQualityDocument): Promise<Q95Ledger>;
|
|
77
94
|
export declare function weightedAxis(input: {
|
|
78
95
|
raw_score: number;
|
|
@@ -90,6 +107,10 @@ export declare function computeIntegrityAxis(document: WorkspaceQualityDocument)
|
|
|
90
107
|
raw_score: number;
|
|
91
108
|
rationale: string;
|
|
92
109
|
};
|
|
110
|
+
export declare function computeRuntimeQualityAxis(document: WorkspaceQualityDocument): {
|
|
111
|
+
raw_score: number;
|
|
112
|
+
rationale: string;
|
|
113
|
+
};
|
|
93
114
|
export declare function computeNamingAxis(feature: BacklogItem, document: WorkspaceQualityDocument): {
|
|
94
115
|
raw_score: number;
|
|
95
116
|
rationale: string;
|
|
@@ -98,6 +119,10 @@ export declare function computeTokenAxis(document: WorkspaceQualityDocument): {
|
|
|
98
119
|
raw_score: number;
|
|
99
120
|
rationale: string;
|
|
100
121
|
};
|
|
122
|
+
export declare function computeStructuredTokenAxis(document: WorkspaceQualityDocument): {
|
|
123
|
+
raw_score: number;
|
|
124
|
+
rationale: string;
|
|
125
|
+
};
|
|
101
126
|
export declare function extractCoveragePerformance(document: WorkspaceQualityDocument, kind: 'unit' | 'integration'): number;
|
|
102
127
|
export declare function integritySignalScore(value: 'not_applicable' | 'pending' | 'passed' | 'failed'): number;
|
|
103
128
|
export declare function inferQ95NextAction(axes: Record<Q95AxisKey, Q95AxisResult>): string;
|