paqad-ai 1.41.1 → 1.43.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +17 -11
  3. package/dist/cli/index.js +63 -5
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/context/tokenizer-cache.d.ts +18 -0
  6. package/dist/context/tokenizer-cache.js +42 -0
  7. package/dist/context/tokenizer-cache.js.map +1 -0
  8. package/dist/{feature-development-policy-CTmYgPS5.d.ts → feature-development-policy-CeD5nYnf.d.ts} +2 -0
  9. package/dist/index.d.ts +13 -20
  10. package/dist/index.js +53 -7
  11. package/dist/index.js.map +1 -1
  12. package/dist/kernel/gate.js +13 -2
  13. package/dist/kernel/gate.js.map +1 -1
  14. package/dist/session-ledger/project-ledger.d.ts +17 -0
  15. package/dist/session-ledger/project-ledger.js +443 -0
  16. package/dist/session-ledger/project-ledger.js.map +1 -0
  17. package/dist/stage-evidence/live-writer.d.ts +2 -2
  18. package/dist/stage-evidence/live-writer.js +11 -1
  19. package/dist/stage-evidence/live-writer.js.map +1 -1
  20. package/dist/stage-evidence/marker-parse.d.ts +2 -2
  21. package/dist/stage-evidence/marker-parse.js +11 -1
  22. package/dist/stage-evidence/marker-parse.js.map +1 -1
  23. package/dist/stage-evidence/narration.d.ts +2 -2
  24. package/dist/stage-evidence/narration.js +11 -1
  25. package/dist/stage-evidence/narration.js.map +1 -1
  26. package/dist/{stages-B-5fe_GW.d.ts → stages-DwQ5X3Bd.d.ts} +1 -1
  27. package/package.json +1 -1
  28. package/runtime/AGENT-BOOTSTRAP.md +1 -1
  29. package/runtime/hooks/agent-entry-gate.mjs +1 -1
  30. package/runtime/hooks/agent-entry-prompt-gate.mjs +1 -1
  31. package/runtime/hooks/context-refresh-trigger.mjs +13 -2
  32. package/runtime/hooks/lib/context-seam-emit.mjs +21 -9
  33. package/runtime/scripts/context-seam.mjs +18 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # paqad-ai
2
2
 
3
+ ## 1.43.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3bc15df: Publish two measured, reproducible benchmark numbers with methodology and caveats
8
+ (issue #285). Adds read-only repo tooling: `scripts/measure-footprint.mjs` reports the
9
+ resident session-start token footprint per area (real tokenizer via
10
+ `src/context/tokenizer-cache.ts`, labelled char/4 fallback), and
11
+ `scripts/rule-findings-stats.mjs` reads the existing `rule-evidence` ledger via
12
+ `readProjectEvents` and buckets deterministic findings by ISO week. Results, method, run
13
+ counts, tokenizer version, per-tier applicability, and caveats live in
14
+ `docs/instructions/benchmarks/measured.md`. The two unbenchmarked "60-85%" README claims
15
+ are replaced with the measured 49-61% resident-load reduction and a link to the method.
16
+ No product behavior changes; `rag_enabled` stays default off.
17
+
18
+ ## 1.42.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 561665d: Token-neutral by default: lean rule loading is now the default delivery path (issue #284).
23
+
24
+ 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.
25
+
3
26
  ## 1.41.1
4
27
 
5
28
  ### Patch Changes
package/README.md CHANGED
@@ -52,16 +52,16 @@ No account, no API key, no subscription. Prefer not to install anything? Run `np
52
52
 
53
53
  ## What you get, at a glance
54
54
 
55
- | Area | What it means for you |
56
- | ---------------------------- | -------------------------------------------------------------------------------- |
57
- | **One setup, every tool** | Configure Claude, Cursor, Copilot, Gemini, and the rest from one source of truth |
58
- | **Workflows, not prompts** | Your team's process runs the same way every time, instead of being re-typed |
59
- | **Proof, not promises** | Automatic checks confirm tests, specs, docs, and security before "done" counts |
60
- | **Security as a workflow** | A full OWASP pentest pass, with retests, built in |
61
- | **Design as a workflow** | Your UI audited against your own design system |
62
- | **Docs that stay current** | The framework keeps your documentation in sync with the code |
63
- | **Fewer tokens, on purpose** | Loads the right files, not the whole repo, cutting token use by 60-85% |
64
- | **Runs locally** | Your code stays on your machine, with an audit trail you can keep |
55
+ | Area | What it means for you |
56
+ | ---------------------------- | -------------------------------------------------------------------------------------- |
57
+ | **One setup, every tool** | Configure Claude, Cursor, Copilot, Gemini, and the rest from one source of truth |
58
+ | **Workflows, not prompts** | Your team's process runs the same way every time, instead of being re-typed |
59
+ | **Proof, not promises** | Automatic checks confirm tests, specs, docs, and security before "done" counts |
60
+ | **Security as a workflow** | A full OWASP pentest pass, with retests, built in |
61
+ | **Design as a workflow** | Your UI audited against your own design system |
62
+ | **Docs that stay current** | The framework keeps your documentation in sync with the code |
63
+ | **Fewer tokens, on purpose** | Loads a lean resident slice, not the whole repo. Measured 49-61% smaller resident load |
64
+ | **Runs locally** | Your code stays on your machine, with an audit trail you can keep |
65
65
 
66
66
  The rest of this page walks through each of these. The [full docs](https://paqad.ai/docs.html) go deeper on every command and concept.
67
67
 
@@ -267,7 +267,13 @@ Documentation is a real output here, not an afterthought you maintain by hand. A
267
267
 
268
268
  ## The right context, with fewer tokens
269
269
 
270
- Your agent does not need your whole repo. It needs the right files. And since every model gets worse on a bloated context, loading less is not just cheaper, it makes the answers better. paqad-ai cuts token use by **60-85%** through careful context loading.
270
+ Your agent does not need your whole repo. It needs the right files. And since every model gets worse on a bloated context, loading less is not just cheaper, it makes the answers better.
271
+
272
+ paqad-ai keeps the session-start load lean: a rule manifest plus the files a task actually touches, instead of the whole rule tree. Measured across two projects, that resident load is **49-61% smaller** than loading everything (paqad-ai's own repo: 61%; a fresh React onboard: 49%). Both used the char/4 heuristic tokenizer, so treat them as an honest floor, not a marketing ceiling. The method, the per-project numbers, and the caveats are in [`docs/instructions/benchmarks/measured.md`](docs/instructions/benchmarks/measured.md), and you can reproduce them in your own repo:
273
+
274
+ ```
275
+ node scripts/measure-footprint.mjs --project .
276
+ ```
271
277
 
272
278
  - It splits files at natural boundaries (functions and classes), not at arbitrary line counts.
273
279
  - It ranks each piece by five signals: meaning, keywords, the symbols involved, how close the file is to the task, and how deeply nested it is.
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.1";
26125
+ var VERSION = "1.43.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" }