paqad-ai 1.46.0 → 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,16 @@
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
+
3
14
  ## 1.46.0
4
15
 
5
16
  ### Minor Changes
package/dist/cli/index.js CHANGED
@@ -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((relative25) => !existsSync32(join58(projectRoot, relative25)));
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(", ")}`,
@@ -25973,16 +25973,21 @@ init_session();
25973
25973
  // src/stage-evidence/stages.ts
25974
25974
  init_esm_shims();
25975
25975
  var STAGE_EVIDENCE_STAGES = [...STAGE_ORDER];
25976
- var COMPLETION_ANCHORED_STAGES = ["review"];
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
+ );
25977
25988
  function isKnownStage(stage) {
25978
25989
  return STAGE_EVIDENCE_STAGES.includes(stage);
25979
25990
  }
25980
- function isCompletionAnchoredStage(stage) {
25981
- return COMPLETION_ANCHORED_STAGES.includes(stage);
25982
- }
25983
- function stageIndex(stage) {
25984
- return STAGE_EVIDENCE_STAGES.indexOf(stage);
25985
- }
25986
25991
 
25987
25992
  // src/stage-evidence/recorder.ts
25988
25993
  var APPEND_OPTS3 = (now) => ({
@@ -26014,29 +26019,12 @@ function resolveOrdinal2(projectRoot, sessionId, ctx) {
26014
26019
  }
26015
26020
  return openStageEvidence(projectRoot, ctx).ordinal;
26016
26021
  }
26017
- function highestStartedIndex(rows) {
26018
- let highest = -1;
26019
- for (const row of rows) {
26020
- if (row.kind === "stage_start" && typeof row.stage === "string") {
26021
- highest = Math.max(highest, stageIndex(row.stage));
26022
- }
26023
- }
26024
- return highest;
26025
- }
26026
26022
  function startStage(projectRoot, stage, ctx) {
26027
26023
  if (!isKnownStage(stage)) {
26028
26024
  throw new Error(`Unknown stage "${stage}" \u2014 not in the feature-development registry.`);
26029
26025
  }
26030
26026
  const sessionId = resolveSessionId(projectRoot, ctx.sessionId);
26031
26027
  const ordinal = resolveOrdinal2(projectRoot, sessionId, ctx);
26032
- const rows = readSessionUnit(projectRoot, STAGE_EVIDENCE_DOC_TYPE, sessionId, ordinal);
26033
- const highest = highestStartedIndex(rows);
26034
- const index = stageIndex(stage);
26035
- if (!isCompletionAnchoredStage(stage) && highest >= 0 && index < highest) {
26036
- throw new Error(
26037
- `Out-of-order stage "${stage}": a later stage already started. Stages must run in registry order.`
26038
- );
26039
- }
26040
26028
  return append(projectRoot, sessionId, ordinal, ctx, {
26041
26029
  kind: "stage_start",
26042
26030
  stage,
@@ -26106,6 +26094,10 @@ init_session();
26106
26094
  init_esm_shims();
26107
26095
  init_framework_config();
26108
26096
 
26097
+ // src/stage-evidence/scope.ts
26098
+ init_esm_shims();
26099
+ import { isAbsolute as isAbsolute3, relative as relative22 } from "pathe";
26100
+
26109
26101
  // src/verification/repository/verdict.ts
26110
26102
  init_esm_shims();
26111
26103
 
@@ -26253,7 +26245,7 @@ init_esm_shims();
26253
26245
  init_esm_shims();
26254
26246
  init_logger_registry();
26255
26247
  import { mkdir as mkdir45, writeFile as writeFile45 } from "fs/promises";
26256
- import { join as join134, relative as relative22 } from "path";
26248
+ import { join as join134, relative as relative23 } from "path";
26257
26249
  init_paths();
26258
26250
  init_path_utils();
26259
26251
 
@@ -26295,7 +26287,7 @@ init_cancelled_error();
26295
26287
  init_events();
26296
26288
 
26297
26289
  // src/index.ts
26298
- var VERSION = "1.46.0";
26290
+ var VERSION = "1.46.1";
26299
26291
 
26300
26292
  // src/cli/commands/audit.ts
26301
26293
  init_esm_shims();
@@ -27294,7 +27286,7 @@ function resolveRelativeSpec(projectRoot, spec) {
27294
27286
  init_esm_shims();
27295
27287
  init_paths();
27296
27288
  import { existsSync as existsSync98 } from "fs";
27297
- 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";
27298
27290
  import { fileURLToPath as fileURLToPath3 } from "url";
27299
27291
  import { Command as Command4 } from "commander";
27300
27292
 
@@ -27392,7 +27384,7 @@ function buildNodeDetail(graph, nodeId, options) {
27392
27384
  init_esm_shims();
27393
27385
  import { existsSync as existsSync70 } from "fs";
27394
27386
  import { readFile as readFile69, readdir as readdir15, stat as stat8 } from "fs/promises";
27395
- 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";
27396
27388
  init_paths();
27397
27389
  var KNOWN_TIERS = /* @__PURE__ */ new Set(["green", "amber", "red", "unknown"]);
27398
27390
  function normaliseTier(value) {
@@ -27430,7 +27422,7 @@ function languageFromExtension(filePath) {
27430
27422
  return map[ext] ?? null;
27431
27423
  }
27432
27424
  function toProjectRelative2(projectRoot, absolutePath) {
27433
- const rel = relative23(projectRoot, absolutePath);
27425
+ const rel = relative24(projectRoot, absolutePath);
27434
27426
  return rel === "" ? "." : rel.split(sep6).join("/");
27435
27427
  }
27436
27428
  function moduleNameForFile(relativePath, knownModules) {
@@ -29289,12 +29281,12 @@ import { existsSync as existsSync78, readdirSync as readdirSync15 } from "fs";
29289
29281
  import { join as join148 } from "path";
29290
29282
  import YAML19 from "yaml";
29291
29283
  var EDITABLE_EXTENSIONS = [".md", ".yml", ".yaml", ".json"];
29292
- function buildNode(absolute, relative25, name) {
29284
+ function buildNode(absolute, relative26, name) {
29293
29285
  const entries = readdirSync15(absolute, { withFileTypes: true });
29294
29286
  const children = [];
29295
29287
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
29296
29288
  if (entry.name.startsWith(".")) continue;
29297
- const childRelative = relative25 === "" ? entry.name : `${relative25}/${entry.name}`;
29289
+ const childRelative = relative26 === "" ? entry.name : `${relative26}/${entry.name}`;
29298
29290
  if (entry.isDirectory()) {
29299
29291
  const child = buildNode(join148(absolute, entry.name), childRelative, entry.name);
29300
29292
  if (child) children.push(child);
@@ -29302,7 +29294,7 @@ function buildNode(absolute, relative25, name) {
29302
29294
  children.push({ path: childRelative, name: entry.name, type: "file" });
29303
29295
  }
29304
29296
  }
29305
- return { path: relative25, name, type: "directory", children };
29297
+ return { path: relative26, name, type: "directory", children };
29306
29298
  }
29307
29299
  function listInstructionsTree(projectRoot) {
29308
29300
  const root = join148(projectRoot, PATHS.INSTRUCTIONS_DIR);
@@ -29415,7 +29407,7 @@ function counted(count, singular, plural, zero) {
29415
29407
  }
29416
29408
  function buildInventory(projectRoot, options = {}) {
29417
29409
  const paqadHome = options.paqadHome ?? join149(homedir10(), ".paqad-ai");
29418
- const at = (relative25) => join149(projectRoot, relative25);
29410
+ const at = (relative26) => join149(projectRoot, relative26);
29419
29411
  const profile = parseYamlFile(at(PATHS.PROJECT_PROFILE));
29420
29412
  const activeCapabilities = Array.isArray(profile?.active_capabilities) ? profile.active_capabilities : [];
29421
29413
  const intelligence = profile?.intelligence ?? null;
@@ -29937,7 +29929,7 @@ function dirHasEntries(path11) {
29937
29929
  }
29938
29930
  }
29939
29931
  function buildOnboardingChecklist(projectRoot) {
29940
- const at = (relative25) => join150(projectRoot, relative25);
29932
+ const at = (relative26) => join150(projectRoot, relative26);
29941
29933
  const agentConnected = [PATHS.CLAUDE_MD, PATHS.AGENTS_MD, PATHS.ANTIGRAVITY_MD, PATHS.GEMINI_MD].some(
29942
29934
  (entry) => existsSync80(at(entry))
29943
29935
  ) && existsSync80(at(PATHS.ONBOARDING_MANIFEST));
@@ -32687,14 +32679,14 @@ data: ${JSON.stringify(data)}
32687
32679
  return;
32688
32680
  }
32689
32681
  if (instructionsFileMatch && req.method === "PUT") {
32690
- const relative25 = decodeURIComponent(instructionsFileMatch[1]);
32682
+ const relative26 = decodeURIComponent(instructionsFileMatch[1]);
32691
32683
  await handleMutation(req, res, async () => {
32692
32684
  const body = await readJsonBody2(req);
32693
32685
  if (typeof body.content !== "string") {
32694
32686
  throw new Error("Body must include the file `content` as a string.");
32695
32687
  }
32696
32688
  return writeManagedFile(options.projectRoot, {
32697
- relativePath: `${PATHS.INSTRUCTIONS_DIR}/${relative25}`,
32689
+ relativePath: `${PATHS.INSTRUCTIONS_DIR}/${relative26}`,
32698
32690
  content: body.content,
32699
32691
  baseHash: typeof body.baseHash === "string" ? body.baseHash : null,
32700
32692
  action: "dashboard.instructions.write"
@@ -33010,7 +33002,7 @@ function openBrowser(options) {
33010
33002
  var DEFAULT_PORT = 5372;
33011
33003
  function resolveStaticDir(override) {
33012
33004
  if (override) {
33013
- return isAbsolute3(override) ? override : resolve10(process.cwd(), override);
33005
+ return isAbsolute4(override) ? override : resolve10(process.cwd(), override);
33014
33006
  }
33015
33007
  const here = dirname69(fileURLToPath3(import.meta.url));
33016
33008
  const candidates = [
@@ -33210,14 +33202,14 @@ function createEvidenceCommand() {
33210
33202
  init_esm_shims();
33211
33203
  init_paths();
33212
33204
  import { existsSync as existsSync99 } from "fs";
33213
- 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";
33214
33206
  import { fileURLToPath as fileURLToPath4 } from "url";
33215
33207
  import { Command as Command9 } from "commander";
33216
33208
  var DEFAULT_PORT2 = 5372;
33217
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.";
33218
33210
  function resolveStaticDir2(override) {
33219
33211
  if (override) {
33220
- return isAbsolute4(override) ? override : resolve12(process.cwd(), override);
33212
+ return isAbsolute5(override) ? override : resolve12(process.cwd(), override);
33221
33213
  }
33222
33214
  const here = dirname71(fileURLToPath4(import.meta.url));
33223
33215
  const candidates = [
@@ -34061,7 +34053,7 @@ function createPacksCommand() {
34061
34053
  init_esm_shims();
34062
34054
  init_project_intelligence();
34063
34055
  import { readFileSync as readFileSync76 } from "fs";
34064
- import { isAbsolute as isAbsolute5, join as join174 } from "path";
34056
+ import { isAbsolute as isAbsolute6, join as join174 } from "path";
34065
34057
  import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
34066
34058
  import { Command as Command18 } from "commander";
34067
34059
  init_framework_config();
@@ -35048,7 +35040,7 @@ function createRagCommand() {
35048
35040
  readFile: (path11) => {
35049
35041
  try {
35050
35042
  return readFileSync76(
35051
- isAbsolute5(path11) ? path11 : join174(options.projectRoot, path11),
35043
+ isAbsolute6(path11) ? path11 : join174(options.projectRoot, path11),
35052
35044
  "utf8"
35053
35045
  );
35054
35046
  } catch {
@@ -35508,7 +35500,7 @@ init_session();
35508
35500
  init_esm_shims();
35509
35501
  init_ledger();
35510
35502
  init_session();
35511
- import { isAbsolute as isAbsolute6, relative as relative24 } from "pathe";
35503
+ import { isAbsolute as isAbsolute7, relative as relative25 } from "pathe";
35512
35504
  function recordMarkedStage(projectRoot, input3) {
35513
35505
  if (!isKnownStage(input3.stage)) return false;
35514
35506
  const ctx = {
@@ -35573,7 +35565,7 @@ function createStageCommand() {
35573
35565
  const recorded = recordMarkedStage(root, { sessionId, stage, phase });
35574
35566
  if (!recorded) {
35575
35567
  console.error(
35576
- `could not record "${stage} ${phase}" \u2014 unknown stage or out-of-order boundary. Stages, in order: ${STAGE_ORDER.join(", ")}`
35568
+ `could not record "${stage} ${phase}" \u2014 unknown stage "${stage}". Stages, in order: ${STAGE_ORDER.join(", ")}`
35577
35569
  );
35578
35570
  process.exitCode = 1;
35579
35571
  return;