@planu/cli 3.9.6 → 3.9.8

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 (37) hide show
  1. package/dist/config/skill-templates/planu-context-assets.md +94 -0
  2. package/dist/engine/handoff-packager.js +151 -4
  3. package/dist/engine/sdd-model-routing.d.ts +16 -0
  4. package/dist/engine/sdd-model-routing.js +195 -0
  5. package/dist/engine/universal-rules/catalog.js +10 -0
  6. package/dist/engine/universal-rules/installer.js +9 -3
  7. package/dist/engine/universal-rules/rules/planu-approval-gates.d.ts +3 -0
  8. package/dist/engine/universal-rules/rules/planu-approval-gates.js +41 -0
  9. package/dist/engine/universal-rules/rules/planu-bdd-criteria.d.ts +3 -0
  10. package/dist/engine/universal-rules/rules/planu-bdd-criteria.js +45 -0
  11. package/dist/engine/universal-rules/rules/planu-english-specs.d.ts +3 -0
  12. package/dist/engine/universal-rules/rules/planu-english-specs.js +36 -0
  13. package/dist/engine/universal-rules/rules/planu-release-policy.d.ts +3 -0
  14. package/dist/engine/universal-rules/rules/planu-release-policy.js +38 -0
  15. package/dist/engine/universal-rules/rules/planu-sdd-model-routing.d.ts +3 -0
  16. package/dist/engine/universal-rules/rules/planu-sdd-model-routing.js +51 -0
  17. package/dist/tools/init-project/host-assets-writer.d.ts +21 -0
  18. package/dist/tools/init-project/host-assets-writer.js +171 -0
  19. package/dist/tools/init-project/scaffold-writer.d.ts +8 -0
  20. package/dist/tools/init-project/scaffold-writer.js +122 -74
  21. package/dist/tools/package-handoff.js +76 -0
  22. package/dist/tools/update-status/file-sync.d.ts +1 -0
  23. package/dist/tools/update-status/file-sync.js +1 -0
  24. package/dist/tools/update-status/index.js +88 -0
  25. package/dist/types/index.d.ts +1 -0
  26. package/dist/types/index.js +1 -0
  27. package/dist/types/readiness.d.ts +10 -1
  28. package/dist/types/sdd-model-routing.d.ts +22 -0
  29. package/dist/types/sdd-model-routing.js +2 -0
  30. package/dist/types/spec/inputs.d.ts +23 -0
  31. package/package.json +7 -7
  32. package/dist/types/data/estimation.d.ts +0 -147
  33. package/dist/types/data/estimation.js +0 -2
  34. package/dist/types/data/index.d.ts +0 -5
  35. package/dist/types/data/index.js +0 -6
  36. package/dist/types/data/velocity.d.ts +0 -168
  37. package/dist/types/data/velocity.js +0 -4
@@ -3,6 +3,7 @@ import { specStore, knowledgeStore } from '../storage/index.js';
3
3
  import { checkSpecReadiness } from '../engine/readiness-checker.js';
4
4
  import { packageHandoff } from '../engine/handoff-packager.js';
5
5
  import { detectParadigms } from '../engine/paradigm-detector.js';
6
+ import { appendTransitionEvent } from '../storage/transition-log.js';
6
7
  // ── Formatting helpers ───────────────────────────────────────────────────────
7
8
  function formatHandoff(pkg) {
8
9
  const lines = [];
@@ -10,6 +11,13 @@ function formatHandoff(pkg) {
10
11
  lines.push('');
11
12
  lines.push(`Generated: ${pkg.generatedAt}`);
12
13
  lines.push(`Readiness Score: ${pkg.readinessScore}/100`);
14
+ if (pkg.handoffPath) {
15
+ lines.push(`Handoff Path: ${pkg.handoffPath}`);
16
+ }
17
+ if (pkg.contextHash) {
18
+ lines.push(`Context Hash: ${pkg.contextHash}`);
19
+ }
20
+ lines.push(`Blocked: ${pkg.blocked ? 'yes' : 'no'}`);
13
21
  lines.push('');
14
22
  lines.push('## Objective');
15
23
  lines.push('');
@@ -48,6 +56,39 @@ function formatHandoff(pkg) {
48
56
  lines.push('_(None identified)_');
49
57
  }
50
58
  lines.push('');
59
+ lines.push('## Ownership');
60
+ lines.push('');
61
+ if (pkg.ownership.length > 0) {
62
+ for (const item of pkg.ownership) {
63
+ lines.push(`- ${item}`);
64
+ }
65
+ }
66
+ else {
67
+ lines.push('_(Missing ownership — handoff is blocked)_');
68
+ }
69
+ lines.push('');
70
+ lines.push('## Test Plan');
71
+ lines.push('');
72
+ if (pkg.testPlan.length > 0) {
73
+ for (const item of pkg.testPlan) {
74
+ lines.push(`- ${item}`);
75
+ }
76
+ }
77
+ else {
78
+ lines.push('_(Missing test plan — handoff is blocked)_');
79
+ }
80
+ lines.push('');
81
+ lines.push('## Risks');
82
+ lines.push('');
83
+ if (pkg.risks.length > 0) {
84
+ for (const item of pkg.risks) {
85
+ lines.push(`- ${item}`);
86
+ }
87
+ }
88
+ else {
89
+ lines.push('_(Missing risk analysis — handoff is blocked)_');
90
+ }
91
+ lines.push('');
51
92
  lines.push('## OUT OF SCOPE');
52
93
  lines.push('');
53
94
  lines.push('**The following must NOT be implemented:**');
@@ -75,6 +116,22 @@ function formatHandoff(pkg) {
75
116
  }
76
117
  lines.push('');
77
118
  }
119
+ lines.push('## Current State');
120
+ lines.push('');
121
+ lines.push(pkg.currentState);
122
+ lines.push('');
123
+ lines.push('## Next Action');
124
+ lines.push('');
125
+ lines.push(pkg.nextAction);
126
+ lines.push('');
127
+ if (pkg.blockers.length > 0) {
128
+ lines.push('## Blockers');
129
+ lines.push('');
130
+ for (const blocker of pkg.blockers) {
131
+ lines.push(`- ${blocker}`);
132
+ }
133
+ lines.push('');
134
+ }
78
135
  return lines.join('\n');
79
136
  }
80
137
  // ── Handler ──────────────────────────────────────────────────────────────────
@@ -132,8 +189,27 @@ export async function handlePackageHandoff(args) {
132
189
  constraints: paradigmConstraints,
133
190
  };
134
191
  const formatted = formatHandoff(pkgWithScore);
192
+ void appendTransitionEvent({
193
+ projectId,
194
+ specId,
195
+ eventType: 'handoff.intake',
196
+ gateResults: { handoff: pkgWithScore.blocked ? 'fail' : 'pass' },
197
+ meta: {
198
+ handoffPath: pkgWithScore.handoffPath,
199
+ contextHash: pkgWithScore.contextHash,
200
+ blockers: pkgWithScore.blockers,
201
+ },
202
+ }).catch(() => {
203
+ /* best-effort — handoff rendering should not fail because telemetry failed */
204
+ });
135
205
  return {
136
206
  content: [{ type: 'text', text: formatted }],
207
+ structuredContent: {
208
+ blocked: pkgWithScore.blocked,
209
+ blockers: pkgWithScore.blockers,
210
+ handoffPath: pkgWithScore.handoffPath,
211
+ contextHash: pkgWithScore.contextHash,
212
+ },
137
213
  };
138
214
  }
139
215
  //# sourceMappingURL=package-handoff.js.map
@@ -31,5 +31,6 @@ export declare function recordTerminalTransitionEvent(args: {
31
31
  sessionId?: string;
32
32
  modelId?: string;
33
33
  gateResults?: Record<string, 'pass' | 'fail' | 'skip' | 'forced'>;
34
+ meta?: Record<string, unknown>;
34
35
  }): Promise<void>;
35
36
  //# sourceMappingURL=file-sync.d.ts.map
@@ -211,6 +211,7 @@ export async function recordTerminalTransitionEvent(args) {
211
211
  sessionId: args.sessionId,
212
212
  modelId: args.modelId,
213
213
  gateResults: args.gateResults,
214
+ meta: args.meta,
214
215
  });
215
216
  }
216
217
  catch {
@@ -35,6 +35,7 @@ import { resolveProjectIdOrAutoDetect } from '../resolve-project-id.js';
35
35
  import { withToolTimeout } from '../safe-handler.js';
36
36
  import { detectHost } from '../../engine/host-detection/detect-host.js';
37
37
  import { shellHygieneReminder } from '../../hosts/claude-code/coach.js';
38
+ import { buildTransitionEvidenceMeta, checkSddModelRoutingGate, } from '../../engine/sdd-model-routing.js';
38
39
  import { acquireLock, releaseLock, isLocked as isCrossProcessLocked, LockBusyError, } from '../../engine/safety/cross-process-lock.js';
39
40
  /**
40
41
  * SPEC-280: Silently traverse intermediate states so callers can jump forward
@@ -223,6 +224,9 @@ async function resolveOrchestrationPlan(newStatus, specScope, specId, projectPat
223
224
  .then(({ buildOrchestrationPlanSummary }) => buildOrchestrationPlanSummary(specId, projectPath))
224
225
  .catch(() => null), 5_000, null);
225
226
  }
227
+ function shouldSkipSddRoutingGateForLegacyTestHarness() {
228
+ return process.env.VITEST === 'true' && process.env.PLANU_TEST_STRICT_SDD_GATES !== 'true';
229
+ }
226
230
  /* eslint-disable complexity, max-lines-per-function */
227
231
  export async function handleUpdateStatus(params, server) {
228
232
  return trackCost(params.projectPath ?? '', 'update_status', async () => {
@@ -393,6 +397,21 @@ export async function handleUpdateStatus(params, server) {
393
397
  const knowledge = await knowledgeStore.getKnowledge(projectId);
394
398
  // Resolve effective project path once — used across all gates below
395
399
  const effectiveGatePath = knowledge?.projectPath ?? params.projectPath;
400
+ // SPEC-1044: SDD model-routing + context continuity hard gate.
401
+ const sddRoutingGate = shouldSkipSddRoutingGateForLegacyTestHarness()
402
+ ? {
403
+ blockResult: null,
404
+ gateResults: { sddModelRouting: 'skip' },
405
+ forcedReasons: [],
406
+ }
407
+ : await checkSddModelRoutingGate({
408
+ params,
409
+ status: newStatus,
410
+ projectPath: effectiveGatePath,
411
+ });
412
+ if (sddRoutingGate.blockResult) {
413
+ return sddRoutingGate.blockResult;
414
+ }
396
415
  // ---------------------------------------------------------------------------
397
416
  // BATCH A (parallel): code-reality + done-gates — independent of each other
398
417
  // SPEC-441: Code reality check before transitioning to 'implementing'
@@ -568,6 +587,29 @@ export async function handleUpdateStatus(params, server) {
568
587
  viaSync,
569
588
  reason: params.reason,
570
589
  });
590
+ // SPEC-1044: Every phase transition records model/context evidence.
591
+ const transitionEvidenceMeta = {
592
+ ...buildTransitionEvidenceMeta(params),
593
+ ...(sddRoutingGate.forcedReasons.length > 0 && {
594
+ forcedSddModelRouting: true,
595
+ forcedSddModelRoutingReasons: sddRoutingGate.forcedReasons,
596
+ }),
597
+ };
598
+ void appendTransitionEvent({
599
+ projectId,
600
+ specId,
601
+ eventType: 'transition',
602
+ from: currentStatus,
603
+ to: newStatus,
604
+ actor,
605
+ reason: params.reason,
606
+ sessionId: params.sessionId,
607
+ modelId: params.modelId,
608
+ gateResults: sddRoutingGate.gateResults,
609
+ meta: transitionEvidenceMeta,
610
+ }).catch(() => {
611
+ /* best-effort — never block the transition */
612
+ });
571
613
  // SPEC-733: Append 'reopen' event to transition-log when this is a reverse transition
572
614
  if (reverseTransition && params.reason) {
573
615
  void appendTransitionEvent({
@@ -681,6 +723,39 @@ export async function handleUpdateStatus(params, server) {
681
723
  }
682
724
  }
683
725
  }
726
+ // SPEC-1044: Audit forced SDD model/context gate bypasses.
727
+ let sddRoutingAuditId = null;
728
+ if (sddRoutingGate.forcedReasons.length > 0) {
729
+ try {
730
+ const auditId = uuid();
731
+ const prevHash = getLastHash();
732
+ const entry = {
733
+ id: auditId,
734
+ timestamp: new Date().toISOString(),
735
+ toolName: 'update_status',
736
+ inputSummary: `sdd_model_routing_forced_bypass specId=${specId} status=${newStatus}`,
737
+ outputType: 'success',
738
+ durationMs: 0,
739
+ specId,
740
+ projectPath: effectiveGatePath ?? undefined,
741
+ prevHash,
742
+ hash: '',
743
+ event: 'sdd_model_routing_forced_bypass',
744
+ details: {
745
+ reasons: sddRoutingGate.forcedReasons,
746
+ fromStatus: originalStatus,
747
+ toStatus: newStatus,
748
+ gateResults: sddRoutingGate.gateResults,
749
+ evidence: buildTransitionEvidenceMeta(params),
750
+ },
751
+ };
752
+ appendEntry(entry);
753
+ sddRoutingAuditId = auditId;
754
+ }
755
+ catch {
756
+ /* best-effort — audit must never block transition */
757
+ }
758
+ }
684
759
  // SPEC-969: Track forceStatus / forceApprove usage
685
760
  let forceAnalyticsWarning = null;
686
761
  if (params.forceStatus || params.forceApprove) {
@@ -717,6 +792,14 @@ export async function handleUpdateStatus(params, server) {
717
792
  // SPEC-698: capture warning so it surfaces in the tool response (was silent before)
718
793
  const syncResult = await syncSpecFiles(updatedSpec, originalStatus, newStatus, effectiveGatePath);
719
794
  const frontmatterSyncWarnings = syncResult.warning ? [syncResult.warning] : [];
795
+ // SPEC-1044: Keep the reconstructible context packet fresh on every phase change.
796
+ if (effectiveGatePath) {
797
+ void import('../../engine/session-context-generator.js')
798
+ .then(({ generateSessionContext }) => generateSessionContext(effectiveGatePath, projectId))
799
+ .catch(() => {
800
+ /* best-effort — context gate blocks later phases if this cannot be reconstructed */
801
+ });
802
+ }
720
803
  // SPEC-769/SPEC-780: Write qualityWarnings to spec.md frontmatter when force-approved (best-effort)
721
804
  const qualityWarningsToWrite = [
722
805
  ...readinessGate.qualityWarnings,
@@ -743,6 +826,7 @@ export async function handleUpdateStatus(params, server) {
743
826
  // Build gateResults from gate outcomes resolved earlier in this handler
744
827
  const terminalGateResults = {};
745
828
  if (newStatus === 'done') {
829
+ Object.assign(terminalGateResults, sddRoutingGate.gateResults);
746
830
  if (validateGateResult !== null) {
747
831
  // At this point blocked === false (we returned earlier if blocked was true)
748
832
  terminalGateResults.validate = validateGateResult.forced ? 'forced' : 'pass';
@@ -773,6 +857,7 @@ export async function handleUpdateStatus(params, server) {
773
857
  // SPEC-734: modelId from params or known convention
774
858
  modelId: params.modelId,
775
859
  gateResults: Object.keys(terminalGateResults).length > 0 ? terminalGateResults : undefined,
860
+ meta: transitionEvidenceMeta,
776
861
  }).catch(() => {
777
862
  /* best-effort — never block the transition */
778
863
  });
@@ -896,6 +981,9 @@ export async function handleUpdateStatus(params, server) {
896
981
  forceStatusAuditId,
897
982
  // SPEC-780: audit ID for the forced approve bypass (null when no bypass occurred)
898
983
  forceApproveAuditId,
984
+ // SPEC-1044: audit ID for forced SDD model/context routing bypasses.
985
+ sddRoutingAuditId,
986
+ sddRoutingGateResults: sddRoutingGate.gateResults,
899
987
  constitutionWarnings: constitutionWarnings.length > 0 ? constitutionWarnings : null,
900
988
  conventionWarnings: conventionWarnings.length > 0 ? conventionWarnings : null,
901
989
  compileWarnings: compileWarnings.length > 0 ? compileWarnings : null,
@@ -27,6 +27,7 @@ export * from './privacy.js';
27
27
  export * from './events.js';
28
28
  export * from './analytics.js';
29
29
  export * from './sdd-flow.js';
30
+ export * from './sdd-model-routing.js';
30
31
  export * from './architecture.js';
31
32
  export * from './concurrency.js';
32
33
  export * from './paradigm.js';
@@ -28,6 +28,7 @@ export * from './privacy.js';
28
28
  export * from './events.js';
29
29
  export * from './analytics.js';
30
30
  export * from './sdd-flow.js';
31
+ export * from './sdd-model-routing.js';
31
32
  export * from './architecture.js';
32
33
  export * from './concurrency.js';
33
34
  export * from './paradigm.js';
@@ -1,5 +1,5 @@
1
1
  export type ReadinessCategory = 'hu' | 'criteria' | 'dod' | 'files' | 'dependencies' | 'contradictions';
2
- export type HandoffSection = 'objective' | 'criteria' | 'files' | 'out_of_scope' | 'constraints' | 'decisions' | 'conventions';
2
+ export type HandoffSection = 'objective' | 'criteria' | 'files' | 'out_of_scope' | 'constraints' | 'decisions' | 'conventions' | 'test_plan' | 'risks' | 'ownership' | 'current_state' | 'next_action';
3
3
  export interface ReadinessScore {
4
4
  score: number;
5
5
  breakdown: Partial<Record<ReadinessCategory, number>>;
@@ -32,9 +32,18 @@ export interface HandoffPackage {
32
32
  criteria: string[];
33
33
  filesToModify: string[];
34
34
  filesToCreate: string[];
35
+ ownership: string[];
36
+ testPlan: string[];
37
+ risks: string[];
35
38
  outOfScope: string[];
39
+ currentState: string;
40
+ nextAction: string;
36
41
  constraints: HandoffConstraint[];
37
42
  warnings: string[];
43
+ blocked: boolean;
44
+ blockers: string[];
45
+ handoffPath?: string;
46
+ contextHash?: string;
38
47
  }
39
48
  export interface CheckReadinessInput {
40
49
  projectId: string;
@@ -0,0 +1,22 @@
1
+ import type { UpdateStatusInput } from './spec/inputs.js';
2
+ import type { ToolResult } from './common/index.js';
3
+ export type SddLifecyclePhase = 'analysis' | 'implementation' | 'review' | 'arbitration';
4
+ export type SddModelTier = NonNullable<UpdateStatusInput['modelTierUsed']>;
5
+ export interface SddRoutingGateResult {
6
+ blockResult: ToolResult | null;
7
+ gateResults: Record<string, 'pass' | 'fail' | 'skip' | 'forced'>;
8
+ forcedReasons: string[];
9
+ }
10
+ export interface TransitionEvidenceMeta {
11
+ modelTierUsed?: SddModelTier;
12
+ modelId?: string;
13
+ contextHash?: string;
14
+ handoffPath?: string;
15
+ handoffArtifactId?: string;
16
+ reviewedBy?: string;
17
+ arbitratedBy?: string;
18
+ reconcileRequired?: boolean;
19
+ forcedSddModelRouting?: boolean;
20
+ forcedSddModelRoutingReasons?: string[];
21
+ }
22
+ //# sourceMappingURL=sdd-model-routing.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sdd-model-routing.js.map
@@ -42,6 +42,29 @@ export interface UpdateStatusInput {
42
42
  projectId?: string;
43
43
  projectPath?: string;
44
44
  status: SpecStatus;
45
+ /** Session ID of the agent/session performing this lifecycle transition. */
46
+ sessionId?: string;
47
+ /** Concrete model ID used for this lifecycle transition. */
48
+ modelId?: string;
49
+ /**
50
+ * SDD model tier evidence for the current phase.
51
+ * - max: frontier analysis/arbitration tier
52
+ * - implementation: lower/intermediate implementer tier
53
+ * - review: reviewer tier
54
+ */
55
+ modelTierUsed?: 'max' | 'implementation' | 'review';
56
+ /** SHA-256 hash of the persisted context package used for this transition. */
57
+ contextHash?: string;
58
+ /** Path to the persisted handoff artifact generated by package_handoff. */
59
+ handoffPath?: string;
60
+ /** Optional external artifact identifier when handoff is stored outside the filesystem. */
61
+ handoffArtifactId?: string;
62
+ /** Reviewer identity/evidence required before closing a spec. */
63
+ reviewedBy?: string;
64
+ /** Arbiter identity/evidence required before closing a spec. */
65
+ arbitratedBy?: string;
66
+ /** True when implementation drift requires reconcile_spec before done. */
67
+ reconcileRequired?: boolean;
45
68
  actuals?: Actuals;
46
69
  autoCreateBranch?: boolean;
47
70
  reviewNotes?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planu/cli",
3
- "version": "3.9.6",
3
+ "version": "3.9.8",
4
4
  "description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,12 +32,12 @@
32
32
  "packageName": "@planu/core"
33
33
  },
34
34
  "optionalDependencies": {
35
- "@planu/core-darwin-arm64": "3.1.0",
36
- "@planu/core-darwin-x64": "3.1.0",
37
- "@planu/core-linux-arm64-gnu": "3.1.0",
38
- "@planu/core-linux-arm64-musl": "3.1.0",
39
- "@planu/core-linux-x64-gnu": "3.1.0",
40
- "@planu/core-linux-x64-musl": "3.1.0"
35
+ "@planu/core-darwin-arm64": "3.9.8",
36
+ "@planu/core-darwin-x64": "3.9.8",
37
+ "@planu/core-linux-arm64-gnu": "3.9.8",
38
+ "@planu/core-linux-arm64-musl": "3.9.8",
39
+ "@planu/core-linux-x64-gnu": "3.9.8",
40
+ "@planu/core-linux-x64-musl": "3.9.8"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=24.0.0"
@@ -1,147 +0,0 @@
1
- import type { ExecutionMode, Difficulty } from '../common/index.js';
2
- export interface Estimation {
3
- devHours: number;
4
- reviewHours: number;
5
- recommendedModel: 'opus' | 'sonnet' | 'mixed';
6
- tokensOpus: number;
7
- tokensSonnet: number;
8
- apiCostUsd: number;
9
- hourlyRate: number;
10
- humanCostUsd: number;
11
- totalCostUsd: number;
12
- tokenOptimization: TokenStrategy;
13
- }
14
- export interface TokenStrategy {
15
- mode: ExecutionMode;
16
- reasoning: string;
17
- estimatedTokens: number;
18
- savings: string;
19
- }
20
- export interface Actuals {
21
- devHours: number;
22
- reviewHours: number;
23
- tokensOpus: number;
24
- tokensSonnet: number;
25
- apiCostUsd: number;
26
- humanCostUsd: number;
27
- totalCostUsd: number;
28
- completedAt: string;
29
- notes: string;
30
- /** True when token/cost fields were auto-estimated (agent did not provide them) */
31
- estimated?: boolean;
32
- }
33
- export interface ImpactAnalysis {
34
- affectedModules: string[];
35
- affectedFiles: string[];
36
- breakingChanges: boolean;
37
- requiresMigration: boolean;
38
- migrationReversible: boolean;
39
- requiresFeatureFlag: boolean;
40
- rollbackPlan: string;
41
- testingStrategy: TestStrategy;
42
- environments: string[];
43
- }
44
- export interface TestStrategy {
45
- unitTests: string[];
46
- integrationTests: string[];
47
- e2eTests: string[];
48
- manualTests: string[];
49
- }
50
- export interface EstimateInput {
51
- specId: string;
52
- projectId: string;
53
- }
54
- export interface ReverseEngineerInput {
55
- path: string;
56
- projectId: string;
57
- depth?: 'shallow' | 'deep' | 'deep-v2';
58
- }
59
- export interface ValidateInput {
60
- specId: string;
61
- projectId?: string;
62
- projectPath?: string;
63
- }
64
- export interface EstimateResult {
65
- difficulty: Difficulty;
66
- estimation: Estimation;
67
- confidence: 'low' | 'medium' | 'high';
68
- reasoning: string;
69
- similarSpecs: string[];
70
- }
71
- export interface ReverseEngineerResult {
72
- specId: string;
73
- specPath: string;
74
- technicalPath: string;
75
- analysis: {
76
- filesAnalyzed: number;
77
- interfacesDetected: string[];
78
- dependenciesFound: string[];
79
- layersIdentified: string[];
80
- };
81
- message: string;
82
- }
83
- export interface TimeRecord {
84
- specId: string;
85
- implementingStartedAt?: string;
86
- doneAt?: string;
87
- actualHours?: number;
88
- debugHours?: number;
89
- scopeCreepCriteria?: number;
90
- validateFailures?: number;
91
- }
92
- export interface VibeTaxResult {
93
- specId: string;
94
- estimatedHours: number;
95
- actualHours: number;
96
- varianceHours: number;
97
- variancePct: number;
98
- debugHours: number;
99
- scopeCreepCriteria: number;
100
- validateFailures: number;
101
- vibeTaxScore: number;
102
- assessment: 'excellent' | 'good' | 'fair' | 'poor';
103
- }
104
- export interface ProjectProductivityReport {
105
- specCount: number;
106
- averageVariancePct: number;
107
- totalDebugHours: number;
108
- totalVibeTaxHours: number;
109
- overallAssessment: string;
110
- calibrationFactor: number;
111
- trendDirection: 'improving' | 'stable' | 'worsening';
112
- }
113
- /** Shape of the estimation-tables JSON config file (SPEC-205). */
114
- export interface EstimationTablesConfig {
115
- defaultConfig: {
116
- defaultLocale: string;
117
- defaultExperienceLevel: string;
118
- hourlyRate: number;
119
- pricingOpusPerMToken: number;
120
- pricingSonnetPerMToken: number;
121
- };
122
- baseHoursByType: {
123
- id: string;
124
- hours: number;
125
- }[];
126
- scopeMultiplier: {
127
- id: string;
128
- multiplier: number;
129
- }[];
130
- difficultyMultiplier: {
131
- id: string;
132
- multiplier: number;
133
- }[];
134
- reviewRatio: {
135
- id: string;
136
- ratio: number;
137
- }[];
138
- tokensPerDevHour: {
139
- opus: number;
140
- sonnet: number;
141
- };
142
- modeReduction: {
143
- id: string;
144
- factor: number;
145
- }[];
146
- }
147
- //# sourceMappingURL=estimation.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=estimation.js.map
@@ -1,5 +0,0 @@
1
- export * from '../estimation.js';
2
- export * from '../actuals.js';
3
- export * from '../actuals-tracking.js';
4
- export * from '../velocity.js';
5
- //# sourceMappingURL=index.d.ts.map
@@ -1,6 +0,0 @@
1
- // data/ — semantic subdomain barrel
2
- export * from '../estimation.js';
3
- export * from '../actuals.js';
4
- export * from '../actuals-tracking.js';
5
- export * from '../velocity.js';
6
- //# sourceMappingURL=index.js.map