@planu/cli 4.7.1 → 4.7.3

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/config/minimal-implementation-gate.json +110 -0
  3. package/dist/config/token-waste-autopilot.json +16 -0
  4. package/dist/engine/compact/compact-middleware.d.ts +2 -2
  5. package/dist/engine/compact/compact-middleware.js +68 -7
  6. package/dist/engine/context-artifacts/index.d.ts +2 -0
  7. package/dist/engine/context-artifacts/index.js +2 -0
  8. package/dist/engine/context-artifacts/store.d.ts +5 -0
  9. package/dist/engine/context-artifacts/store.js +176 -0
  10. package/dist/engine/handoff-artifacts/schemas.d.ts +112 -0
  11. package/dist/engine/handoff-artifacts/schemas.js +40 -0
  12. package/dist/engine/minimality/analyzer.d.ts +3 -0
  13. package/dist/engine/minimality/analyzer.js +140 -0
  14. package/dist/engine/minimality/formatter.d.ts +3 -0
  15. package/dist/engine/minimality/formatter.js +25 -0
  16. package/dist/engine/minimality/index.d.ts +4 -0
  17. package/dist/engine/minimality/index.js +4 -0
  18. package/dist/engine/minimality/policy-loader.d.ts +3 -0
  19. package/dist/engine/minimality/policy-loader.js +133 -0
  20. package/dist/engine/token-optimizer/content-aware-compactor.d.ts +4 -0
  21. package/dist/engine/token-optimizer/content-aware-compactor.js +230 -0
  22. package/dist/engine/token-optimizer/index.d.ts +1 -0
  23. package/dist/engine/token-optimizer/index.js +1 -0
  24. package/dist/engine/token-optimizer/output-filter.js +18 -2
  25. package/dist/engine/token-optimizer/policy-loader.js +12 -0
  26. package/dist/engine/token-optimizer/reporter.d.ts +4 -0
  27. package/dist/engine/token-optimizer/reporter.js +14 -1
  28. package/dist/engine/validator/validation-report-writer.d.ts +2 -0
  29. package/dist/engine/validator/validation-report-writer.js +19 -0
  30. package/dist/engine/web-fetcher/docs-fetcher.js +5 -1
  31. package/dist/tools/challenge-spec.js +25 -0
  32. package/dist/tools/package-handoff.js +23 -1
  33. package/dist/tools/safe-handler.js +4 -1
  34. package/dist/tools/token-usage-handler.js +5 -3
  35. package/dist/tools/update-status/dod-gates.js +9 -0
  36. package/dist/tools/validate.js +34 -0
  37. package/dist/types/compact/compact-mode.d.ts +5 -0
  38. package/dist/types/context-artifacts.d.ts +96 -0
  39. package/dist/types/context-artifacts.js +2 -0
  40. package/dist/types/handoff-artifacts.d.ts +2 -0
  41. package/dist/types/index.d.ts +2 -0
  42. package/dist/types/index.js +2 -0
  43. package/dist/types/minimal-implementation-gate.d.ts +92 -0
  44. package/dist/types/minimal-implementation-gate.js +2 -0
  45. package/dist/types/token-optimization.d.ts +2 -0
  46. package/dist/types/token-waste-autopilot.d.ts +15 -0
  47. package/package.json +17 -17
  48. package/planu-native.json +1 -1
  49. package/planu-plugin.json +1 -1
@@ -28,6 +28,16 @@ export class OptimizationReporter {
28
28
  record.tokensSaved += tokensSaved;
29
29
  this.totalSaved += tokensSaved;
30
30
  }
31
+ /**
32
+ * Record measured savings from reversible compaction.
33
+ */
34
+ recordCompaction(toolName, tokensSaved, retrievals = 0) {
35
+ const record = this.getOrCreateRecord(toolName);
36
+ record.compactionTokensSaved = (record.compactionTokensSaved ?? 0) + tokensSaved;
37
+ record.artifactRetrievals = (record.artifactRetrievals ?? 0) + retrievals;
38
+ record.tokensSaved += tokensSaved;
39
+ this.totalSaved += tokensSaved;
40
+ }
31
41
  /**
32
42
  * Record a cache miss for a tool.
33
43
  */
@@ -106,7 +116,8 @@ export class OptimizationReporter {
106
116
  for (const record of toolRecords) {
107
117
  lines.push(`- ${record.toolName}: ${String(record.totalTokens)} tokens, ` +
108
118
  `${String(record.callCount)} calls, ` +
109
- `${String(record.tokensSaved)} saved`);
119
+ `${String(record.tokensSaved)} saved ` +
120
+ `(compaction ${String(record.compactionTokensSaved ?? 0)}, retrievals ${String(record.artifactRetrievals ?? 0)})`);
110
121
  }
111
122
  }
112
123
  return lines.join('\n');
@@ -134,6 +145,8 @@ export class OptimizationReporter {
134
145
  cacheHits: 0,
135
146
  cacheMisses: 0,
136
147
  tokensSaved: 0,
148
+ compactionTokensSaved: 0,
149
+ artifactRetrievals: 0,
137
150
  };
138
151
  this.toolRecords.set(toolName, record);
139
152
  }
@@ -1,5 +1,6 @@
1
1
  import type { Spec } from '../../types/index.js';
2
2
  import type { ValidationReportV1 } from '../../types/handoff-artifacts.js';
3
+ import type { MinimalImplementationReport } from '../../types/minimal-implementation-gate.js';
3
4
  export declare function writeImplementationReviewReport(input: {
4
5
  projectId: string;
5
6
  specId: string;
@@ -8,6 +9,7 @@ export declare function writeImplementationReviewReport(input: {
8
9
  score: number | null;
9
10
  lintPassed?: boolean;
10
11
  conventionRegression?: boolean;
12
+ minimalityReport?: MinimalImplementationReport;
11
13
  }): Promise<{
12
14
  written: boolean;
13
15
  path?: string;
@@ -7,6 +7,7 @@ export async function writeImplementationReviewReport(input) {
7
7
  lintPassed: input.lintPassed ?? true,
8
8
  conventionRegression: input.conventionRegression ?? false,
9
9
  specCompliance,
10
+ minimalityReport: input.minimalityReport,
10
11
  });
11
12
  const passed = gates.every((gate) => gate.passed);
12
13
  const reviewer = {
@@ -22,6 +23,7 @@ export async function writeImplementationReviewReport(input) {
22
23
  gates,
23
24
  reviewer,
24
25
  specCompliance: reportCompliance,
26
+ minimalityReport: input.minimalityReport,
25
27
  score: input.score ?? undefined,
26
28
  completedAt: new Date().toISOString(),
27
29
  };
@@ -73,8 +75,25 @@ function buildGates(args) {
73
75
  reason: args.conventionRegression ? 'Convention baseline regression detected.' : undefined,
74
76
  },
75
77
  buildSpecComplianceGate(args.specCompliance),
78
+ buildMinimalityGate(args.minimalityReport),
76
79
  ];
77
80
  }
81
+ function buildMinimalityGate(report) {
82
+ if (report?.enabled !== true) {
83
+ return {
84
+ name: 'minimal-implementation',
85
+ passed: true,
86
+ reason: 'Minimal implementation report unavailable or disabled.',
87
+ };
88
+ }
89
+ return {
90
+ name: 'minimal-implementation',
91
+ passed: !report.blocked,
92
+ reason: report.blocked
93
+ ? `Blocking minimality findings: ${String(report.findings.filter((finding) => finding.blocksDone).length)}.`
94
+ : undefined,
95
+ };
96
+ }
78
97
  function buildSpecComplianceGate(result) {
79
98
  if (result.perScenario.length === 0) {
80
99
  return {
@@ -1,6 +1,7 @@
1
1
  // Planu — Web Fetcher: consultDocs orchestration
2
2
  import { searchAndRegisterFramework, saveRegistry } from '../registry-updater.js';
3
3
  import { loadDocsRegistry, findDocsEntry, setDocsRegistryCache, getStoredRegistryPath, } from './registry-loader.js';
4
+ import { DEFAULT_CONFIG } from './cache.js';
4
5
  import { fetchUrl } from './http-client.js';
5
6
  import { extractTextContent, extractCodeBlocks, extractBestPractices, buildSummaryFromContent, buildPlaceholderSummary, buildPlaceholderExamples, buildPlaceholderBestPractices, } from './content-extractor.js';
6
7
  export async function consultDocsImpl(topic, framework) {
@@ -25,7 +26,10 @@ export async function consultDocsImpl(topic, framework) {
25
26
  : `https://www.google.com/search?q=${encodeURIComponent(`${resolvedFramework} ${topic} documentation`)}`;
26
27
  const baseUrl = docsEntry?.base ?? '';
27
28
  if (baseUrl) {
28
- const fetchResult = await fetchUrl(docsUrl);
29
+ const fetchResult = await fetchUrl(docsUrl, {
30
+ ...DEFAULT_CONFIG,
31
+ timeoutMs: 2_500,
32
+ });
29
33
  if (fetchResult) {
30
34
  const textContent = extractTextContent(fetchResult.content);
31
35
  const codeBlocks = extractCodeBlocks(fetchResult.content);
@@ -24,6 +24,7 @@ import { generateResilienceChallengeScenarios } from './challenge-spec/resilienc
24
24
  import { detectContradictions as detectDecisionContradictions, searchPriorDecisions, } from '../engine/prior-decisions/index.js';
25
25
  import { getDecisions } from '../storage/decision-store.js';
26
26
  import { calculateTokenBudget, injectBudgetIntoPrompt } from '../engine/token-budget/index.js';
27
+ import { analyzeMinimalImplementation, loadMinimalImplementationPolicy, } from '../engine/minimality/index.js';
27
28
  const ALL_FOCUS_AREAS = [
28
29
  'failures',
29
30
  'concurrency',
@@ -127,6 +128,30 @@ export async function handleChallengeSpec(args, server) {
127
128
  const focusAreas = focus && focus.length > 0 ? focus : ALL_FOCUS_AREAS;
128
129
  // 5. Generate failure scenarios
129
130
  const failureScenarios = [];
131
+ try {
132
+ const { policy, evidence } = await loadMinimalImplementationPolicy(knowledge.projectPath);
133
+ const minimality = analyzeMinimalImplementation({
134
+ policy,
135
+ specId,
136
+ specRisk: spec.risk,
137
+ specText: specContent,
138
+ evidence,
139
+ });
140
+ for (const finding of minimality.findings.slice(0, 5)) {
141
+ failureScenarios.push({
142
+ scenario: `Minimal implementation concern: ${finding.tag}`,
143
+ probability: finding.confidence === 'high' ? 'high' : 'medium',
144
+ impact: finding.blocksDone ? 'high' : 'low',
145
+ currentHandling: `${finding.target}${finding.line ? `:${String(finding.line)}` : ''} — ${finding.evidence}`,
146
+ requiredHandling: finding.replacementGuidance,
147
+ dataConsistency: 'Scope control risk',
148
+ userExperience: 'Avoidable implementation complexity can increase token use and maintenance cost',
149
+ });
150
+ }
151
+ }
152
+ catch {
153
+ // Minimality challenge is best-effort and must not hide resilience findings.
154
+ }
130
155
  if (focusAreas.includes('failures')) {
131
156
  failureScenarios.push(...generateFailureScenarios(spec, specContent, knowledge));
132
157
  }
@@ -6,6 +6,7 @@ import { detectParadigms } from '../engine/paradigm-detector.js';
6
6
  import { analyzeContextPreflight, buildTokenWasteReport, formatTokenWasteReport, loadTokenWastePolicy, recommendRelevantTools, toolsFromPolicyGroups, } from '../engine/token-optimizer/index.js';
7
7
  import { appendTransitionEvent } from '../storage/transition-log.js';
8
8
  import { formatProjectGraphContext, queryProjectGraphSlice, } from '../engine/project-graph/index.js';
9
+ import { analyzeMinimalImplementation, loadMinimalImplementationPolicy, } from '../engine/minimality/index.js';
9
10
  // ── Formatting helpers ───────────────────────────────────────────────────────
10
11
  function formatHandoff(pkg) {
11
12
  const lines = [];
@@ -196,6 +197,22 @@ async function buildGraphContextSection(args) {
196
197
  return null;
197
198
  }
198
199
  }
200
+ async function buildMinimalImplementationReport(pkg, knowledge, spec, handoffText) {
201
+ try {
202
+ const { policy, evidence } = await loadMinimalImplementationPolicy(knowledge.projectPath);
203
+ return analyzeMinimalImplementation({
204
+ policy,
205
+ specId: spec.id,
206
+ specRisk: spec.risk,
207
+ handoffText,
208
+ files: [...pkg.filesToModify, ...pkg.filesToCreate].map((path) => ({ path, content: path })),
209
+ evidence,
210
+ });
211
+ }
212
+ catch {
213
+ return null;
214
+ }
215
+ }
199
216
  // ── Handler ──────────────────────────────────────────────────────────────────
200
217
  export async function handlePackageHandoff(args) {
201
218
  const { projectId, specId } = args;
@@ -256,9 +273,13 @@ export async function handlePackageHandoff(args) {
256
273
  projectPath: knowledge.projectPath,
257
274
  specId,
258
275
  });
259
- const handoffText = graphContext !== null
276
+ const baseHandoffText = graphContext !== null
260
277
  ? `${formatHandoff(pkgWithScore)}\n${graphContext.text}`
261
278
  : formatHandoff(pkgWithScore);
279
+ const minimalityReport = await buildMinimalImplementationReport(pkgWithScore, knowledge, spec, baseHandoffText);
280
+ const handoffText = minimalityReport !== null && minimalityReport.markdown.length > 0
281
+ ? `${baseHandoffText}\n${minimalityReport.markdown}`
282
+ : baseHandoffText;
262
283
  const formatted = tokenWasteReport !== null
263
284
  ? `${handoffText}\n${formatTokenWasteReport(tokenWasteReport)}`
264
285
  : handoffText;
@@ -282,6 +303,7 @@ export async function handlePackageHandoff(args) {
282
303
  blockers: pkgWithScore.blockers,
283
304
  handoffPath: pkgWithScore.handoffPath,
284
305
  contextHash: pkgWithScore.contextHash,
306
+ ...(minimalityReport !== null ? { minimality: minimalityReport } : {}),
285
307
  ...(tokenWasteReport !== null ? { tokenWaste: tokenWasteReport } : {}),
286
308
  ...(graphContext !== null ? { graphContext: graphContext.structured } : {}),
287
309
  },
@@ -268,7 +268,10 @@ function safeWithTelemetry(toolName, handler) {
268
268
  // SPEC-455: Compress verbose JSON outputs to save LLM tokens
269
269
  const compressed = compressToolOutput(result);
270
270
  // SPEC-922: Apply compact mode middleware
271
- const compacted = applyCompactMode(compressed, decision);
271
+ const compacted = applyCompactMode(compressed, decision, {
272
+ projectPath,
273
+ flow: toolName,
274
+ });
272
275
  // Inject pending drift banner (non-blocking, informational only)
273
276
  const driftBanner = projectPath !== undefined ? await checkPendingDriftBanner(projectPath) : null;
274
277
  const withDrift = injectDriftBanner(compacted, driftBanner);
@@ -27,10 +27,12 @@ export function handleTokenUsage(args) {
27
27
  let details;
28
28
  if (groupBy === 'tool' && toolRecords.length > 0) {
29
29
  const lines = toolRecords.map((r) => `| ${r.toolName} | ${String(r.totalTokens)} | ${String(r.callCount)} | ` +
30
- `${String(r.cacheHits)}/${String(r.cacheHits + r.cacheMisses)} | ${String(r.tokensSaved)} |`);
30
+ `${String(r.cacheHits)}/${String(r.cacheHits + r.cacheMisses)} | ` +
31
+ `${String(r.tokensSaved)} | ${String(r.compactionTokensSaved ?? 0)} | ` +
32
+ `${String(r.artifactRetrievals ?? 0)} |`);
31
33
  details = [
32
- '| Tool | Tokens | Calls | Cache H/T | Saved |',
33
- '|------|--------|-------|-----------|-------|',
34
+ '| Tool | Tokens | Calls | Cache H/T | Saved | Compaction Saved | Retrievals |',
35
+ '|------|--------|-------|-----------|-------|------------------|------------|',
34
36
  ...lines,
35
37
  ].join('\n');
36
38
  }
@@ -299,6 +299,15 @@ export async function checkValidationReportGate(specId, projectId, force) {
299
299
  fixHint: 'Fix failing gates and re-run validate before marking done.',
300
300
  });
301
301
  }
302
+ if (result.payload.minimalityReport?.blocked) {
303
+ return validationReportGateError({
304
+ specId,
305
+ error: 'minimality_findings_block_done',
306
+ message: 'Validation report contains blocking minimal implementation findings. Remove avoidable complexity or provide an audited forceStatusReason.',
307
+ gates: result.payload.gates,
308
+ fixHint: 'Fix blocking minimality findings and re-run validate before marking done. Use forceStatus only with an audited reason for accepted complexity.',
309
+ });
310
+ }
302
311
  if (result.payload.reviewer.verdict !== 'approved' ||
303
312
  result.payload.reviewer.agent.trim().length === 0) {
304
313
  return validationReportGateError({
@@ -18,6 +18,7 @@ import { compareWithBaseline } from '../storage/convention-baseline.js';
18
18
  import { writeImplementationReviewReport } from '../engine/validator/validation-report-writer.js';
19
19
  import { evaluateNewCodeGate } from '../engine/ai-assurance/index.js';
20
20
  import { queryProjectGraphSlice } from '../engine/project-graph/index.js';
21
+ import { analyzeMinimalImplementation, loadMinimalImplementationPolicy, } from '../engine/minimality/index.js';
21
22
  // Re-export for external use (SPEC-018)
22
23
  export { validateContractCompliance };
23
24
  function graphCoverageGaps(slice) {
@@ -47,6 +48,25 @@ function formatGraphCoverageText(report) {
47
48
  ? `\nGRAPH ${String(report.gaps.length)} graph-backed coverage gap(s)`
48
49
  : '';
49
50
  }
51
+ async function buildMinimalityReport(args) {
52
+ try {
53
+ const { policy, evidence } = await loadMinimalImplementationPolicy(args.projectPath);
54
+ return analyzeMinimalImplementation({
55
+ policy,
56
+ specId: args.specId,
57
+ specRisk: args.risk,
58
+ specText: [args.title ?? '', ...args.missing, ...args.extra].join('\n'),
59
+ files: args.qualityIssues.map((issue) => ({
60
+ path: issue.file,
61
+ content: [issue.rule, issue.message, issue.suggestion ?? ''].join('\n'),
62
+ })),
63
+ evidence,
64
+ });
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
50
70
  async function validateStrictLayoutOrError(args) {
51
71
  try {
52
72
  const { validateStrictPlanuLayout } = await import('../engine/spec-migrator/index.js');
@@ -176,6 +196,15 @@ export async function handleValidate(args, server) {
176
196
  // 7. Lint check (best-effort — non-blocking)
177
197
  const lintCheck = runLintCheck(projectPath, knowledge.lintCommand ?? null);
178
198
  const assuranceGates = runAssuranceGates(projectPath);
199
+ const minimalityReport = await buildMinimalityReport({
200
+ projectPath,
201
+ specId,
202
+ risk: spec.risk,
203
+ title: spec.title,
204
+ missing: result.missing,
205
+ extra: result.extra,
206
+ qualityIssues: result.qualityIssues,
207
+ });
179
208
  // SPEC-1050: Generate a mandatory implementation-review artifact.
180
209
  const validationReport = await writeImplementationReviewReport({
181
210
  projectId,
@@ -185,6 +214,7 @@ export async function handleValidate(args, server) {
185
214
  score: result.score,
186
215
  lintPassed: lintCheck.passed,
187
216
  conventionRegression: regressionDetected,
217
+ minimalityReport: minimalityReport ?? undefined,
188
218
  });
189
219
  // 8. Build output
190
220
  const output = {
@@ -262,6 +292,7 @@ export async function handleValidate(args, server) {
262
292
  lintCheck,
263
293
  assuranceGates,
264
294
  validationReport,
295
+ minimalityReport,
265
296
  graphCoverage,
266
297
  };
267
298
  // SPEC-612: Scope boundary validation — warn if impl files match outOfScope items
@@ -312,6 +343,9 @@ export async function handleValidate(args, server) {
312
343
  if (!assuranceGates.newCode.passed) {
313
344
  suggestions.push(`Assurance gate failed: ${String(assuranceGates.newCode.findings.length)} new-code domain inference issue(s) found.`);
314
345
  }
346
+ if (minimalityReport?.blocked) {
347
+ suggestions.push(`${minimalityReport.findings.filter((finding) => finding.blocksDone).length} blocking minimality finding(s) detected. Remove avoidable complexity or record accepted debt before marking done.`);
348
+ }
315
349
  const outputWithSuggestions = compactObj({
316
350
  ...output,
317
351
  suggestions: suggestions.length > 0 ? suggestions : undefined,
@@ -20,6 +20,11 @@ export interface CompactDecision {
20
20
  contextUsed?: number;
21
21
  reason: 'header_above_enter' | 'header_below_exit' | 'hysteresis_keep' | 'no_header';
22
22
  }
23
+ export interface CompactModeOptions {
24
+ projectPath?: string;
25
+ sourcePath?: string;
26
+ flow?: string;
27
+ }
23
28
  export interface CompactMetrics {
24
29
  compactDecisions: number;
25
30
  verboseDecisions: number;
@@ -0,0 +1,96 @@
1
+ export type ContextArtifactContentType = 'json' | 'test-log' | 'runtime-log' | 'search-results' | 'code' | 'spec-or-handoff' | 'generic-text';
2
+ export interface ContextArtifactCompactionMetadata {
3
+ artifactRef: string;
4
+ originalTokens: number;
5
+ compactTokens: number;
6
+ tokensSaved: number;
7
+ strategy: string;
8
+ contentType: ContextArtifactContentType;
9
+ expiresAt: string;
10
+ retrievalHint: string;
11
+ }
12
+ export interface ContextArtifact {
13
+ ref: string;
14
+ contentHash: string;
15
+ createdAt: string;
16
+ expiresAt: string;
17
+ ttlMs: number;
18
+ projectId: string;
19
+ contentType: ContextArtifactContentType;
20
+ strategy: string;
21
+ originalTokens: number;
22
+ compactTokens: number;
23
+ tokensSaved: number;
24
+ retrievalCount: number;
25
+ metadata: Record<string, string | number | boolean>;
26
+ originalContent: string;
27
+ compactContent: string;
28
+ }
29
+ export interface StoreContextArtifactInput {
30
+ projectPath: string;
31
+ originalContent: string;
32
+ compactContent: string;
33
+ contentType: ContextArtifactContentType;
34
+ strategy: string;
35
+ originalTokens: number;
36
+ compactTokens: number;
37
+ ttlMs: number;
38
+ sourcePath?: string;
39
+ flow?: string;
40
+ metadata?: Record<string, unknown>;
41
+ }
42
+ export interface StoreContextArtifactResult {
43
+ stored: boolean;
44
+ artifact?: ContextArtifact;
45
+ metadata?: ContextArtifactCompactionMetadata;
46
+ refusedReason?: string;
47
+ }
48
+ export interface RetrieveContextArtifactResult {
49
+ found: boolean;
50
+ artifact?: ContextArtifact;
51
+ reason?: 'missing' | 'expired' | 'corrupt' | 'invalid-ref' | 'unauthorized';
52
+ hint: string;
53
+ }
54
+ export interface ContextArtifactStats {
55
+ artifactCount: number;
56
+ totalOriginalTokens: number;
57
+ totalCompactTokens: number;
58
+ totalTokensSaved: number;
59
+ retrievalCount: number;
60
+ }
61
+ export interface ContentAwareCompactionInput {
62
+ text: string;
63
+ policy: {
64
+ contextArtifacts?: {
65
+ enabled?: boolean;
66
+ ttlMs?: number;
67
+ minTokens?: number;
68
+ };
69
+ contentCompaction?: {
70
+ strategies?: Partial<Record<ContextArtifactContentType, {
71
+ maxLines?: number;
72
+ maxSnippetChars?: number;
73
+ }>>;
74
+ };
75
+ redaction: {
76
+ maxSnippetChars: number;
77
+ redactPatterns: string[];
78
+ };
79
+ };
80
+ projectPath?: string;
81
+ kind?: string;
82
+ sourcePath?: string;
83
+ flow?: string;
84
+ metadata?: Record<string, unknown>;
85
+ }
86
+ export interface ContentAwareCompactionResult {
87
+ text: string;
88
+ originalTokens: number;
89
+ compactTokens: number;
90
+ tokensSaved: number;
91
+ strategy: string;
92
+ contentType: ContextArtifactContentType;
93
+ artifact?: ContextArtifactCompactionMetadata;
94
+ refusedReason?: string;
95
+ }
96
+ //# sourceMappingURL=context-artifacts.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context-artifacts.js.map
@@ -72,6 +72,7 @@ export interface ValidationReportV1 {
72
72
  evidence: string[];
73
73
  }[];
74
74
  };
75
+ minimalityReport?: MinimalImplementationReport;
75
76
  score?: number;
76
77
  completedAt: string;
77
78
  }
@@ -83,4 +84,5 @@ export interface ArtifactPayloadMap {
83
84
  'validation-report': ValidationReportV1;
84
85
  }
85
86
  export type ArtifactPayload<K extends ArtifactKind> = ArtifactPayloadMap[K];
87
+ import type { MinimalImplementationReport } from './minimal-implementation-gate.js';
86
88
  //# sourceMappingURL=handoff-artifacts.d.ts.map
@@ -80,6 +80,8 @@ export * from './workers.js';
80
80
  export * from './orchestration-runtime.js';
81
81
  export * from './token-optimization.js';
82
82
  export * from './token-waste-autopilot.js';
83
+ export * from './context-artifacts.js';
84
+ export * from './minimal-implementation-gate.js';
83
85
  export * from './llm-providers.js';
84
86
  export * from './plugins.js';
85
87
  export * from './github.js';
@@ -81,6 +81,8 @@ export * from './workers.js';
81
81
  export * from './orchestration-runtime.js';
82
82
  export * from './token-optimization.js';
83
83
  export * from './token-waste-autopilot.js';
84
+ export * from './context-artifacts.js';
85
+ export * from './minimal-implementation-gate.js';
84
86
  export * from './llm-providers.js';
85
87
  export * from './plugins.js';
86
88
  export * from './github.js';
@@ -0,0 +1,92 @@
1
+ export type MinimalImplementationTag = string;
2
+ export type MinimalImplementationSeverity = 'info' | 'warning' | 'blocker';
3
+ export type MinimalImplementationConfidence = 'low' | 'medium' | 'high';
4
+ export type MinimalImplementationSource = 'policy' | 'project-config' | 'runtime' | 'spec';
5
+ export interface MinimalImplementationPolicyLoadOptions {
6
+ defaultPolicyPath?: string;
7
+ }
8
+ export interface MinimalImplementationEvidence {
9
+ source: MinimalImplementationSource;
10
+ key: string;
11
+ value?: string | number | boolean;
12
+ }
13
+ export interface MinimalImplementationRule {
14
+ id: string;
15
+ tag: MinimalImplementationTag;
16
+ severity: MinimalImplementationSeverity;
17
+ confidence: MinimalImplementationConfidence;
18
+ patterns: string[];
19
+ replacementGuidance: string;
20
+ blockWhenRiskAtLeast?: 'low' | 'medium' | 'high' | 'max';
21
+ }
22
+ export interface MinimalImplementationPolicy {
23
+ version: 1;
24
+ enabled: boolean;
25
+ report: {
26
+ maxFindings: number;
27
+ maxMarkdownLines: number;
28
+ maxEvidenceChars: number;
29
+ };
30
+ tags: Record<string, {
31
+ description: string;
32
+ }>;
33
+ rules: MinimalImplementationRule[];
34
+ safetyExclusions: string[];
35
+ excludedPathPatterns: string[];
36
+ debtEvidence: {
37
+ requiredFields: string[];
38
+ };
39
+ }
40
+ export interface LoadedMinimalImplementationPolicy {
41
+ policy: MinimalImplementationPolicy;
42
+ evidence: MinimalImplementationEvidence[];
43
+ }
44
+ export interface MinimalImplementationFileSignal {
45
+ path: string;
46
+ content?: string;
47
+ }
48
+ export interface MinimalImplementationInput {
49
+ policy: MinimalImplementationPolicy;
50
+ specId?: string;
51
+ specRisk?: string;
52
+ specText?: string;
53
+ handoffText?: string;
54
+ files?: MinimalImplementationFileSignal[];
55
+ packageManifestText?: string;
56
+ acceptedDebt?: MinimalImplementationDebtEvidence[];
57
+ evidence?: MinimalImplementationEvidence[];
58
+ }
59
+ export interface MinimalImplementationFinding {
60
+ ruleId: string;
61
+ tag: MinimalImplementationTag;
62
+ severity: MinimalImplementationSeverity;
63
+ confidence: MinimalImplementationConfidence;
64
+ target: string;
65
+ line?: number;
66
+ evidence: string;
67
+ replacementGuidance: string;
68
+ blocksDone: boolean;
69
+ evidenceSource: MinimalImplementationEvidence[];
70
+ }
71
+ export interface MinimalImplementationSafetyException {
72
+ target: string;
73
+ reason: string;
74
+ evidence: string;
75
+ }
76
+ export interface MinimalImplementationDebtEvidence {
77
+ specId: string;
78
+ files: string[];
79
+ ceiling: string;
80
+ upgradeTrigger: string;
81
+ reviewRationale: string;
82
+ }
83
+ export interface MinimalImplementationReport {
84
+ enabled: boolean;
85
+ blocked: boolean;
86
+ findings: MinimalImplementationFinding[];
87
+ safetyExceptions: MinimalImplementationSafetyException[];
88
+ debtEvidence: MinimalImplementationDebtEvidence[];
89
+ evidence: MinimalImplementationEvidence[];
90
+ markdown: string;
91
+ }
92
+ //# sourceMappingURL=minimal-implementation-gate.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=minimal-implementation-gate.js.map
@@ -104,6 +104,8 @@ export interface ToolTokenRecord {
104
104
  cacheHits: number;
105
105
  cacheMisses: number;
106
106
  tokensSaved: number;
107
+ compactionTokensSaved?: number;
108
+ artifactRetrievals?: number;
107
109
  }
108
110
  export interface BatchEntry {
109
111
  input: unknown;
@@ -1,3 +1,4 @@
1
+ import type { ContextArtifactCompactionMetadata } from './context-artifacts.js';
1
2
  export type TokenWasteDecisionKind = 'include' | 'summarize' | 'exclude' | 'recommend' | 'avoid' | 'warn' | 'override';
2
3
  export type TokenWasteConfidence = 'high' | 'medium' | 'low';
3
4
  export type TokenWasteAction = string;
@@ -21,6 +22,7 @@ export interface TokenWasteOutputStrategy {
21
22
  keepFailures?: boolean;
22
23
  uniqueOnly?: boolean;
23
24
  summarizeKeys?: boolean;
25
+ maxSnippetChars?: number;
24
26
  }
25
27
  export interface TokenWastePolicy {
26
28
  version: 1;
@@ -35,6 +37,14 @@ export interface TokenWastePolicy {
35
37
  outputs: {
36
38
  strategies: Record<string, TokenWasteOutputStrategy>;
37
39
  };
40
+ contextArtifacts?: {
41
+ enabled: boolean;
42
+ ttlMs: number;
43
+ minTokens: number;
44
+ };
45
+ contentCompaction?: {
46
+ strategies: Record<string, TokenWasteOutputStrategy>;
47
+ };
38
48
  tools: {
39
49
  groups: Record<string, string[]>;
40
50
  maxRecommended: number;
@@ -83,12 +93,17 @@ export interface VerboseOutputInput {
83
93
  text: string;
84
94
  policy: TokenWastePolicy;
85
95
  fullOutputRef?: string;
96
+ projectPath?: string;
97
+ sourcePath?: string;
98
+ flow?: string;
99
+ metadata?: Record<string, unknown>;
86
100
  }
87
101
  export interface VerboseOutputResult {
88
102
  text: string;
89
103
  originalLines: number;
90
104
  returnedLines: number;
91
105
  fullOutputRef?: string;
106
+ compaction?: ContextArtifactCompactionMetadata;
92
107
  decisions: TokenWasteDecision[];
93
108
  }
94
109
  export interface ToolRelevanceInput {