paqad-ai 1.41.0 → 1.42.0

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,26 @@
1
1
  # paqad-ai
2
2
 
3
+ ## 1.42.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 561665d: Token-neutral by default: lean rule loading is now the default delivery path (issue #284).
8
+
9
+ A new `lean_rules` flag (default **on**, env `PAQAD_LEAN_RULES`) makes the always-resident rule manifest plus trigger-loaded applicable rule text the default, instead of loading the whole `docs/instructions/rules` tree every session. The framework bootstrap and the Claude Code prompt-gate now read `.paqad/context/session-context.md` artifact-first, falling back to the full rule load only when the artifact is missing. On Claude Code the session-time seam and the background refresh trigger are ungated from `rag_enabled` so the rule slice is injected and kept current with no embedding, index, or provider call on the lean path; `rag_enabled` continues to govern only what retrieval/memory/drift sections compose into the same artifact. A committed resident-footprint budget test and a `paqad-ai doctor` readout gate the token cost. `lean_rules=false` restores the previous full-load behaviour exactly, and paqad-disabled stays a pure no-op.
10
+
11
+ ## 1.41.1
12
+
13
+ ### Patch Changes
14
+
15
+ - 2137219: Rule-script whole-tree scan now respects `.gitignore`. Previously the scanner
16
+ enumerated the working tree with a fixed ignore list (`node_modules`, `dist`,
17
+ `.paqad`, `build`) and never consulted the project's `.gitignore`, so gitignored
18
+ build output, vendored dependencies, and generated code were still scanned —
19
+ producing `deterministic` findings on files the developer cannot hand-fix and
20
+ blocking the strict `rule_compliance` gate. The scan now drops git-ignored paths
21
+ via a batched `git check-ignore` (falling back to the static list when git is
22
+ unavailable), and adds `vendor/` to that fallback list.
23
+
3
24
  ## 1.41.0
4
25
 
5
26
  ### Minor Changes
package/dist/cli/index.js CHANGED
@@ -665,7 +665,8 @@ function resolveFrameworkConfigFromMap(raw) {
665
665
  market_research: rb("market_research"),
666
666
  design_research: rb("design_research"),
667
667
  team_agents: rb("team_agents"),
668
- analytics_instrumentation: rb("analytics_instrumentation")
668
+ analytics_instrumentation: rb("analytics_instrumentation"),
669
+ lean_rules: rb("lean_rules")
669
670
  },
670
671
  research: {
671
672
  depth: asEnum(
@@ -1023,6 +1024,7 @@ function frameworkOverridesToFlat(overrides) {
1023
1024
  f.analytics_instrumentation,
1024
1025
  d.features.analytics_instrumentation
1025
1026
  );
1027
+ put("lean_rules", f.lean_rules, d.features.lean_rules);
1026
1028
  }
1027
1029
  if (overrides.research) {
1028
1030
  put("research_depth", overrides.research.depth, d.research.depth);
@@ -1233,6 +1235,15 @@ var init_framework_config = __esm({
1233
1235
  section: "Feature flags",
1234
1236
  comment: "Opt in to complementary analytics instrumentation (issue #241, refined #279). OFF (default) is silent; ON authorizes wiring tracking + a per-event tracking-plan doc."
1235
1237
  },
1238
+ {
1239
+ key: "lean_rules",
1240
+ env: "PAQAD_LEAN_RULES",
1241
+ type: "boolean",
1242
+ default: true,
1243
+ group: "app",
1244
+ section: "Feature flags",
1245
+ comment: "Token-neutral rule loading (issue #284). ON (default) delivers the lean rule contract (manifest + only the rule text that applies to the files in play) and lifts the full-load mandate. OFF restores loading docs/instructions/rules in full every session."
1246
+ },
1236
1247
  // ── rag group ──────────────────────────────────────────────────────────
1237
1248
  {
1238
1249
  key: "rag_enabled",
@@ -1580,7 +1591,8 @@ var init_framework_config = __esm({
1580
1591
  "market_research",
1581
1592
  "design_research",
1582
1593
  "team_agents",
1583
- "analytics_instrumentation"
1594
+ "analytics_instrumentation",
1595
+ "lean_rules"
1584
1596
  ]
1585
1597
  },
1586
1598
  { present: (p) => p.research !== void 0, keys: ["research_depth"] },
@@ -3464,7 +3476,8 @@ var init_project_profile_schema = __esm({
3464
3476
  market_research: { type: "boolean" },
3465
3477
  design_research: { type: "boolean" },
3466
3478
  team_agents: { type: "boolean" },
3467
- analytics_instrumentation: { type: "boolean" }
3479
+ analytics_instrumentation: { type: "boolean" },
3480
+ lean_rules: { type: "boolean" }
3468
3481
  }
3469
3482
  },
3470
3483
  enterprise: {
@@ -18266,6 +18279,7 @@ var HealthChecker = class {
18266
18279
  this.checkMcp(projectRoot, profile),
18267
18280
  this.checkSkillCache(projectRoot),
18268
18281
  this.checkContextHitRate(projectRoot, profile),
18282
+ this.checkLeanRuleFootprint(projectRoot),
18269
18283
  this.checkClassificationOverrideRate(projectRoot),
18270
18284
  ...await this.checkRag(projectRoot, profile)
18271
18285
  ];
@@ -18794,6 +18808,37 @@ var HealthChecker = class {
18794
18808
  mcp_usage_rate: 0
18795
18809
  };
18796
18810
  }
18811
+ /**
18812
+ * Issue #284 — the resident rule-footprint readout. Reports how many bytes the lean
18813
+ * session-context artifact carries versus loading the full `docs/instructions/rules`
18814
+ * tree, computed per project (no hard-coded sizes). A present, smaller artifact is a
18815
+ * pass with the savings; an artifact that is not smaller than the full rule set warns
18816
+ * (lean loading is not paying off). A missing artifact is a pass: full-load is the
18817
+ * documented fallback and the artifact regenerates on the next refresh/onboard.
18818
+ */
18819
+ checkLeanRuleFootprint(projectRoot) {
18820
+ const name = "Lean rule footprint acceptable";
18821
+ const rulesRoot = join58(projectRoot, PATHS.RULES_DIR);
18822
+ if (!existsSync32(rulesRoot)) {
18823
+ return pass(name, "No rules directory to load \u2014 nothing to slim");
18824
+ }
18825
+ const fullRulesBytes = walk2(rulesRoot).filter((file) => file.endsWith(".md")).reduce((sum2, file) => sum2 + statSync4(file).size, 0);
18826
+ const artifactPath = join58(projectRoot, PATHS.CONTEXT_SESSION_ARTIFACT);
18827
+ if (!existsSync32(artifactPath)) {
18828
+ return pass(
18829
+ name,
18830
+ "Lean rule artifact not generated yet \u2014 full rule load is the fallback until the next refresh"
18831
+ );
18832
+ }
18833
+ const residentBytes = statSync4(artifactPath).size;
18834
+ const pct = fullRulesBytes > 0 ? Math.round(residentBytes / fullRulesBytes * 100) : 0;
18835
+ const detail = `Resident rule context is ${residentBytes} bytes vs ${fullRulesBytes} bytes for the full rule set (${pct}% of full)`;
18836
+ return residentBytes < fullRulesBytes || fullRulesBytes === 0 ? pass(name, detail) : warn(
18837
+ name,
18838
+ `${detail} \u2014 lean loading is not reducing the resident footprint`,
18839
+ "Ensure lean_rules is on and re-run `paqad-ai rag refresh-context` to recompose the lean artifact."
18840
+ );
18841
+ }
18797
18842
  checkClassificationOverrideRate(projectRoot) {
18798
18843
  const path11 = join58(projectRoot, PATHS.AGENCY_CACHE_DIR, "classification-history.json");
18799
18844
  if (!existsSync32(path11)) {
@@ -23982,7 +24027,8 @@ function buildProjectProfile(selections, snapshot, overrides, projectRoot) {
23982
24027
  market_research: false,
23983
24028
  design_research: false,
23984
24029
  team_agents: true,
23985
- analytics_instrumentation: false
24030
+ analytics_instrumentation: false,
24031
+ lean_rules: true
23986
24032
  },
23987
24033
  // Issue #187 — emit the enterprise block at onboarding so the opt-in
23988
24034
  // evidence-ledger / AI-BOM / compliance-citation switches are visible and
@@ -26076,7 +26122,7 @@ init_cancelled_error();
26076
26122
  init_events();
26077
26123
 
26078
26124
  // src/index.ts
26079
- var VERSION = "1.41.0";
26125
+ var VERSION = "1.42.0";
26080
26126
 
26081
26127
  // src/cli/commands/audit.ts
26082
26128
  init_esm_shims();
@@ -33845,6 +33891,7 @@ import { readFileSync as readFileSync76 } from "fs";
33845
33891
  import { isAbsolute as isAbsolute5, join as join174 } from "path";
33846
33892
  import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
33847
33893
  import { Command as Command18 } from "commander";
33894
+ init_framework_config();
33848
33895
 
33849
33896
  // src/context/codebase-memory.ts
33850
33897
  init_esm_shims();
@@ -34808,6 +34855,17 @@ function createRagCommand() {
34808
34855
  command.command("refresh-context").description(
34809
34856
  "Sync the index, retrieve slices, and recompose session context (background worker)"
34810
34857
  ).option("--project-root <path>", "Project root", process.cwd()).option("--quiet", "Suppress output (used by the background trigger)").action(async (options) => {
34858
+ const ragEnabled = resolveFrameworkConfig(options.projectRoot).intelligence.rag_enabled;
34859
+ if (!ragEnabled) {
34860
+ const target2 = await refreshRuleContext(options.projectRoot, {});
34861
+ if (!options.quiet) {
34862
+ process.stdout.write(
34863
+ `${target2 ? `wrote ${target2}` : "nothing to compose"}; rule-only (rag off)
34864
+ `
34865
+ );
34866
+ }
34867
+ return;
34868
+ }
34811
34869
  const sync = await backgroundIndexSync(options.projectRoot);
34812
34870
  const slices = await gatherWorkingSetSlices(options.projectRoot, {
34813
34871
  recordEvidence: { adapter: "engine" }