paqad-ai 1.44.1 → 1.46.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/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # paqad-ai
2
2
 
3
+ ## 1.46.1
4
+
5
+ ### Patch Changes
6
+
7
+ - c0e7efa: Fix #310: the feature-development stage gate blocked documentation-only work and could deadlock unclearably.
8
+
9
+ - **Scope.** The pre-mutation and completion stage gates now govern **feature development only**. A documentation-only change (`docs/**`, markdown) or a framework-internal change (`.paqad/**`) is no longer forced through the planning → specification → … → checks stages. The check is language-agnostic (an exclude list, not a `src/` allowlist), so it holds for any onboarded stack (Laravel `app/*.php`, Python, Go, …), and it keeps full teeth on real source edits.
10
+ - **No deadlock.** The live writer no longer stamps a stage (e.g. `development`/`documentation_sync`) before the pre-code stages are recorded — that phantom used to poison stage ordering so `planning` could never be recorded again. The recorder no longer rejects an out-of-order earlier `stage_start`; ordering is judged non-destructively by the completion fold, so the stages the gate demands can always be recorded and the same-turn marker remediation actually clears the block.
11
+ - **Consistent predicate.** An `end` with no matching `start` is now `inconclusive`, not silently `complete`, so the pre-mutation gate and the completion verifier agree a stage needs a start.
12
+ - **Reachable remedy.** Editing `.paqad/configs/.config.policy` (the `stages_mode` escape hatch) is no longer blocked by the gate it configures.
13
+
14
+ ## 1.46.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 944f52f: Stages gate: same-turn unblock that actually works, sentinel bootstrap un-deadlocked, and stage narration everywhere (#307).
19
+
20
+ - `paqad:stage` markers are now parsed at the pre-mutation seam too, so markers emitted earlier in the same turn clear the block-forward gate immediately — not only after Stop.
21
+ - New `paqad-ai stage <start|end> <stage>` CLI verb replaces the never-shipped `scripts/se-mark.ts` as the shell escape hatch; the block message, framework bootstrap, and decision-skill docs now name only remediations that exist on an onboarded project.
22
+ - The write of `.paqad/.agent-entry-loaded` is exempt from both the agent-entry gate and the stages gate: turn one can complete the bootstrap it is being asked to perform.
23
+ - Narration and ledger are both non-negotiable: every stage-evidence row minted from markers (pre-mutation sweep, Stop parse, CLI) is narrated back to the developer as a `▸ paqad` line via the host's user-message channel; allow-path advisories use `systemMessage` instead of invisible stdout.
24
+ - Guardrails: a packaging-truth test suite pins that every runnable path/verb named in user-facing remediation surfaces resolves in the published package, and `src/stage-evidence/**` now holds a 100% coverage floor (statements, branches, functions, lines).
25
+ - Completion-backstop over-block fixed (decision `D-01KWYDTDZ24CV802R2HGDS4RH4`), removing two false blocks that hit every onboarded repo's first code change: (1) an implementation-drift canonical doc that does not exist on disk is no longer treated as an unresolved obligation — a code change cannot stale a framework-assumed doc (`docs/maintainers/architecture-map.md`, `docs/modules/README.md`) the project never created; existing drift docs are still flagged and required per-module docs stay enforced; (2) test-evidence strength is a provider-workflow concern the agent-independent backstop cannot collect, so at backstop origins it now escalates (visibly) instead of hard-blocking — in-session and CI still enforce it.
26
+
27
+ ## 1.45.0
28
+
29
+ ### Minor Changes
30
+
31
+ - b07dc02: Decision Pause now mints packets on more of the forks that matter (#300, option B2):
32
+
33
+ - **Self-arm broadened to architecture-path.** Alongside create-vs-reuse (0.92), the opt-in self-arm minter now also arms on a new tight `explicit-path-fork` detector signal (0.90) — two distinct file paths offered as alternatives ("live in X or Y", "X vs Y"). The pre-existing broad architecture-path signals (a bare "or", two paths merely mentioned) stay at 0.64 and never clear the arming bar, so a stray "or" cannot mint a pause. Self-arm remains OFF by default.
34
+ - **spec.change now has a deterministic minter.** A new always-on, no-opt-in spec-change guard runs at the pre-mutation seam: when a persisted frozen spec's source markdown has moved since freeze (`isFrozenSpecStale`), it mints one `spec.change` pause via `buildSpecChangePacket`. It is naturally inert until a spec is frozen and its sidecar persisted (`writeFrozenSpec`), so nothing changes for projects that do not use the spec-freeze lifecycle. Both minters only write a pending packet; the existing decision-pause gate still owns the block on the next edit.
35
+
36
+ Cross-provider: the architecture-path leg inherits self-arm's existing transcript-based provider coverage (parity with `HOOK_COVERAGE_MATRIX`); the spec-change guard is provider-independent (it reads spec files on disk, not the turn transcript).
37
+
38
+ Also fixes `buildSpecChangePacket` copy that could never pass `lintDecisionCopy` (banned word "invariant", non-approved label verb, em dashes), which had silently blocked the packet from ever being written to the pending store.
39
+
3
40
  ## 1.44.1
4
41
 
5
42
  ### Patch Changes
package/dist/cli/index.js CHANGED
@@ -9772,7 +9772,7 @@ import { pathToFileURL } from "url";
9772
9772
 
9773
9773
  // src/cli/program.ts
9774
9774
  init_esm_shims();
9775
- import { Command as Command23 } from "commander";
9775
+ import { Command as Command24 } from "commander";
9776
9776
 
9777
9777
  // src/index.ts
9778
9778
  init_esm_shims();
@@ -16072,8 +16072,8 @@ function isPlaceholder(tokens) {
16072
16072
  return tokens.$comment === DESIGN_TOKENS_PLACEHOLDER_NOTE;
16073
16073
  }
16074
16074
  var DesignTokenService = class {
16075
- constructor(validator3 = new SchemaValidator()) {
16076
- this.validator = validator3;
16075
+ constructor(validator4 = new SchemaValidator()) {
16076
+ this.validator = validator4;
16077
16077
  }
16078
16078
  async seed(projectRoot) {
16079
16079
  const target = join53(projectRoot, PATHS.DESIGN_TOKENS_FILE);
@@ -18302,7 +18302,7 @@ var HealthChecker = class {
18302
18302
  }
18303
18303
  checkFrameworkArtifacts(projectRoot) {
18304
18304
  const required = [PATHS.PROJECT_PROFILE, PATHS.FRAMEWORK_PATH];
18305
- const missing = required.filter((relative24) => !existsSync32(join58(projectRoot, relative24)));
18305
+ const missing = required.filter((relative26) => !existsSync32(join58(projectRoot, relative26)));
18306
18306
  return missing.length === 0 ? pass("Framework artifacts exist", "Framework artifacts are present") : fail(
18307
18307
  "Framework artifacts exist",
18308
18308
  `Missing framework artifacts: ${missing.join(", ")}`,
@@ -22714,8 +22714,8 @@ function loadDeliveryPolicy(projectRoot) {
22714
22714
  ]
22715
22715
  };
22716
22716
  }
22717
- const validator3 = new SchemaValidator();
22718
- const validation = validator3.validate("delivery-policy", parsed);
22717
+ const validator4 = new SchemaValidator();
22718
+ const validation = validator4.validate("delivery-policy", parsed);
22719
22719
  if (!validation.valid) {
22720
22720
  return {
22721
22721
  policy: withDetection(projectRoot, defaults),
@@ -23700,8 +23700,8 @@ var OnboardingOrchestrator = class {
23700
23700
  options.projectRoot
23701
23701
  );
23702
23702
  profile.intelligence = applyRagSelection(profile.intelligence, void 0);
23703
- const validator3 = new SchemaValidator();
23704
- const validation = validator3.validate("project-profile", profile);
23703
+ const validator4 = new SchemaValidator();
23704
+ const validation = validator4.validate("project-profile", profile);
23705
23705
  const modules = await discoverModules(options.projectRoot);
23706
23706
  if (!validation.valid) {
23707
23707
  throw new Error(validation.errors.map((error) => error.message).join("; "));
@@ -23937,8 +23937,8 @@ var OnboardingOrchestrator = class {
23937
23937
  options.projectRoot
23938
23938
  );
23939
23939
  profile.intelligence = applyRagSelection(profile.intelligence, void 0);
23940
- const validator3 = new SchemaValidator();
23941
- const validation = validator3.validate("project-profile", profile);
23940
+ const validator4 = new SchemaValidator();
23941
+ const validation = validator4.validate("project-profile", profile);
23942
23942
  if (!validation.valid) {
23943
23943
  throw new ValidationError(validation.errors.map((error) => error.message).join("; "), {
23944
23944
  projectRoot: options.projectRoot
@@ -25904,9 +25904,68 @@ import Ajv5 from "ajv";
25904
25904
  // src/stage-evidence/types.ts
25905
25905
  init_esm_shims();
25906
25906
  var STAGE_EVIDENCE_DOC_TYPE = "paqad.stage-evidence";
25907
+ var STAGE_EVIDENCE_SCHEMA_VERSION = 1;
25907
25908
 
25908
25909
  // src/stage-evidence/schema.ts
25910
+ var nullableString3 = { type: ["string", "null"] };
25911
+ var STAGE_EVIDENCE_SCHEMA = {
25912
+ $id: "paqad://schemas/stage-evidence.json",
25913
+ type: "object",
25914
+ additionalProperties: false,
25915
+ required: [
25916
+ "schema_version",
25917
+ "doc_type",
25918
+ "kind",
25919
+ "session_id",
25920
+ "conversation_ordinal",
25921
+ "ts",
25922
+ "adapter",
25923
+ "content_hash"
25924
+ ],
25925
+ properties: {
25926
+ schema_version: { type: "integer", const: 1 },
25927
+ doc_type: { const: STAGE_EVIDENCE_DOC_TYPE },
25928
+ kind: { enum: ["open", "stage_start", "stage_end", "verify", "close"] },
25929
+ session_id: { type: "string", minLength: 1 },
25930
+ conversation_ordinal: { type: "integer", minimum: 1 },
25931
+ ts: { type: "string", minLength: 1 },
25932
+ adapter: { type: "string", minLength: 1 },
25933
+ stage: nullableString3,
25934
+ event_status: {
25935
+ type: ["string", "null"],
25936
+ enum: ["started", "completed", "skipped", "failed", "redone", "inferred", null]
25937
+ },
25938
+ evidence_source: {
25939
+ type: ["string", "null"],
25940
+ enum: ["live-mark", "inferred-artifact", "inferred-git", "redo", null]
25941
+ },
25942
+ artifact_paths: { type: ["array", "null"], items: { type: "string" } },
25943
+ artifact_digest: nullableString3,
25944
+ subject_digest: nullableString3,
25945
+ lane: { type: ["string", "null"], enum: ["fast", "graduated", "full", null] },
25946
+ note: nullableString3,
25947
+ content_hash: { type: "string", minLength: 1 }
25948
+ }
25949
+ };
25909
25950
  var ajv4 = new Ajv5({ allErrors: true, allowUnionTypes: true });
25951
+ var compiled3;
25952
+ function validator3() {
25953
+ if (!compiled3) {
25954
+ compiled3 = ajv4.compile(STAGE_EVIDENCE_SCHEMA);
25955
+ }
25956
+ return compiled3;
25957
+ }
25958
+ function formatValidationError(error) {
25959
+ return `${error.instancePath || "(root)"} ${error.message ?? "invalid"}`;
25960
+ }
25961
+ function validateStageEvidenceRow(row) {
25962
+ const validate = validator3();
25963
+ if (validate(row)) {
25964
+ return [];
25965
+ }
25966
+ const errors = validate.errors;
25967
+ return errors.map(formatValidationError);
25968
+ }
25910
25969
 
25911
25970
  // src/stage-evidence/recorder.ts
25912
25971
  init_session();
@@ -25914,6 +25973,108 @@ init_session();
25914
25973
  // src/stage-evidence/stages.ts
25915
25974
  init_esm_shims();
25916
25975
  var STAGE_EVIDENCE_STAGES = [...STAGE_ORDER];
25976
+ var MANDATORY_STAGES = [
25977
+ "planning",
25978
+ "specification",
25979
+ "development",
25980
+ "review",
25981
+ "checks",
25982
+ "documentation_sync"
25983
+ ];
25984
+ var PRE_CODE_STAGES = MANDATORY_STAGES.slice(
25985
+ 0,
25986
+ MANDATORY_STAGES.indexOf("development")
25987
+ );
25988
+ function isKnownStage(stage) {
25989
+ return STAGE_EVIDENCE_STAGES.includes(stage);
25990
+ }
25991
+
25992
+ // src/stage-evidence/recorder.ts
25993
+ var APPEND_OPTS3 = (now) => ({
25994
+ schemaVersion: STAGE_EVIDENCE_SCHEMA_VERSION,
25995
+ validate: (row) => validateStageEvidenceRow(row),
25996
+ now
25997
+ });
25998
+ function changeKey(sessionId, ordinal) {
25999
+ return `${sessionId}#${ordinal}`;
26000
+ }
26001
+ function openStageEvidence(projectRoot, ctx) {
26002
+ const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
26003
+ const { ordinal } = openSessionDoc(
26004
+ projectRoot,
26005
+ STAGE_EVIDENCE_DOC_TYPE,
26006
+ sessionId,
26007
+ { adapter: ctx.adapter, lane: ctx.lane ?? null },
26008
+ APPEND_OPTS3(ctx.now)
26009
+ );
26010
+ return { sessionId, ordinal, changeKey: changeKey(sessionId, ordinal) };
26011
+ }
26012
+ function resolveOrdinal2(projectRoot, sessionId, ctx) {
26013
+ if (ctx.ordinal && ctx.ordinal > 0) {
26014
+ return ctx.ordinal;
26015
+ }
26016
+ const current = currentOrdinal(projectRoot, STAGE_EVIDENCE_DOC_TYPE, sessionId);
26017
+ if (current > 0) {
26018
+ return current;
26019
+ }
26020
+ return openStageEvidence(projectRoot, ctx).ordinal;
26021
+ }
26022
+ function startStage(projectRoot, stage, ctx) {
26023
+ if (!isKnownStage(stage)) {
26024
+ throw new Error(`Unknown stage "${stage}" \u2014 not in the feature-development registry.`);
26025
+ }
26026
+ const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
26027
+ const ordinal = resolveOrdinal2(projectRoot, sessionId, ctx);
26028
+ return append(projectRoot, sessionId, ordinal, ctx, {
26029
+ kind: "stage_start",
26030
+ stage,
26031
+ event_status: "started",
26032
+ evidence_source: "live-mark"
26033
+ });
26034
+ }
26035
+ function endStage(projectRoot, stage, input3, ctx) {
26036
+ if (!isKnownStage(stage)) {
26037
+ throw new Error(`Unknown stage "${stage}" \u2014 not in the feature-development registry.`);
26038
+ }
26039
+ const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
26040
+ const ordinal = resolveOrdinal2(projectRoot, sessionId, ctx);
26041
+ const artifactPaths = input3.artifactPaths ?? [];
26042
+ const artifactDigest = artifactPaths.length > 0 ? hashArtifacts(projectRoot, artifactPaths) : null;
26043
+ const subjectDigest = stage === "development" ? input3.subjectDigest ?? artifactDigest : input3.subjectDigest ?? null;
26044
+ return append(projectRoot, sessionId, ordinal, ctx, {
26045
+ kind: "stage_end",
26046
+ stage,
26047
+ event_status: "completed",
26048
+ evidence_source: "live-mark",
26049
+ artifact_paths: artifactPaths.length > 0 ? artifactPaths : null,
26050
+ artifact_digest: artifactDigest,
26051
+ subject_digest: subjectDigest,
26052
+ note: input3.note ?? null
26053
+ });
26054
+ }
26055
+ function hashArtifacts(projectRoot, artifactPaths) {
26056
+ const perFile = [...artifactPaths].sort().map((rel) => {
26057
+ const abs = join129(projectRoot, rel);
26058
+ let bytes;
26059
+ try {
26060
+ bytes = readFileSync56(abs);
26061
+ } catch {
26062
+ return `${rel}:absent`;
26063
+ }
26064
+ return `${rel}:${createHash29("sha256").update(bytes).digest("hex")}`;
26065
+ });
26066
+ return `sha256-${createHash29("sha256").update(perFile.join("\n")).digest("hex")}`;
26067
+ }
26068
+ function append(projectRoot, sessionId, ordinal, ctx, fields) {
26069
+ return appendSessionEvent(
26070
+ projectRoot,
26071
+ STAGE_EVIDENCE_DOC_TYPE,
26072
+ sessionId,
26073
+ ordinal,
26074
+ { conversation_ordinal: ordinal, adapter: ctx.adapter, lane: ctx.lane ?? null, ...fields },
26075
+ APPEND_OPTS3(ctx.now)
26076
+ );
26077
+ }
25917
26078
 
25918
26079
  // src/stage-evidence/finalize.ts
25919
26080
  init_session();
@@ -25933,6 +26094,10 @@ init_session();
25933
26094
  init_esm_shims();
25934
26095
  init_framework_config();
25935
26096
 
26097
+ // src/stage-evidence/scope.ts
26098
+ init_esm_shims();
26099
+ import { isAbsolute as isAbsolute3, relative as relative22 } from "pathe";
26100
+
25936
26101
  // src/verification/repository/verdict.ts
25937
26102
  init_esm_shims();
25938
26103
 
@@ -26080,7 +26245,7 @@ init_esm_shims();
26080
26245
  init_esm_shims();
26081
26246
  init_logger_registry();
26082
26247
  import { mkdir as mkdir45, writeFile as writeFile45 } from "fs/promises";
26083
- import { join as join134, relative as relative22 } from "path";
26248
+ import { join as join134, relative as relative23 } from "path";
26084
26249
  init_paths();
26085
26250
  init_path_utils();
26086
26251
 
@@ -26122,7 +26287,7 @@ init_cancelled_error();
26122
26287
  init_events();
26123
26288
 
26124
26289
  // src/index.ts
26125
- var VERSION = "1.44.1";
26290
+ var VERSION = "1.46.1";
26126
26291
 
26127
26292
  // src/cli/commands/audit.ts
26128
26293
  init_esm_shims();
@@ -27121,7 +27286,7 @@ function resolveRelativeSpec(projectRoot, spec) {
27121
27286
  init_esm_shims();
27122
27287
  init_paths();
27123
27288
  import { existsSync as existsSync98 } from "fs";
27124
- import { dirname as dirname69, isAbsolute as isAbsolute3, join as join169, resolve as resolve10 } from "path";
27289
+ import { dirname as dirname69, isAbsolute as isAbsolute4, join as join169, resolve as resolve10 } from "path";
27125
27290
  import { fileURLToPath as fileURLToPath3 } from "url";
27126
27291
  import { Command as Command4 } from "commander";
27127
27292
 
@@ -27219,7 +27384,7 @@ function buildNodeDetail(graph, nodeId, options) {
27219
27384
  init_esm_shims();
27220
27385
  import { existsSync as existsSync70 } from "fs";
27221
27386
  import { readFile as readFile69, readdir as readdir15, stat as stat8 } from "fs/promises";
27222
- import { extname as extname8, join as join138, relative as relative23, sep as sep6 } from "path";
27387
+ import { extname as extname8, join as join138, relative as relative24, sep as sep6 } from "path";
27223
27388
  init_paths();
27224
27389
  var KNOWN_TIERS = /* @__PURE__ */ new Set(["green", "amber", "red", "unknown"]);
27225
27390
  function normaliseTier(value) {
@@ -27257,7 +27422,7 @@ function languageFromExtension(filePath) {
27257
27422
  return map[ext] ?? null;
27258
27423
  }
27259
27424
  function toProjectRelative2(projectRoot, absolutePath) {
27260
- const rel = relative23(projectRoot, absolutePath);
27425
+ const rel = relative24(projectRoot, absolutePath);
27261
27426
  return rel === "" ? "." : rel.split(sep6).join("/");
27262
27427
  }
27263
27428
  function moduleNameForFile(relativePath, knownModules) {
@@ -29116,12 +29281,12 @@ import { existsSync as existsSync78, readdirSync as readdirSync15 } from "fs";
29116
29281
  import { join as join148 } from "path";
29117
29282
  import YAML19 from "yaml";
29118
29283
  var EDITABLE_EXTENSIONS = [".md", ".yml", ".yaml", ".json"];
29119
- function buildNode(absolute, relative24, name) {
29284
+ function buildNode(absolute, relative26, name) {
29120
29285
  const entries = readdirSync15(absolute, { withFileTypes: true });
29121
29286
  const children = [];
29122
29287
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
29123
29288
  if (entry.name.startsWith(".")) continue;
29124
- const childRelative = relative24 === "" ? entry.name : `${relative24}/${entry.name}`;
29289
+ const childRelative = relative26 === "" ? entry.name : `${relative26}/${entry.name}`;
29125
29290
  if (entry.isDirectory()) {
29126
29291
  const child = buildNode(join148(absolute, entry.name), childRelative, entry.name);
29127
29292
  if (child) children.push(child);
@@ -29129,7 +29294,7 @@ function buildNode(absolute, relative24, name) {
29129
29294
  children.push({ path: childRelative, name: entry.name, type: "file" });
29130
29295
  }
29131
29296
  }
29132
- return { path: relative24, name, type: "directory", children };
29297
+ return { path: relative26, name, type: "directory", children };
29133
29298
  }
29134
29299
  function listInstructionsTree(projectRoot) {
29135
29300
  const root = join148(projectRoot, PATHS.INSTRUCTIONS_DIR);
@@ -29242,7 +29407,7 @@ function counted(count, singular, plural, zero) {
29242
29407
  }
29243
29408
  function buildInventory(projectRoot, options = {}) {
29244
29409
  const paqadHome = options.paqadHome ?? join149(homedir10(), ".paqad-ai");
29245
- const at = (relative24) => join149(projectRoot, relative24);
29410
+ const at = (relative26) => join149(projectRoot, relative26);
29246
29411
  const profile = parseYamlFile(at(PATHS.PROJECT_PROFILE));
29247
29412
  const activeCapabilities = Array.isArray(profile?.active_capabilities) ? profile.active_capabilities : [];
29248
29413
  const intelligence = profile?.intelligence ?? null;
@@ -29764,7 +29929,7 @@ function dirHasEntries(path11) {
29764
29929
  }
29765
29930
  }
29766
29931
  function buildOnboardingChecklist(projectRoot) {
29767
- const at = (relative24) => join150(projectRoot, relative24);
29932
+ const at = (relative26) => join150(projectRoot, relative26);
29768
29933
  const agentConnected = [PATHS.CLAUDE_MD, PATHS.AGENTS_MD, PATHS.ANTIGRAVITY_MD, PATHS.GEMINI_MD].some(
29769
29934
  (entry) => existsSync80(at(entry))
29770
29935
  ) && existsSync80(at(PATHS.ONBOARDING_MANIFEST));
@@ -32514,14 +32679,14 @@ data: ${JSON.stringify(data)}
32514
32679
  return;
32515
32680
  }
32516
32681
  if (instructionsFileMatch && req.method === "PUT") {
32517
- const relative24 = decodeURIComponent(instructionsFileMatch[1]);
32682
+ const relative26 = decodeURIComponent(instructionsFileMatch[1]);
32518
32683
  await handleMutation(req, res, async () => {
32519
32684
  const body = await readJsonBody2(req);
32520
32685
  if (typeof body.content !== "string") {
32521
32686
  throw new Error("Body must include the file `content` as a string.");
32522
32687
  }
32523
32688
  return writeManagedFile(options.projectRoot, {
32524
- relativePath: `${PATHS.INSTRUCTIONS_DIR}/${relative24}`,
32689
+ relativePath: `${PATHS.INSTRUCTIONS_DIR}/${relative26}`,
32525
32690
  content: body.content,
32526
32691
  baseHash: typeof body.baseHash === "string" ? body.baseHash : null,
32527
32692
  action: "dashboard.instructions.write"
@@ -32837,7 +33002,7 @@ function openBrowser(options) {
32837
33002
  var DEFAULT_PORT = 5372;
32838
33003
  function resolveStaticDir(override) {
32839
33004
  if (override) {
32840
- return isAbsolute3(override) ? override : resolve10(process.cwd(), override);
33005
+ return isAbsolute4(override) ? override : resolve10(process.cwd(), override);
32841
33006
  }
32842
33007
  const here = dirname69(fileURLToPath3(import.meta.url));
32843
33008
  const candidates = [
@@ -33037,14 +33202,14 @@ function createEvidenceCommand() {
33037
33202
  init_esm_shims();
33038
33203
  init_paths();
33039
33204
  import { existsSync as existsSync99 } from "fs";
33040
- import { dirname as dirname71, isAbsolute as isAbsolute4, join as join170, resolve as resolve12 } from "path";
33205
+ import { dirname as dirname71, isAbsolute as isAbsolute5, join as join170, resolve as resolve12 } from "path";
33041
33206
  import { fileURLToPath as fileURLToPath4 } from "url";
33042
33207
  import { Command as Command9 } from "commander";
33043
33208
  var DEFAULT_PORT2 = 5372;
33044
33209
  var DEPRECATION_LINE = "paqad-ai graph has moved into the dashboard. Opening the dashboard on the Graph view. Run paqad-ai dashboard next time.";
33045
33210
  function resolveStaticDir2(override) {
33046
33211
  if (override) {
33047
- return isAbsolute4(override) ? override : resolve12(process.cwd(), override);
33212
+ return isAbsolute5(override) ? override : resolve12(process.cwd(), override);
33048
33213
  }
33049
33214
  const here = dirname71(fileURLToPath4(import.meta.url));
33050
33215
  const candidates = [
@@ -33888,7 +34053,7 @@ function createPacksCommand() {
33888
34053
  init_esm_shims();
33889
34054
  init_project_intelligence();
33890
34055
  import { readFileSync as readFileSync76 } from "fs";
33891
- import { isAbsolute as isAbsolute5, join as join174 } from "path";
34056
+ import { isAbsolute as isAbsolute6, join as join174 } from "path";
33892
34057
  import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
33893
34058
  import { Command as Command18 } from "commander";
33894
34059
  init_framework_config();
@@ -34875,7 +35040,7 @@ function createRagCommand() {
34875
35040
  readFile: (path11) => {
34876
35041
  try {
34877
35042
  return readFileSync76(
34878
- isAbsolute5(path11) ? path11 : join174(options.projectRoot, path11),
35043
+ isAbsolute6(path11) ? path11 : join174(options.projectRoot, path11),
34879
35044
  "utf8"
34880
35045
  );
34881
35046
  } catch {
@@ -35326,10 +35491,95 @@ function resolveChangedFiles(projectRoot, contextChangedFiles) {
35326
35491
  }
35327
35492
  }
35328
35493
 
35494
+ // src/cli/commands/stage.ts
35495
+ init_esm_shims();
35496
+ import { Command as Command21 } from "commander";
35497
+ init_session();
35498
+
35499
+ // src/stage-evidence/live-writer.ts
35500
+ init_esm_shims();
35501
+ init_ledger();
35502
+ init_session();
35503
+ import { isAbsolute as isAbsolute7, relative as relative25 } from "pathe";
35504
+ function recordMarkedStage(projectRoot, input3) {
35505
+ if (!isKnownStage(input3.stage)) return false;
35506
+ const ctx = {
35507
+ sessionId: input3.sessionId,
35508
+ adapter: input3.adapter ?? "claude-code",
35509
+ now: input3.now
35510
+ };
35511
+ try {
35512
+ if (input3.phase === "start") {
35513
+ startStage(projectRoot, input3.stage, ctx);
35514
+ } else {
35515
+ endStage(projectRoot, input3.stage, { artifactPaths: input3.artifactPaths ?? [] }, ctx);
35516
+ }
35517
+ return true;
35518
+ } catch {
35519
+ return false;
35520
+ }
35521
+ }
35522
+
35523
+ // src/stage-evidence/narration.ts
35524
+ init_esm_shims();
35525
+ init_ledger();
35526
+ init_session();
35527
+ var STAGE_NARRATION = {
35528
+ ticket_intake: "picking up the ticket and reading what it needs",
35529
+ planning: "planning this out, checking which module it touches",
35530
+ specification: "writing the spec before any code",
35531
+ development: "building it to the spec",
35532
+ review: "reviewing the change for regressions",
35533
+ checks: "running the gates: format, tests, build, rules",
35534
+ documentation_sync: "syncing the docs this change touched",
35535
+ delivery: "delivering per the branch and PR conventions"
35536
+ };
35537
+ function stageNarrationLine(stage) {
35538
+ const text = STAGE_NARRATION[stage];
35539
+ return text ? `\u25B8 paqad \xB7 ${text}` : "";
35540
+ }
35541
+ function markerNarrationLine(stage, phase) {
35542
+ if (!STAGE_NARRATION[stage]) return "";
35543
+ if (phase === "start") return stageNarrationLine(stage);
35544
+ return `\u25B8 paqad \xB7 ${stage.replace(/_/g, " ")} done \u2014 evidence recorded in the ledger`;
35545
+ }
35546
+
35547
+ // src/cli/commands/stage.ts
35548
+ function createStageCommand() {
35549
+ return new Command21("stage").description(
35550
+ "Mark a feature-development stage boundary in the stage-evidence ledger (clears the pre-code block for planning/specification)"
35551
+ ).argument("<phase>", "'start' or 'end'").argument("<stage>", `one of: ${STAGE_ORDER.join(", ")}`).option("--project-root <path>", "Project root", process.cwd()).option(
35552
+ "--session <id>",
35553
+ "Session id to record under (defaults to SE_SESSION / CLAUDE_SESSION_ID, then the shared ledger-session cache)"
35554
+ ).action((phase, stage, options) => {
35555
+ if (phase !== "start" && phase !== "end") {
35556
+ console.error(`unknown phase "${phase}" \u2014 use 'start' or 'end'`);
35557
+ process.exitCode = 1;
35558
+ return;
35559
+ }
35560
+ const root = options.projectRoot;
35561
+ const sessionId = resolveSessionId(
35562
+ root,
35563
+ options.session ?? process.env.SE_SESSION ?? process.env.CLAUDE_SESSION_ID ?? null
35564
+ );
35565
+ const recorded = recordMarkedStage(root, { sessionId, stage, phase });
35566
+ if (!recorded) {
35567
+ console.error(
35568
+ `could not record "${stage} ${phase}" \u2014 unknown stage "${stage}". Stages, in order: ${STAGE_ORDER.join(", ")}`
35569
+ );
35570
+ process.exitCode = 1;
35571
+ return;
35572
+ }
35573
+ const line = markerNarrationLine(stage, phase);
35574
+ if (line) console.log(line);
35575
+ console.log(JSON.stringify({ recorded: true, stage, phase }));
35576
+ });
35577
+ }
35578
+
35329
35579
  // src/cli/commands/status.ts
35330
35580
  init_esm_shims();
35331
35581
  import { resolve as resolve14 } from "path";
35332
- import { Command as Command21 } from "commander";
35582
+ import { Command as Command22 } from "commander";
35333
35583
  init_reconciler();
35334
35584
  function collectDriftSignals(projectRoot) {
35335
35585
  const drift = readDriftReport(projectRoot);
@@ -35349,7 +35599,7 @@ function driftSignalsTrip(signals) {
35349
35599
  return signals.mmFindings > 0 || signals.staleModules.length > 0 || signals.expiredDecisions.length > 0 || signals.mmDocMissing > 0 || signals.blocked !== null;
35350
35600
  }
35351
35601
  function createStatusCommand() {
35352
- return new Command21("status").description("Print a one-shot dashboard report (Markdown or JSON)").option("--format <fmt>", "Output format: markdown | json", "markdown").option("--project-root <path>", "Project root", process.cwd()).option(
35602
+ return new Command22("status").description("Print a one-shot dashboard report (Markdown or JSON)").option("--format <fmt>", "Output format: markdown | json", "markdown").option("--project-root <path>", "Project root", process.cwd()).option(
35353
35603
  "--fail-on-drift",
35354
35604
  "Exit non-zero when module-map drift, stale module-health, expired MD-XXXX decisions, or MM-DOC-MISSING findings are present",
35355
35605
  false
@@ -35391,9 +35641,9 @@ function createStatusCommand() {
35391
35641
 
35392
35642
  // src/cli/commands/update.ts
35393
35643
  init_esm_shims();
35394
- import { Command as Command22 } from "commander";
35644
+ import { Command as Command23 } from "commander";
35395
35645
  function createUpdateCommand() {
35396
- return new Command22("update").description("Update framework-managed artifacts").option("--project-root <path>", "Project root", process.cwd()).option("--silent", "Suppress output; write results to audit log only").action(async (options) => {
35646
+ return new Command23("update").description("Update framework-managed artifacts").option("--project-root <path>", "Project root", process.cwd()).option("--silent", "Suppress output; write results to audit log only").action(async (options) => {
35397
35647
  try {
35398
35648
  const report = await new FrameworkUpdater().run(options.projectRoot);
35399
35649
  if (!options.silent) {
@@ -35417,7 +35667,7 @@ function createUpdateCommand() {
35417
35667
 
35418
35668
  // src/cli/program.ts
35419
35669
  function createProgram() {
35420
- const program = new Command23();
35670
+ const program = new Command24();
35421
35671
  program.name("paqad-ai").description("AI Agency Framework for software agencies").version(VERSION).showSuggestionAfterError(true);
35422
35672
  program.addCommand(createInstallCommand());
35423
35673
  program.addCommand(createCapabilitiesCommand());
@@ -35440,6 +35690,7 @@ function createProgram() {
35440
35690
  program.addCommand(createRagEvidenceCommand());
35441
35691
  program.addCommand(createUpdateCommand());
35442
35692
  program.addCommand(createPatternsCommand());
35693
+ program.addCommand(createStageCommand());
35443
35694
  program.addCommand(createStatusCommand());
35444
35695
  return program;
35445
35696
  }