@encore-os/eos-spec 0.3.1
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/LICENSE +17 -0
- package/bin/check-dist-fresh.js +51 -0
- package/bin/eos-spec.js +7 -0
- package/dist/commands/ac-backfill.d.ts +31 -0
- package/dist/commands/ac-backfill.js +198 -0
- package/dist/commands/ac-backfill.js.map +1 -0
- package/dist/commands/archive.d.ts +2 -0
- package/dist/commands/archive.js +101 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/audit.d.ts +30 -0
- package/dist/commands/audit.js +107 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/backfill.d.ts +41 -0
- package/dist/commands/backfill.js +239 -0
- package/dist/commands/backfill.js.map +1 -0
- package/dist/commands/checkArtifacts.d.ts +2 -0
- package/dist/commands/checkArtifacts.js +48 -0
- package/dist/commands/checkArtifacts.js.map +1 -0
- package/dist/commands/checkPlacement.d.ts +2 -0
- package/dist/commands/checkPlacement.js +31 -0
- package/dist/commands/checkPlacement.js.map +1 -0
- package/dist/commands/claim.d.ts +4 -0
- package/dist/commands/claim.js +46 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/complete.d.ts +2 -0
- package/dist/commands/complete.js +138 -0
- package/dist/commands/complete.js.map +1 -0
- package/dist/commands/conformance.d.ts +23 -0
- package/dist/commands/conformance.js +124 -0
- package/dist/commands/conformance.js.map +1 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.js +277 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/deferred.d.ts +2 -0
- package/dist/commands/deferred.js +85 -0
- package/dist/commands/deferred.js.map +1 -0
- package/dist/commands/delta.d.ts +17 -0
- package/dist/commands/delta.js +292 -0
- package/dist/commands/delta.js.map +1 -0
- package/dist/commands/freshness.d.ts +13 -0
- package/dist/commands/freshness.js +72 -0
- package/dist/commands/freshness.js.map +1 -0
- package/dist/commands/funnel.d.ts +2 -0
- package/dist/commands/funnel.js +61 -0
- package/dist/commands/funnel.js.map +1 -0
- package/dist/commands/gen-tests.d.ts +2 -0
- package/dist/commands/gen-tests.js +53 -0
- package/dist/commands/gen-tests.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +64 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +9 -0
- package/dist/commands/list.js +61 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/metrics.d.ts +2 -0
- package/dist/commands/metrics.js +66 -0
- package/dist/commands/metrics.js.map +1 -0
- package/dist/commands/next.d.ts +48 -0
- package/dist/commands/next.js +344 -0
- package/dist/commands/next.js.map +1 -0
- package/dist/commands/precedent.d.ts +66 -0
- package/dist/commands/precedent.js +343 -0
- package/dist/commands/precedent.js.map +1 -0
- package/dist/commands/ready.d.ts +28 -0
- package/dist/commands/ready.js +147 -0
- package/dist/commands/ready.js.map +1 -0
- package/dist/commands/reconcile.d.ts +44 -0
- package/dist/commands/reconcile.js +187 -0
- package/dist/commands/reconcile.js.map +1 -0
- package/dist/commands/rollup.d.ts +2 -0
- package/dist/commands/rollup.js +43 -0
- package/dist/commands/rollup.js.map +1 -0
- package/dist/commands/scorecard.d.ts +11 -0
- package/dist/commands/scorecard.js +55 -0
- package/dist/commands/scorecard.js.map +1 -0
- package/dist/commands/signoff.d.ts +2 -0
- package/dist/commands/signoff.js +114 -0
- package/dist/commands/signoff.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +100 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tasks.d.ts +13 -0
- package/dist/commands/tasks.js +81 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/commands/validate.d.ts +16 -0
- package/dist/commands/validate.js +89 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/verify-acs.d.ts +15 -0
- package/dist/commands/verify-acs.js +196 -0
- package/dist/commands/verify-acs.js.map +1 -0
- package/dist/commands/verifyRollout.d.ts +2 -0
- package/dist/commands/verifyRollout.js +125 -0
- package/dist/commands/verifyRollout.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +138 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/ac-draft-prompt.d.ts +18 -0
- package/dist/lib/ac-draft-prompt.js +38 -0
- package/dist/lib/ac-draft-prompt.js.map +1 -0
- package/dist/lib/ac-response-parser.d.ts +18 -0
- package/dist/lib/ac-response-parser.js +57 -0
- package/dist/lib/ac-response-parser.js.map +1 -0
- package/dist/lib/ai-call.d.ts +13 -0
- package/dist/lib/ai-call.js +17 -0
- package/dist/lib/ai-call.js.map +1 -0
- package/dist/lib/archive.d.ts +21 -0
- package/dist/lib/archive.js +136 -0
- package/dist/lib/archive.js.map +1 -0
- package/dist/lib/artifact-integrity.d.ts +5 -0
- package/dist/lib/artifact-integrity.js +65 -0
- package/dist/lib/artifact-integrity.js.map +1 -0
- package/dist/lib/backfill-queue.d.ts +11 -0
- package/dist/lib/backfill-queue.js +14 -0
- package/dist/lib/backfill-queue.js.map +1 -0
- package/dist/lib/blockers.d.ts +66 -0
- package/dist/lib/blockers.js +103 -0
- package/dist/lib/blockers.js.map +1 -0
- package/dist/lib/claims.d.ts +39 -0
- package/dist/lib/claims.js +133 -0
- package/dist/lib/claims.js.map +1 -0
- package/dist/lib/classify-debt.d.ts +17 -0
- package/dist/lib/classify-debt.js +13 -0
- package/dist/lib/classify-debt.js.map +1 -0
- package/dist/lib/code-evidence.d.ts +35 -0
- package/dist/lib/code-evidence.js +171 -0
- package/dist/lib/code-evidence.js.map +1 -0
- package/dist/lib/coherence.d.ts +14 -0
- package/dist/lib/coherence.js +188 -0
- package/dist/lib/coherence.js.map +1 -0
- package/dist/lib/completion-gate.d.ts +17 -0
- package/dist/lib/completion-gate.js +28 -0
- package/dist/lib/completion-gate.js.map +1 -0
- package/dist/lib/compliance-signoff.d.ts +39 -0
- package/dist/lib/compliance-signoff.js +81 -0
- package/dist/lib/compliance-signoff.js.map +1 -0
- package/dist/lib/config.d.ts +63 -0
- package/dist/lib/config.js +40 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/cost.d.ts +12 -0
- package/dist/lib/cost.js +12 -0
- package/dist/lib/cost.js.map +1 -0
- package/dist/lib/debt-dashboard.d.ts +25 -0
- package/dist/lib/debt-dashboard.js +36 -0
- package/dist/lib/debt-dashboard.js.map +1 -0
- package/dist/lib/embedding-store.d.ts +103 -0
- package/dist/lib/embedding-store.js +133 -0
- package/dist/lib/embedding-store.js.map +1 -0
- package/dist/lib/embeddings-source.d.ts +36 -0
- package/dist/lib/embeddings-source.js +62 -0
- package/dist/lib/embeddings-source.js.map +1 -0
- package/dist/lib/enforcement-allowlist.d.ts +12 -0
- package/dist/lib/enforcement-allowlist.js +25 -0
- package/dist/lib/enforcement-allowlist.js.map +1 -0
- package/dist/lib/events.d.ts +47 -0
- package/dist/lib/events.js +75 -0
- package/dist/lib/events.js.map +1 -0
- package/dist/lib/exec.d.ts +8 -0
- package/dist/lib/exec.js +25 -0
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +112 -0
- package/dist/lib/frontmatter.js +261 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/funnel.d.ts +22 -0
- package/dist/lib/funnel.js +41 -0
- package/dist/lib/funnel.js.map +1 -0
- package/dist/lib/git-mtime.d.ts +4 -0
- package/dist/lib/git-mtime.js +23 -0
- package/dist/lib/git-mtime.js.map +1 -0
- package/dist/lib/metrics.d.ts +42 -0
- package/dist/lib/metrics.js +92 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/migration-collision.d.ts +20 -0
- package/dist/lib/migration-collision.js +61 -0
- package/dist/lib/migration-collision.js.map +1 -0
- package/dist/lib/next-action.d.ts +44 -0
- package/dist/lib/next-action.js +138 -0
- package/dist/lib/next-action.js.map +1 -0
- package/dist/lib/ollama-embed.d.ts +21 -0
- package/dist/lib/ollama-embed.js +65 -0
- package/dist/lib/ollama-embed.js.map +1 -0
- package/dist/lib/output.d.ts +35 -0
- package/dist/lib/output.js +46 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pipeline-config.d.ts +20 -0
- package/dist/lib/pipeline-config.js +208 -0
- package/dist/lib/pipeline-config.js.map +1 -0
- package/dist/lib/pipeline-map.d.ts +68 -0
- package/dist/lib/pipeline-map.js +256 -0
- package/dist/lib/pipeline-map.js.map +1 -0
- package/dist/lib/pipeline-schema.d.ts +48 -0
- package/dist/lib/pipeline-schema.js +22 -0
- package/dist/lib/pipeline-schema.js.map +1 -0
- package/dist/lib/placement.d.ts +6 -0
- package/dist/lib/placement.js +40 -0
- package/dist/lib/placement.js.map +1 -0
- package/dist/lib/precedent-search.d.ts +18 -0
- package/dist/lib/precedent-search.js +160 -0
- package/dist/lib/precedent-search.js.map +1 -0
- package/dist/lib/predicate-registry.d.ts +6 -0
- package/dist/lib/predicate-registry.js +40 -0
- package/dist/lib/predicate-registry.js.map +1 -0
- package/dist/lib/recall-cases.d.ts +15 -0
- package/dist/lib/recall-cases.js +39 -0
- package/dist/lib/recall-cases.js.map +1 -0
- package/dist/lib/repo.d.ts +20 -0
- package/dist/lib/repo.js +82 -0
- package/dist/lib/repo.js.map +1 -0
- package/dist/lib/requirements.d.ts +91 -0
- package/dist/lib/requirements.js +179 -0
- package/dist/lib/requirements.js.map +1 -0
- package/dist/lib/rollup.d.ts +24 -0
- package/dist/lib/rollup.js +34 -0
- package/dist/lib/rollup.js.map +1 -0
- package/dist/lib/scorecard-run.d.ts +6 -0
- package/dist/lib/scorecard-run.js +48 -0
- package/dist/lib/scorecard-run.js.map +1 -0
- package/dist/lib/scorecard.d.ts +69 -0
- package/dist/lib/scorecard.js +113 -0
- package/dist/lib/scorecard.js.map +1 -0
- package/dist/lib/semantic-search.d.ts +36 -0
- package/dist/lib/semantic-search.js +56 -0
- package/dist/lib/semantic-search.js.map +1 -0
- package/dist/lib/session-state.d.ts +8 -0
- package/dist/lib/session-state.js +25 -0
- package/dist/lib/session-state.js.map +1 -0
- package/dist/lib/spec-debt.d.ts +8 -0
- package/dist/lib/spec-debt.js +17 -0
- package/dist/lib/spec-debt.js.map +1 -0
- package/dist/lib/spec-pure.d.ts +59 -0
- package/dist/lib/spec-pure.js +215 -0
- package/dist/lib/spec-pure.js.map +1 -0
- package/dist/lib/specs.d.ts +148 -0
- package/dist/lib/specs.js +373 -0
- package/dist/lib/specs.js.map +1 -0
- package/dist/lib/test-generator.d.ts +5 -0
- package/dist/lib/test-generator.js +72 -0
- package/dist/lib/test-generator.js.map +1 -0
- package/dist/lib/user-stories.d.ts +6 -0
- package/dist/lib/user-stories.js +56 -0
- package/dist/lib/user-stories.js.map +1 -0
- package/dist/lib/verifies-scan.d.ts +9 -0
- package/dist/lib/verifies-scan.js +73 -0
- package/dist/lib/verifies-scan.js.map +1 -0
- package/dist/lib/verify-core.d.ts +23 -0
- package/dist/lib/verify-core.js +48 -0
- package/dist/lib/verify-core.js.map +1 -0
- package/dist/lib/with-event-log.d.ts +12 -0
- package/dist/lib/with-event-log.js +65 -0
- package/dist/lib/with-event-log.js.map +1 -0
- package/dist/lib/wizard-specs.d.ts +17 -0
- package/dist/lib/wizard-specs.js +34 -0
- package/dist/lib/wizard-specs.js.map +1 -0
- package/dist/pure.d.ts +19 -0
- package/dist/pure.js +31 -0
- package/dist/pure.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../src/lib/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,OAAO,GAAG,4DAA4D,CAAC;AAC7E,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAEpD,gGAAgG;AAChG,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;AACzE,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,iBAAiB,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-spec verification-debt flag (A7): true when the spec CLAIMS complete but has zero
|
|
3
|
+
* @verifies-backed requirements — the scorecard's `claimedCompleteButUnverified` column for
|
|
4
|
+
* one id. Reuses buildScorecardForCore + scanVerifies (the same machinery `eos-spec scorecard`
|
|
5
|
+
* runs) rather than re-deriving the predicate, so `next`/`status` and the scorecard never drift.
|
|
6
|
+
* Returns false for an unknown id (no row).
|
|
7
|
+
*/
|
|
8
|
+
export declare function isClaimedCompleteUnverified(repoRoot: string, specId: string): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { buildScorecardForCore } from './scorecard-run.js';
|
|
2
|
+
import { scanVerifies } from './verifies-scan.js';
|
|
3
|
+
/**
|
|
4
|
+
* Single-spec verification-debt flag (A7): true when the spec CLAIMS complete but has zero
|
|
5
|
+
* @verifies-backed requirements — the scorecard's `claimedCompleteButUnverified` column for
|
|
6
|
+
* one id. Reuses buildScorecardForCore + scanVerifies (the same machinery `eos-spec scorecard`
|
|
7
|
+
* runs) rather than re-deriving the predicate, so `next`/`status` and the scorecard never drift.
|
|
8
|
+
* Returns false for an unknown id (no row).
|
|
9
|
+
*/
|
|
10
|
+
export function isClaimedCompleteUnverified(repoRoot, specId) {
|
|
11
|
+
const core = specId.split('-')[0]?.toLowerCase();
|
|
12
|
+
const verifiedBySpec = scanVerifies(repoRoot);
|
|
13
|
+
const report = buildScorecardForCore(repoRoot, core, verifiedBySpec);
|
|
14
|
+
const row = report.rows.find((r) => r.id.toUpperCase() === specId.toUpperCase());
|
|
15
|
+
return row?.claimedCompleteButUnverified ?? false;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=spec-debt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-debt.js","sourceRoot":"","sources":["../../src/lib/spec-debt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,QAAgB,EAAE,MAAc;IAC1E,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;IACjD,MAAM,cAAc,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,qBAAqB,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACjF,OAAO,GAAG,EAAE,4BAA4B,IAAI,KAAK,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SpecSignals } from './specs.js';
|
|
2
|
+
/** Cores requiring regulatory grounding + compliance review. */
|
|
3
|
+
export declare const REGULATED_CORES: Set<string>;
|
|
4
|
+
/** True when a generated test source has ≥1 ACTIVE `test(` block (not `test.fixme`/
|
|
5
|
+
* `test.describe`) and is not an AC-less placeholder. Pure (operates on source text). */
|
|
6
|
+
export declare function hasActiveGeneratedTestSource(source: string): boolean;
|
|
7
|
+
/** File-existence + fs-derived flags `deriveSignalsFromText` cannot compute from
|
|
8
|
+
* content alone; the fs-bound `deriveSignals` (specs.ts) supplies them, a browser
|
|
9
|
+
* consumer passes what it knows (e.g. `reviewFileExists`) and the rest default false. */
|
|
10
|
+
export type SpecSignalFlags = {
|
|
11
|
+
researchFileExists?: boolean;
|
|
12
|
+
reviewFileExists?: boolean;
|
|
13
|
+
generatedTestExists?: boolean;
|
|
14
|
+
complianceSignoffFileExists?: boolean;
|
|
15
|
+
docshotImageExists?: boolean;
|
|
16
|
+
activeGeneratedTests?: boolean;
|
|
17
|
+
isCreateWizardSpec?: boolean;
|
|
18
|
+
submitE2eProvesPersist?: boolean;
|
|
19
|
+
linkedLocalTestExists?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Derive a spec's pipeline signals from its core + raw markdown text, using only
|
|
23
|
+
* content (frontmatter + body regexes) plus the caller-supplied file-existence
|
|
24
|
+
* flags. The single source of truth for signal derivation: the fs-bound
|
|
25
|
+
* `deriveSignals` in specs.ts is a thin positional-args adapter over this.
|
|
26
|
+
*/
|
|
27
|
+
export declare function deriveSignalsFromText(core: string, text: string, flags?: SpecSignalFlags): SpecSignals;
|
|
28
|
+
/**
|
|
29
|
+
* The spec id parsed from `filename`, anchored to the EXACT `core` (any length).
|
|
30
|
+
* The id grammar is `{core}[-{SUB}]-{num}[.{minor}][-{EN-n|En|Pn[.n][-EN-n]}]`,
|
|
31
|
+
* matched case-insensitively. Anchoring to the literal core (instead of a generic
|
|
32
|
+
* `[A-Z]{2,N}` class + `startsWith`) is what lets the same helper serve encoreos's
|
|
33
|
+
* 2-char cores (PF/CE) AND builder's longer cores (RUNNER, tool) without
|
|
34
|
+
* over-crediting a foreign id (e.g. `FARM-12` is never read as core `fa`). Proven
|
|
35
|
+
* zero-diff against all 1287 encoreos spec files and 50/50 on the builder corpus
|
|
36
|
+
* (epic #300, Wave-1 G3).
|
|
37
|
+
*/
|
|
38
|
+
export declare function extractSpecId(filename: string, core: string): string | null;
|
|
39
|
+
/** A `{ID}-PHASE…` lifecycle file. `[A-Z]{2,6}` so it skips builder phase files
|
|
40
|
+
* (e.g. `RUNNER-…-PHASE2-…`) as well as encoreos's 2–3-char cores. */
|
|
41
|
+
export declare function isPhaseLifecycleFile(filename: string): boolean;
|
|
42
|
+
export declare function isLifecycleArtifact(filename: string): boolean;
|
|
43
|
+
/** True when a filename + its containing dir indicate a derivative artifact, not a primary spec. */
|
|
44
|
+
export declare function isDerivativeArtifact(dirName: string, filename: string): boolean;
|
|
45
|
+
/** The skip rules `collectSpecsFromDirectory` applies to one filename. */
|
|
46
|
+
export declare function isPrimarySpecFile(filename: string): boolean;
|
|
47
|
+
/** True when a repo-relative path is a primary spec directly under specs/{core}/specs|ux/. */
|
|
48
|
+
export declare function isPrimarySpecPath(path: string): boolean;
|
|
49
|
+
/** The spec id for a primary spec path, or null if the path isn't a primary spec. */
|
|
50
|
+
export declare function specIdForPath(path: string): string | null;
|
|
51
|
+
/** Deterministic winner (path-sorted, mirroring the CLI's findSpec) for a spec id among `allPaths`. */
|
|
52
|
+
export declare function findSpecPath(specId: string, allPaths: string[]): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Path-Set equivalent of specs.ts's `hasArtifact`/`resolveArtifactPath`: is there a
|
|
55
|
+
* `specs/{core}/{folder}/{id}-{suffix}.md` (flat dir only) in `paths`? A child
|
|
56
|
+
* sub-spec's artifact (`{id}-EN-01-TASKS.md`, `{id}-P2-TASKS.md`) must not credit
|
|
57
|
+
* the parent id — same boundary rule the fs walker uses.
|
|
58
|
+
*/
|
|
59
|
+
export declare function hasArtifactInPaths(paths: Set<string>, core: string, folder: 'plans' | 'tasks', id: string, suffix: string): boolean;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, fs-free spec helpers — the browser-safe core a client (e.g. Spec Studio)
|
|
3
|
+
* can import without pulling node:fs / child_process. Everything here takes spec
|
|
4
|
+
* CONTENT and PATH STRINGS (or a Set of paths), never reads the filesystem, so it
|
|
5
|
+
* is re-exported from `/pure` and guarded by `pure-purity.test.ts`.
|
|
6
|
+
*
|
|
7
|
+
* `specs.ts` (the fs-bound corpus walker) DELEGATES to these: `deriveSignals`
|
|
8
|
+
* calls `deriveSignalsFromText`, and the path classifiers / artifact-existence
|
|
9
|
+
* checks are the single source of truth re-exported from there. That keeps the
|
|
10
|
+
* fs and browser code paths from drifting — the whole reason this module exists.
|
|
11
|
+
*
|
|
12
|
+
* The `import type` of `SpecSignals` from the fs-bound `specs.ts` is erased by
|
|
13
|
+
* tsc, so it does NOT pull specs.ts into the `/pure` runtime closure (asserted by
|
|
14
|
+
* pure-purity.test.ts).
|
|
15
|
+
*/
|
|
16
|
+
import { collectSpecIds } from './blockers.js';
|
|
17
|
+
import { readFrontmatter } from './frontmatter.js';
|
|
18
|
+
import { acStatusCounts, allAcceptanceCriteriaTerminal } from './requirements.js';
|
|
19
|
+
/** Cores requiring regulatory grounding + compliance review. */
|
|
20
|
+
export const REGULATED_CORES = new Set(['cl', 'pm', 'hr', 'rh', 'gr']);
|
|
21
|
+
/** The marker the generator emits for an AC-less spec. */
|
|
22
|
+
const GENERATED_NO_AC_MARKER = 'no acceptance_criteria — run encore-spec-ac-draft first';
|
|
23
|
+
/** True when a generated test source has ≥1 ACTIVE `test(` block (not `test.fixme`/
|
|
24
|
+
* `test.describe`) and is not an AC-less placeholder. Pure (operates on source text). */
|
|
25
|
+
export function hasActiveGeneratedTestSource(source) {
|
|
26
|
+
if (source.includes(GENERATED_NO_AC_MARKER))
|
|
27
|
+
return false;
|
|
28
|
+
const withoutLineComments = source.replace(/\/\/[^\n]*/g, '');
|
|
29
|
+
return /(?<![.\w])test\s*\(/.test(withoutLineComments);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Derive a spec's pipeline signals from its core + raw markdown text, using only
|
|
33
|
+
* content (frontmatter + body regexes) plus the caller-supplied file-existence
|
|
34
|
+
* flags. The single source of truth for signal derivation: the fs-bound
|
|
35
|
+
* `deriveSignals` in specs.ts is a thin positional-args adapter over this.
|
|
36
|
+
*/
|
|
37
|
+
export function deriveSignalsFromText(core, text, flags = {}) {
|
|
38
|
+
const { researchFileExists = false, reviewFileExists = false, generatedTestExists = false, complianceSignoffFileExists = false, docshotImageExists = false, activeGeneratedTests = false, isCreateWizardSpec = false, submitE2eProvesPersist = false, linkedLocalTestExists = false, } = flags;
|
|
39
|
+
const fm = readFrontmatter(text);
|
|
40
|
+
const nonEmptyArray = (v) => Array.isArray(v) && v.length > 0;
|
|
41
|
+
const hasUserStoriesSection = /^#{1,3}\s+User Stories\b/im.test(text);
|
|
42
|
+
const affectedFiles = Array.isArray(fm.affected_files) ? fm.affected_files.map(String) : [];
|
|
43
|
+
const uiAffectedFiles = affectedFiles.some((f) => /\/(components|pages|wizards)\//.test(f) || f.endsWith('.tsx'));
|
|
44
|
+
return {
|
|
45
|
+
isRegulated: REGULATED_CORES.has(core.toLowerCase()),
|
|
46
|
+
pipelineStatus: typeof fm.pipeline_status === 'string' ? fm.pipeline_status : undefined,
|
|
47
|
+
hasResearch: researchFileExists || typeof fm.research_appendix === 'string',
|
|
48
|
+
hasAcceptanceCriteria: nonEmptyArray(fm.acceptance_criteria),
|
|
49
|
+
hasVerifiedAcceptanceCriteria: allAcceptanceCriteriaTerminal(fm.acceptance_criteria),
|
|
50
|
+
hasLinkedLocalTest: nonEmptyArray(fm.e2e_tests) && linkedLocalTestExists,
|
|
51
|
+
hasUserStories: nonEmptyArray(fm.user_stories) || hasUserStoriesSection,
|
|
52
|
+
hasGeneratedTests: nonEmptyArray(fm.e2e_tests) || generatedTestExists,
|
|
53
|
+
hasActiveGeneratedTests: activeGeneratedTests,
|
|
54
|
+
hasSeedFixture: /tests\/fixtures\/[a-z0-9-]+\/[A-Za-z0-9]+Seed\.ts/.test(text),
|
|
55
|
+
hasSpecReview: reviewFileExists || /<!--\s*spec-reviewed:/i.test(text),
|
|
56
|
+
hasValidationSignoff: /<!--\s*validated:/i.test(text),
|
|
57
|
+
hasComplianceSignoff: complianceSignoffFileExists || /<!--\s*compliance-reviewed:/i.test(text),
|
|
58
|
+
hasUxSignoff: /<!--\s*ux-reviewed:/i.test(text),
|
|
59
|
+
isUiBearing: uiAffectedFiles || /^#{1,3}\s*UI\s*\/?\s*UX\b/im.test(text),
|
|
60
|
+
hasDocshots: docshotImageExists || /-docs-shots\.spec\.ts/.test(text) || /<!--\s*docshots:/i.test(text),
|
|
61
|
+
hasHealSignoff: /<!--\s*heal-verified:/i.test(text),
|
|
62
|
+
hasUiGateWaiver: /<!--\s*ui-gate-waived:/i.test(text),
|
|
63
|
+
isCreateWizardSpec,
|
|
64
|
+
hasSubmitE2e: submitE2eProvesPersist || /<!--\s*submit-e2e-waived:/i.test(text),
|
|
65
|
+
blockedBy: collectSpecIds(fm.blocked_by),
|
|
66
|
+
hasVerificationSection: /^#{1,3}\s+Verification\b/im.test(text),
|
|
67
|
+
acStatus: acStatusCounts(fm.acceptance_criteria),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ── pure path classification (the fs-free half of specs.ts's directory walk) ──
|
|
71
|
+
/** Escape a core for use inside a RegExp. */
|
|
72
|
+
function escapeForRegExp(s) {
|
|
73
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
74
|
+
}
|
|
75
|
+
const LIFECYCLE_ARTIFACTS = [
|
|
76
|
+
'CLARIFICATION',
|
|
77
|
+
'REVIEW',
|
|
78
|
+
'COMPLIANCE-REPORT',
|
|
79
|
+
'IMPLEMENTATION_PLAN',
|
|
80
|
+
'IMPLEMENTATION-PLAN',
|
|
81
|
+
'-ENHANCEMENT-',
|
|
82
|
+
'-ANALYSIS',
|
|
83
|
+
];
|
|
84
|
+
/** Subdirectories that hold derivative docs, not primary specs. */
|
|
85
|
+
const NON_PRIMARY_DIRS = new Set([
|
|
86
|
+
'analysis',
|
|
87
|
+
'decisions',
|
|
88
|
+
'contexts',
|
|
89
|
+
'navigation',
|
|
90
|
+
'recommendations',
|
|
91
|
+
'enhancements',
|
|
92
|
+
'reviews',
|
|
93
|
+
'reports',
|
|
94
|
+
'research',
|
|
95
|
+
'summaries',
|
|
96
|
+
'plans',
|
|
97
|
+
'tasks',
|
|
98
|
+
]);
|
|
99
|
+
/** Filename without directory or trailing `.md`. */
|
|
100
|
+
function specBasename(path) {
|
|
101
|
+
const file = path.split('/').pop() ?? path;
|
|
102
|
+
return file.endsWith('.md') ? file.slice(0, -3) : file;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The spec id parsed from `filename`, anchored to the EXACT `core` (any length).
|
|
106
|
+
* The id grammar is `{core}[-{SUB}]-{num}[.{minor}][-{EN-n|En|Pn[.n][-EN-n]}]`,
|
|
107
|
+
* matched case-insensitively. Anchoring to the literal core (instead of a generic
|
|
108
|
+
* `[A-Z]{2,N}` class + `startsWith`) is what lets the same helper serve encoreos's
|
|
109
|
+
* 2-char cores (PF/CE) AND builder's longer cores (RUNNER, tool) without
|
|
110
|
+
* over-crediting a foreign id (e.g. `FARM-12` is never read as core `fa`). Proven
|
|
111
|
+
* zero-diff against all 1287 encoreos spec files and 50/50 on the builder corpus
|
|
112
|
+
* (epic #300, Wave-1 G3).
|
|
113
|
+
*/
|
|
114
|
+
export function extractSpecId(filename, core) {
|
|
115
|
+
const re = new RegExp(`^(${escapeForRegExp(core)}(?:-[A-Z]{1,4})?-\\d+(?:\\.\\d+)?(?:-(?:EN-\\d+|E\\d+|P\\d+(?:\\.\\d+)?(?:-EN-\\d+)?))?)`, 'i');
|
|
116
|
+
const match = re.exec(specBasename(filename));
|
|
117
|
+
return match ? match[1] : null;
|
|
118
|
+
}
|
|
119
|
+
/** A `{ID}-PHASE…` lifecycle file. `[A-Z]{2,6}` so it skips builder phase files
|
|
120
|
+
* (e.g. `RUNNER-…-PHASE2-…`) as well as encoreos's 2–3-char cores. */
|
|
121
|
+
export function isPhaseLifecycleFile(filename) {
|
|
122
|
+
return /^[A-Z]{2,6}-\d+(?:\.\d+)?-(?:[A-Z]+-)?PHASE\d?-/i.test(specBasename(filename).toUpperCase());
|
|
123
|
+
}
|
|
124
|
+
export function isLifecycleArtifact(filename) {
|
|
125
|
+
const upper = specBasename(filename).toUpperCase();
|
|
126
|
+
// Match each token at DASH boundaries, preserving the token's own leading/trailing
|
|
127
|
+
// '-'. Plain `includes` over-excluded valid primary specs: 'REVIEW' matched
|
|
128
|
+
// `WEB-3-REVIEWED`/`...-PREVIEW-...`, 'COMPLIANCE-REPORT' matched
|
|
129
|
+
// `...-COMPLIANCE-REPORTING`, and stripping the dashes off '-ENHANCEMENT-' wrongly
|
|
130
|
+
// caught a `...-enhancement` SUFFIX. The token's own dashes are the boundary; the
|
|
131
|
+
// other side anchors on a dash or the string end.
|
|
132
|
+
return LIFECYCLE_ARTIFACTS.some((token) => {
|
|
133
|
+
const esc = token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
134
|
+
const left = token.startsWith('-') ? '' : '(?:^|-)';
|
|
135
|
+
const right = token.endsWith('-') ? '' : '(?:-|$)';
|
|
136
|
+
return new RegExp(`${left}${esc}${right}`).test(upper);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** True when a filename + its containing dir indicate a derivative artifact, not a primary spec. */
|
|
140
|
+
export function isDerivativeArtifact(dirName, filename) {
|
|
141
|
+
if (NON_PRIMARY_DIRS.has(dirName))
|
|
142
|
+
return true;
|
|
143
|
+
if (isLifecycleArtifact(filename) || isPhaseLifecycleFile(filename))
|
|
144
|
+
return true;
|
|
145
|
+
return /-(TASKS|PLAN|CONTEXT|RESEARCH|NAVIGATION|RECOMMENDATION|RECOMMENDATIONS|DECISION|DECISIONS|SUMMARY|IMPLEMENTATION|WORKSTREAM|AUDIT|REPORT|SIGNOFF|READINESS|EXPANSION|WORKSHEET|PATTERNS)/i.test(specBasename(filename).toUpperCase());
|
|
146
|
+
}
|
|
147
|
+
/** The skip rules `collectSpecsFromDirectory` applies to one filename. */
|
|
148
|
+
export function isPrimarySpecFile(filename) {
|
|
149
|
+
if (!filename.endsWith('.md'))
|
|
150
|
+
return false;
|
|
151
|
+
if (filename.includes('CONTEXT'))
|
|
152
|
+
return false;
|
|
153
|
+
if (filename.startsWith('SPEC_INDEX'))
|
|
154
|
+
return false;
|
|
155
|
+
if (filename.startsWith('README'))
|
|
156
|
+
return false;
|
|
157
|
+
if (filename.includes('ENHANCEMENTS'))
|
|
158
|
+
return false;
|
|
159
|
+
if (filename.includes('EXPANSION'))
|
|
160
|
+
return false;
|
|
161
|
+
if (isPhaseLifecycleFile(filename))
|
|
162
|
+
return false;
|
|
163
|
+
if (isLifecycleArtifact(filename))
|
|
164
|
+
return false;
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
/** True when a repo-relative path is a primary spec directly under specs/{core}/specs|ux/. */
|
|
168
|
+
export function isPrimarySpecPath(path) {
|
|
169
|
+
const parts = path.split('/');
|
|
170
|
+
if (parts.length !== 4 || parts[0] !== 'specs')
|
|
171
|
+
return false;
|
|
172
|
+
if (parts[2] !== 'specs' && parts[2] !== 'ux')
|
|
173
|
+
return false;
|
|
174
|
+
if (!isPrimarySpecFile(parts[3]))
|
|
175
|
+
return false;
|
|
176
|
+
return extractSpecId(parts[3], parts[1]) != null;
|
|
177
|
+
}
|
|
178
|
+
/** The spec id for a primary spec path, or null if the path isn't a primary spec. */
|
|
179
|
+
export function specIdForPath(path) {
|
|
180
|
+
if (!isPrimarySpecPath(path))
|
|
181
|
+
return null;
|
|
182
|
+
const parts = path.split('/');
|
|
183
|
+
return extractSpecId(parts[3], parts[1]);
|
|
184
|
+
}
|
|
185
|
+
/** Deterministic winner (path-sorted, mirroring the CLI's findSpec) for a spec id among `allPaths`. */
|
|
186
|
+
export function findSpecPath(specId, allPaths) {
|
|
187
|
+
const up = specId.toUpperCase();
|
|
188
|
+
const matches = allPaths.filter((p) => specIdForPath(p)?.toUpperCase() === up).sort((a, b) => a.localeCompare(b));
|
|
189
|
+
return matches[0] ?? null;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Path-Set equivalent of specs.ts's `hasArtifact`/`resolveArtifactPath`: is there a
|
|
193
|
+
* `specs/{core}/{folder}/{id}-{suffix}.md` (flat dir only) in `paths`? A child
|
|
194
|
+
* sub-spec's artifact (`{id}-EN-01-TASKS.md`, `{id}-P2-TASKS.md`) must not credit
|
|
195
|
+
* the parent id — same boundary rule the fs walker uses.
|
|
196
|
+
*/
|
|
197
|
+
export function hasArtifactInPaths(paths, core, folder, id, suffix) {
|
|
198
|
+
const prefix = `specs/${core}/${folder}/`;
|
|
199
|
+
for (const p of paths) {
|
|
200
|
+
if (!p.startsWith(prefix))
|
|
201
|
+
continue;
|
|
202
|
+
const file = p.slice(prefix.length);
|
|
203
|
+
if (file.includes('/'))
|
|
204
|
+
continue; // flat readdir parity with the CLI
|
|
205
|
+
if (file === `${id}-${suffix}.md`)
|
|
206
|
+
return true;
|
|
207
|
+
if (!file.startsWith(`${id}-`) || !file.endsWith(`-${suffix}.md`))
|
|
208
|
+
continue;
|
|
209
|
+
const middle = file.slice(id.length + 1, file.length - `-${suffix}.md`.length);
|
|
210
|
+
if (!/^(EN-\d+|P\d+)(-|$)/i.test(middle))
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=spec-pure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-pure.js","sourceRoot":"","sources":["../../src/lib/spec-pure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { AcStatusCounts } from './requirements.js';
|
|
2
|
+
import { extractSpecId, isDerivativeArtifact } from './spec-pure.js';
|
|
3
|
+
export { extractSpecId, isDerivativeArtifact };
|
|
4
|
+
/** True when a generated test source has ≥1 ACTIVE `test(` block (not `test.fixme`/
|
|
5
|
+
* `test.describe`) and is not an AC-less placeholder. Mirrors the active-test regex
|
|
6
|
+
* in scripts/specs/check-generated-tests.ts (flagWeakTest): the negative lookbehind
|
|
7
|
+
* rejects `test.fixme(`, `test.describe(`, and `/re/.test(`. Line comments are stripped
|
|
8
|
+
* first so a `test(` mentioned in a `//` comment is not a false positive (the canonical
|
|
9
|
+
* regex runs on real generated files, which never carry such comments). */
|
|
10
|
+
export declare function hasActiveGeneratedTestSource(source: string): boolean;
|
|
11
|
+
/** Cores requiring regulatory grounding + compliance review (matches scripts/specs/validate-compliance-gate.ts). */
|
|
12
|
+
export declare const REGULATED_CORES: Set<string>;
|
|
13
|
+
export type SpecSignals = {
|
|
14
|
+
isRegulated: boolean;
|
|
15
|
+
pipelineStatus?: string;
|
|
16
|
+
hasResearch: boolean;
|
|
17
|
+
hasAcceptanceCriteria: boolean;
|
|
18
|
+
hasUserStories: boolean;
|
|
19
|
+
hasGeneratedTests: boolean;
|
|
20
|
+
/** A generated suite exists AND has ≥1 active test() block (not stub-only
|
|
21
|
+
* test.fixme scaffolds, and not an AC-less placeholder). Distinguishes
|
|
22
|
+
* tests-generated from tests-stubbed in the navigator funnel (B5). */
|
|
23
|
+
hasActiveGeneratedTests: boolean;
|
|
24
|
+
/** Every acceptance_criteria entry is in a TERMINAL status (`verified` |
|
|
25
|
+
* `hand_closed` | `deferred`) and there is ≥1 — i.e. none remain `planned`.
|
|
26
|
+
* Proof the ACs are terminally resolved (a `verified` AC is backed by a passing
|
|
27
|
+
* test set by verify-acs; `hand_closed`/`deferred` are the ADR-0015 audit-closed
|
|
28
|
+
* statuses, issue #174), so the generate-tests gate is satisfied even without a
|
|
29
|
+
* generated scaffold (C1). Computed via the typed model's
|
|
30
|
+
* `allAcceptanceCriteriaTerminal`. The name is retained for signal-shape
|
|
31
|
+
* stability across consumers; "verified" here means "terminally resolved". */
|
|
32
|
+
hasVerifiedAcceptanceCriteria: boolean;
|
|
33
|
+
/** A hand-authored `tests/e2e/<core>/<id>(-slug)?-local.spec.ts` carries a
|
|
34
|
+
* `@verifies <ID>` backlink AND the spec declares `e2e_tests` — the
|
|
35
|
+
* superpowers / non-generated test path (C1). */
|
|
36
|
+
hasLinkedLocalTest: boolean;
|
|
37
|
+
/** Advisory (Phase 3 canonical seed-fixture): the spec declares a Lane-4 seed
|
|
38
|
+
* fixture — a `tests/fixtures/<core>/<spec>Seed.ts` reference in its body, per the
|
|
39
|
+
* "### Seed Fixtures / Test Data" template section. Not a pipeline gate. */
|
|
40
|
+
hasSeedFixture?: boolean;
|
|
41
|
+
hasSpecReview: boolean;
|
|
42
|
+
hasValidationSignoff: boolean;
|
|
43
|
+
hasComplianceSignoff: boolean;
|
|
44
|
+
hasUxSignoff: boolean;
|
|
45
|
+
/** The spec ships user-facing UI (a populated "UI / UX" template section, or
|
|
46
|
+
* affected_files reaching into components/pages/wizards). Gates the verification
|
|
47
|
+
* tail (docshots + browser auto-heal) — data/backend-only specs skip both. */
|
|
48
|
+
isUiBearing: boolean;
|
|
49
|
+
/** Docshot evidence exists: a `docs/images/<area>/<spec-id>-*.png` on disk, a
|
|
50
|
+
* `*-docs-shots.spec.ts` referenced by the spec, or an explicit
|
|
51
|
+
* `<!-- docshots: -->` marker (legacy shot naming / not-applicable escape hatch,
|
|
52
|
+
* written via `eos-spec signoff --type docshots`). */
|
|
53
|
+
hasDocshots: boolean;
|
|
54
|
+
/** Browser auto-heal verdict recorded: `<!-- heal-verified: -->` marker, written
|
|
55
|
+
* via `eos-spec signoff --type heal-verified` after the browser-autoheal skill
|
|
56
|
+
* reaches HEAL_VERDICT=green. */
|
|
57
|
+
hasHealSignoff: boolean;
|
|
58
|
+
/** A `<!-- ui-gate-waived: <date> reason -->` marker exists, written via
|
|
59
|
+
* `eos-spec signoff --type ui-gate-waived`. Documented escape for the C1
|
|
60
|
+
* UI-evidence gate (e.g. a backend spec that `isUiBearing` false-positives on). */
|
|
61
|
+
hasUiGateWaiver: boolean;
|
|
62
|
+
/** Phase 3 (#1185): the spec is a kind:'create' wizard per the generated
|
|
63
|
+
* wizard-create-specs bridge. Gates the submit→DB E2E completion check. */
|
|
64
|
+
isCreateWizardSpec?: boolean;
|
|
65
|
+
/** Phase 3 (#1185): a tests/e2e/<core>/<id>-local.spec.ts proves a persisted row
|
|
66
|
+
* (imports createClient + a `.from('<table>') ... .select(` read-back of the target
|
|
67
|
+
* table — the post-submit verification read, not a bare cleanup `.delete()`, #1327),
|
|
68
|
+
* OR a `<!-- submit-e2e-waived: -->` marker is present. */
|
|
69
|
+
hasSubmitE2e?: boolean;
|
|
70
|
+
/** Canonical cross-spec blockers, parsed from `blocked_by` frontmatter (upper-cased spec ids). */
|
|
71
|
+
blockedBy: string[];
|
|
72
|
+
/** A `## Verification` section/heading is present in the spec body. A `hand_closed`
|
|
73
|
+
* AC (proven by a CI suite the src-lane prover can't reach) REQUIRES this backlink;
|
|
74
|
+
* the audit flags a hand_closed AC with no Verification section as a violation (#174).
|
|
75
|
+
* Optional on the type for signal-shape stability; always populated by deriveSignals. */
|
|
76
|
+
hasVerificationSection?: boolean;
|
|
77
|
+
/** Per-AC status tally (planned vs verified vs hand_closed vs deferred) read from
|
|
78
|
+
* frontmatter — the typed AC model the `audit` command consumes (#174). Optional on
|
|
79
|
+
* the type for signal-shape stability; always populated by deriveSignals. */
|
|
80
|
+
acStatus?: AcStatusCounts;
|
|
81
|
+
};
|
|
82
|
+
export type SpecFile = {
|
|
83
|
+
id: string;
|
|
84
|
+
core: string;
|
|
85
|
+
path: string;
|
|
86
|
+
title?: string;
|
|
87
|
+
status?: string;
|
|
88
|
+
/** The id of the spec that supersedes this one (frontmatter `superseded_by`). Present ⇒ terminal. */
|
|
89
|
+
supersededBy?: string;
|
|
90
|
+
hasPlan: boolean;
|
|
91
|
+
hasTasks: boolean;
|
|
92
|
+
hasContext: boolean;
|
|
93
|
+
signals: SpecSignals;
|
|
94
|
+
archived: boolean;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Derive pipeline signals from a spec's core + raw text. File-existence flags are
|
|
98
|
+
* supplied by the caller. Thin positional-args adapter over the pure
|
|
99
|
+
* {@link deriveSignalsFromText} (spec-pure.ts) — the single source of signal
|
|
100
|
+
* derivation, shared with browser consumers via `/pure`. Keep this signature
|
|
101
|
+
* stable; route new signal logic through `deriveSignalsFromText`.
|
|
102
|
+
*/
|
|
103
|
+
export declare function deriveSignals(core: string, text: string, researchFileExists: boolean, reviewFileExists?: boolean, generatedTestExists?: boolean, complianceSignoffFileExists?: boolean, docshotImageExists?: boolean, activeGeneratedTests?: boolean, isCreateWizardSpec?: boolean, submitE2eProvesPersist?: boolean, linkedLocalTestExists?: boolean): SpecSignals;
|
|
104
|
+
export declare function listSpecs(repoRoot: string, coreFilter?: string, options?: {
|
|
105
|
+
includeArchived?: boolean;
|
|
106
|
+
}): SpecFile[];
|
|
107
|
+
/**
|
|
108
|
+
* Resolve the on-disk path of a spec artifact (plan/tasks) for `id`, or null when none exists.
|
|
109
|
+
* Folder-agnostic: the artifact dir is `specs/{core}/{folder}/`, independent of whether the
|
|
110
|
+
* spec itself lives under `specs/{core}/specs/` or `specs/{core}/ux/` — which is exactly why
|
|
111
|
+
* the old `/\/specs\/[^/]+\.md$/` path-derivation regex in next.ts silently failed for UX specs.
|
|
112
|
+
*/
|
|
113
|
+
export declare function resolveArtifactPath(repoRoot: string, core: string, folder: 'plans' | 'tasks', id: string, suffix: string): string | null;
|
|
114
|
+
/** True when a tests/e2e/<core>/<id-lower>(-<slug>)?-local.spec.ts exists AND
|
|
115
|
+
* proves a persisted row was *read back* after submit: it imports createClient AND
|
|
116
|
+
* contains a `.from('<targetTable>')` chained to a `.select(` — the post-submit
|
|
117
|
+
* verification read — not merely a `.from('<targetTable>')` that could be a
|
|
118
|
+
* setup/cleanup `.delete()` (#1327). Quote style is free (`'`, `"`, or backtick),
|
|
119
|
+
* and arbitrary whitespace/newlines/chaining is allowed between the `.from(...)`
|
|
120
|
+
* and the `.select(` (the Supabase builder is fluent, so the read-back commonly
|
|
121
|
+
* spans lines: `db\n .from('t')\n .select(...)`). The submit→DB completion signal.
|
|
122
|
+
* The repo convention is `<id>-<slug>-local.spec.ts` (e.g.
|
|
123
|
+
* gr-ux-10-contract-creation-local.spec.ts), so the file is matched by prefix —
|
|
124
|
+
* the same prefix-glob `generatedTestExistsFor` uses — not an exact filename. */
|
|
125
|
+
export declare function submitE2eProvesPersistFor(repoRoot: string, core: string, id: string, targetTable: string): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* All specs whose ID matches `specId` (case-insensitive) across `specs/` and
|
|
128
|
+
* `ux/` — plus `archive/` when `options.includeArchived` is set. Duplicate spec
|
|
129
|
+
* IDs are live in the corpus today (e.g. PF-76, PF-77); callers that
|
|
130
|
+
* gate on identity (create/archive collision checks, the navigator) must use
|
|
131
|
+
* this instead of `findSpec` so collisions are visible, never silently resolved.
|
|
132
|
+
*/
|
|
133
|
+
export declare function findSpecsById(repoRoot: string, specId: string, options?: {
|
|
134
|
+
includeArchived?: boolean;
|
|
135
|
+
}): SpecFile[];
|
|
136
|
+
export declare function findSpec(repoRoot: string, specId: string, options?: {
|
|
137
|
+
includeArchived?: boolean;
|
|
138
|
+
}): SpecFile | null;
|
|
139
|
+
export type MissingSpecDiagnosis = {
|
|
140
|
+
foundPath?: string;
|
|
141
|
+
reason: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* When findSpec returns null, look for a markdown file on disk whose name starts
|
|
145
|
+
* with the id so we can give honest advice instead of always suggesting
|
|
146
|
+
* create-spec. Walks `specs/{core}/` recursively.
|
|
147
|
+
*/
|
|
148
|
+
export declare function diagnoseMissingSpec(repoRoot: string, specId: string): MissingSpecDiagnosis;
|