paqad-ai 1.58.0 → 1.60.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 +24 -0
- package/dist/cli/index.js +367 -35
- package/dist/cli/index.js.map +1 -1
- package/dist/{feature-development-policy-BU3ikY71.d.ts → feature-development-policy-C-X0Wwyb.d.ts} +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +88 -18
- package/dist/index.js.map +1 -1
- package/dist/kernel/gate.js +15 -1
- package/dist/kernel/gate.js.map +1 -1
- package/dist/rule-scripts/index.js +14 -1
- package/dist/rule-scripts/index.js.map +1 -1
- package/dist/stage-evidence/live-writer.d.ts +2 -2
- package/dist/stage-evidence/live-writer.js +14 -1
- package/dist/stage-evidence/live-writer.js.map +1 -1
- package/dist/stage-evidence/marker-parse.d.ts +2 -2
- package/dist/stage-evidence/marker-parse.js +14 -1
- package/dist/stage-evidence/marker-parse.js.map +1 -1
- package/dist/stage-evidence/narration.d.ts +2 -2
- package/dist/stage-evidence/narration.js +14 -1
- package/dist/stage-evidence/narration.js.map +1 -1
- package/dist/{stages-B2ozdF12.d.ts → stages-DUIvMjp6.d.ts} +1 -1
- package/package.json +1 -1
- package/runtime/scripts/verify-backstop.mjs +61 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# paqad-ai
|
|
2
2
|
|
|
3
|
+
## 1.60.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2b2ee2c: Planning now sees the codebase: on the feature-development route, the background context
|
|
8
|
+
worker composes a token-capped `## Existing surface` section into the session-context
|
|
9
|
+
artifact. It lists the exported symbols that already exist for the files/modules the prompt
|
|
10
|
+
and working set implicate — as signature cards (`name(signature) — file:line · called from N
|
|
11
|
+
places · module`) ranked by the repo-map's structural importance (PageRank) — so the model
|
|
12
|
+
reuses what exists instead of rewriting it. Signatures and caller counts come from the
|
|
13
|
+
code-knowledge index when present, falling back to name-only cards otherwise. The section is
|
|
14
|
+
budget-capped (config `existing_surface_tokens`, default 1000) with an honest truncation
|
|
15
|
+
line, appears only for feature-development (every other route stays token-neutral), and rides
|
|
16
|
+
the existing artifact so Codex/Gemini/advisory hosts get it through the same file. This gives
|
|
17
|
+
the built-but-unconsumed repo-map its first live consumer.
|
|
18
|
+
|
|
19
|
+
## 1.59.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- deb1cb9: Make the end-of-change verdict visible, honest, and enforced (#368). The completion backstop now surfaces the one end-of-change receipt to the developer whether the verdict passes, fails, or is inconclusive — a failing "Needs your attention" verdict can no longer be hidden on stderr while a PR ships. A hard-failing feature-development change now blocks the turn at the Stop seam via the documented `decision:block` channel (exit 2 is a no-op there), bounded by the stop-hook loop guard. A feature-development change with no real `paqad-ai checks run` report reads as Inconclusive and shows its `checks` stage as unverified rather than done. The `checks.block_on_failure` escalation stays script-enforced; `review_findings` / `stale_docs` are documented as agent-raised and Decision-Pause-enforced rather than falsely claiming script enforcement. The cross-provider verdict tiering (hook-surfaced on Claude, agent-narrated on Codex/Gemini/advisory) is documented so the promise is truthful per host.
|
|
24
|
+
|
|
25
|
+
Also (AC-D2, from the second reproduction on the #355 session): the evidence receipt's `verification_result` is now three-way — `FAILED` only on a genuine failure, `INCONCLUSIVE` when a measure could not run (a `blocked` ratchet from unwired/absent tooling) or could not be judged, and `PASSED` when every row passed. A couldn't-verify is no longer reported as a failure, so an unwired quality-ratchet measure can no longer manufacture a false `FAILED` on the attestation.
|
|
26
|
+
|
|
3
27
|
## 1.58.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/dist/cli/index.js
CHANGED
|
@@ -359,6 +359,7 @@ function defaultIntelligenceConfig() {
|
|
|
359
359
|
rag_relief_floor: 0.35,
|
|
360
360
|
rag_top_n: 20,
|
|
361
361
|
rag_max_file_size: 153600,
|
|
362
|
+
existing_surface_tokens: DEFAULT_EXISTING_SURFACE_TOKENS,
|
|
362
363
|
benchmark_gates: { ...DEFAULT_BENCHMARK_GATES },
|
|
363
364
|
benchmark_eval: { ...DEFAULT_BENCHMARK_EVAL },
|
|
364
365
|
adaptive_retrieval: {
|
|
@@ -384,6 +385,7 @@ function normalizeIntelligenceConfig(input3) {
|
|
|
384
385
|
rag_relief_floor: input3.rag_relief_floor ?? defaults.rag_relief_floor,
|
|
385
386
|
rag_top_n: input3.rag_top_n ?? defaults.rag_top_n,
|
|
386
387
|
rag_max_file_size: input3.rag_max_file_size ?? defaults.rag_max_file_size,
|
|
388
|
+
existing_surface_tokens: input3.existing_surface_tokens ?? defaults.existing_surface_tokens,
|
|
387
389
|
rag_base_branch: input3.rag_base_branch ?? defaults.rag_base_branch,
|
|
388
390
|
benchmark_gates: {
|
|
389
391
|
...DEFAULT_BENCHMARK_GATES,
|
|
@@ -421,7 +423,7 @@ function normalizeIntelligenceConfig(input3) {
|
|
|
421
423
|
}
|
|
422
424
|
return normalized;
|
|
423
425
|
}
|
|
424
|
-
var EMBEDDING_PROVIDERS, LOCAL_EMBEDDING_MODELS, DEFAULT_LOCAL_EMBEDDING_MODEL, DEFAULT_BENCHMARK_EVAL, DEFAULT_ADAPTIVE_RETRIEVAL, DEFAULT_RERANKING, DEFAULT_METADATA_FILTERS, DEFAULT_ACTION_ROUTING, DEFAULT_BENCHMARK_GATES;
|
|
426
|
+
var EMBEDDING_PROVIDERS, LOCAL_EMBEDDING_MODELS, DEFAULT_LOCAL_EMBEDDING_MODEL, DEFAULT_BENCHMARK_EVAL, DEFAULT_ADAPTIVE_RETRIEVAL, DEFAULT_RERANKING, DEFAULT_METADATA_FILTERS, DEFAULT_ACTION_ROUTING, DEFAULT_EXISTING_SURFACE_TOKENS, DEFAULT_BENCHMARK_GATES;
|
|
425
427
|
var init_project_intelligence = __esm({
|
|
426
428
|
"src/core/project-intelligence.ts"() {
|
|
427
429
|
"use strict";
|
|
@@ -461,6 +463,7 @@ var init_project_intelligence = __esm({
|
|
|
461
463
|
DEFAULT_ACTION_ROUTING = {
|
|
462
464
|
enabled: false
|
|
463
465
|
};
|
|
466
|
+
DEFAULT_EXISTING_SURFACE_TOKENS = 1e3;
|
|
464
467
|
DEFAULT_BENCHMARK_GATES = {
|
|
465
468
|
hit_at_5_improvement_pct: 20,
|
|
466
469
|
task_success_rate_improvement_pct: 10,
|
|
@@ -665,7 +668,8 @@ function resolveFrameworkConfigFromMap(raw) {
|
|
|
665
668
|
rag_relief_floor: rn("rag_relief_floor"),
|
|
666
669
|
rag_top_n: rn("rag_top_n"),
|
|
667
670
|
rag_max_file_size: rn("rag_max_file_size"),
|
|
668
|
-
rag_base_branch: raw.get("rag_base_branch")?.trim() || void 0
|
|
671
|
+
rag_base_branch: raw.get("rag_base_branch")?.trim() || void 0,
|
|
672
|
+
existing_surface_tokens: rn("existing_surface_tokens")
|
|
669
673
|
});
|
|
670
674
|
return {
|
|
671
675
|
paqad: { enabled: rb("paqad_enable") },
|
|
@@ -1029,6 +1033,11 @@ function frameworkOverridesToFlat(overrides) {
|
|
|
1029
1033
|
put("rag_top_n", i.rag_top_n, d.intelligence.rag_top_n);
|
|
1030
1034
|
put("rag_max_file_size", i.rag_max_file_size, d.intelligence.rag_max_file_size);
|
|
1031
1035
|
put("rag_base_branch", i.rag_base_branch, d.intelligence.rag_base_branch);
|
|
1036
|
+
put(
|
|
1037
|
+
"existing_surface_tokens",
|
|
1038
|
+
i.existing_surface_tokens,
|
|
1039
|
+
d.intelligence.existing_surface_tokens
|
|
1040
|
+
);
|
|
1032
1041
|
}
|
|
1033
1042
|
if (overrides.strictness) {
|
|
1034
1043
|
const s = overrides.strictness;
|
|
@@ -1388,6 +1397,15 @@ var init_framework_config = __esm({
|
|
|
1388
1397
|
section: "Intelligence / RAG",
|
|
1389
1398
|
comment: "Base branch for branch-aware RAG. Unset auto-detects main->master."
|
|
1390
1399
|
},
|
|
1400
|
+
{
|
|
1401
|
+
key: "existing_surface_tokens",
|
|
1402
|
+
env: "PAQAD_EXISTING_SURFACE_TOKENS",
|
|
1403
|
+
type: "number",
|
|
1404
|
+
default: 1e3,
|
|
1405
|
+
group: "rag",
|
|
1406
|
+
section: "Intelligence / RAG",
|
|
1407
|
+
comment: 'Token budget for the feature-development "Existing surface" planning digest (existing symbols the model should reuse). Cards drop by rank past this budget.'
|
|
1408
|
+
},
|
|
1391
1409
|
// ── models group ───────────────────────────────────────────────────────
|
|
1392
1410
|
{
|
|
1393
1411
|
key: "research_depth",
|
|
@@ -1640,7 +1658,8 @@ var init_framework_config = __esm({
|
|
|
1640
1658
|
"rag_relief_floor",
|
|
1641
1659
|
"rag_top_n",
|
|
1642
1660
|
"rag_max_file_size",
|
|
1643
|
-
"rag_base_branch"
|
|
1661
|
+
"rag_base_branch",
|
|
1662
|
+
"existing_surface_tokens"
|
|
1644
1663
|
]
|
|
1645
1664
|
},
|
|
1646
1665
|
{
|
|
@@ -3638,6 +3657,7 @@ var init_project_profile_schema = __esm({
|
|
|
3638
3657
|
rag_top_n: { type: "integer", minimum: 1 },
|
|
3639
3658
|
rag_max_file_size: { type: "integer", minimum: 1 },
|
|
3640
3659
|
rag_base_branch: { type: "string" },
|
|
3660
|
+
existing_surface_tokens: { type: "integer", minimum: 1 },
|
|
3641
3661
|
benchmark_gates: {
|
|
3642
3662
|
type: "object",
|
|
3643
3663
|
additionalProperties: false,
|
|
@@ -8443,6 +8463,17 @@ function renderDefaultFeatureDevelopmentPolicyYaml() {
|
|
|
8443
8463
|
return `# Feature Development Stage Policy
|
|
8444
8464
|
# This file customizes how the built-in feature-development workflow behaves in this project.
|
|
8445
8465
|
# The framework still owns routing, phase order, and mandatory safety stages.
|
|
8466
|
+
#
|
|
8467
|
+
# Enforcement tiers (issue #368) \u2014 an escalation is honoured on one of two tiers, and
|
|
8468
|
+
# this contract never claims script enforcement it does not have:
|
|
8469
|
+
# - SCRIPT-ENFORCED (deterministic): checks.block_on_failure and the mandatory-stage
|
|
8470
|
+
# completeness gate. \`paqad-ai checks run\` exits non-zero on any red command and the
|
|
8471
|
+
# completion backstop reads its report; a feature-dev change with no report reads
|
|
8472
|
+
# Inconclusive, never a vacuous pass.
|
|
8473
|
+
# - AGENT-RAISED -> DECISION-PAUSE-ENFORCED: review.escalation.review_findings and
|
|
8474
|
+
# documentation_sync.escalation.stale_docs need model judgment to raise, so no script
|
|
8475
|
+
# detects them; once raised as a \`stop\`, the Decision-Pause gate holds edits until the
|
|
8476
|
+
# packet resolves. Not a false "a script proves this" promise.
|
|
8446
8477
|
schema_version: "1"
|
|
8447
8478
|
merge_mode: append
|
|
8448
8479
|
|
|
@@ -25056,10 +25087,12 @@ ${blocks}
|
|
|
25056
25087
|
async function writeRuleContext(projectRoot, options = {}) {
|
|
25057
25088
|
const loadRules = options.loadRules ?? true;
|
|
25058
25089
|
const store = loadRules ? await readCompiledRules(projectRoot) : null;
|
|
25090
|
+
const existingSurfaceSection = loadRules ? options.existingSurfaceSection?.trim() ?? "" : "";
|
|
25059
25091
|
const memorySection = options.memorySection?.trim() ?? "";
|
|
25060
25092
|
const retrievalSection = options.retrievalSection?.trim() ?? "";
|
|
25061
25093
|
const driftSection = options.driftSection?.trim() ?? "";
|
|
25062
|
-
if (!store && !memorySection && !retrievalSection && !driftSection)
|
|
25094
|
+
if (!store && !existingSurfaceSection && !memorySection && !retrievalSection && !driftSection)
|
|
25095
|
+
return null;
|
|
25063
25096
|
let markdown = "";
|
|
25064
25097
|
if (store) {
|
|
25065
25098
|
const changedPaths = (await loadChangeEvidence(projectRoot)).files;
|
|
@@ -25071,7 +25104,7 @@ ${DECISION_PAUSE_REMINDER}
|
|
|
25071
25104
|
`;
|
|
25072
25105
|
}
|
|
25073
25106
|
}
|
|
25074
|
-
for (const section of [memorySection, retrievalSection, driftSection]) {
|
|
25107
|
+
for (const section of [existingSurfaceSection, memorySection, retrievalSection, driftSection]) {
|
|
25075
25108
|
if (section) {
|
|
25076
25109
|
markdown = markdown ? `${markdown}
|
|
25077
25110
|
${section}
|
|
@@ -30327,7 +30360,7 @@ init_cancelled_error();
|
|
|
30327
30360
|
init_events();
|
|
30328
30361
|
|
|
30329
30362
|
// src/index.ts
|
|
30330
|
-
var VERSION = "1.
|
|
30363
|
+
var VERSION = "1.60.0";
|
|
30331
30364
|
|
|
30332
30365
|
// src/cli/commands/audit.ts
|
|
30333
30366
|
init_esm_shims();
|
|
@@ -33240,7 +33273,8 @@ var FIELD_CHECKS = {
|
|
|
33240
33273
|
rag_similarity_threshold: (value) => typeof value === "number" && value >= 0 && value <= 1 ? null : "Expected a number between 0 and 1.",
|
|
33241
33274
|
rag_top_n: (value) => typeof value === "number" && Number.isInteger(value) && value > 0 ? null : "Expected a positive integer.",
|
|
33242
33275
|
rag_max_file_size: (value) => typeof value === "number" && Number.isInteger(value) && value > 0 ? null : "Expected a positive integer.",
|
|
33243
|
-
rag_base_branch: (value) => typeof value === "string" ? null : "Expected a string."
|
|
33276
|
+
rag_base_branch: (value) => typeof value === "string" ? null : "Expected a string.",
|
|
33277
|
+
existing_surface_tokens: (value) => typeof value === "number" && Number.isInteger(value) && value > 0 ? null : "Expected a positive integer."
|
|
33244
33278
|
};
|
|
33245
33279
|
function putRagConfig(projectRoot, candidate) {
|
|
33246
33280
|
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
@@ -42477,6 +42511,7 @@ var KNOB_CONSUMERS = {
|
|
|
42477
42511
|
rag_top_n: "RAG retrieval depth",
|
|
42478
42512
|
rag_max_file_size: "RAG index build",
|
|
42479
42513
|
rag_base_branch: "branch-aware RAG index",
|
|
42514
|
+
existing_surface_tokens: "existing-surface planning digest",
|
|
42480
42515
|
research_depth: NOTHING,
|
|
42481
42516
|
model_default: "model selection (skills/model-selector)",
|
|
42482
42517
|
model_reasoning: "model routing (budget optimizer)",
|
|
@@ -42648,8 +42683,8 @@ function createDecisionCommand() {
|
|
|
42648
42683
|
// src/cli/commands/rag.ts
|
|
42649
42684
|
init_esm_shims();
|
|
42650
42685
|
init_project_intelligence();
|
|
42651
|
-
import { readFileSync as
|
|
42652
|
-
import { isAbsolute as isAbsolute11, join as
|
|
42686
|
+
import { readFileSync as readFileSync104 } from "fs";
|
|
42687
|
+
import { isAbsolute as isAbsolute11, join as join208 } from "path";
|
|
42653
42688
|
import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
|
|
42654
42689
|
import { Command as Command28 } from "commander";
|
|
42655
42690
|
|
|
@@ -42985,6 +43020,293 @@ ${lines}
|
|
|
42985
43020
|
`;
|
|
42986
43021
|
}
|
|
42987
43022
|
|
|
43023
|
+
// src/context/existing-surface.ts
|
|
43024
|
+
init_esm_shims();
|
|
43025
|
+
import { readFileSync as readFileSync101 } from "fs";
|
|
43026
|
+
import { join as join204 } from "path";
|
|
43027
|
+
init_project_intelligence();
|
|
43028
|
+
|
|
43029
|
+
// src/rag/repo-map.ts
|
|
43030
|
+
init_esm_shims();
|
|
43031
|
+
var PAGERANK_DAMPING = 0.85;
|
|
43032
|
+
function pageRank(seedNodes, edges, options = {}) {
|
|
43033
|
+
const damping = options.damping ?? PAGERANK_DAMPING;
|
|
43034
|
+
const iterations = options.iterations ?? 50;
|
|
43035
|
+
const tolerance = options.tolerance ?? 1e-6;
|
|
43036
|
+
const nodes = new Set(seedNodes);
|
|
43037
|
+
for (const edge of edges) {
|
|
43038
|
+
nodes.add(edge.from);
|
|
43039
|
+
nodes.add(edge.to);
|
|
43040
|
+
}
|
|
43041
|
+
const nodeList = [...nodes];
|
|
43042
|
+
const n = nodeList.length;
|
|
43043
|
+
if (n === 0) {
|
|
43044
|
+
return /* @__PURE__ */ new Map();
|
|
43045
|
+
}
|
|
43046
|
+
const outLinks = /* @__PURE__ */ new Map();
|
|
43047
|
+
for (const edge of edges) {
|
|
43048
|
+
if (edge.from === edge.to) {
|
|
43049
|
+
continue;
|
|
43050
|
+
}
|
|
43051
|
+
const list = outLinks.get(edge.from) ?? [];
|
|
43052
|
+
list.push(edge.to);
|
|
43053
|
+
outLinks.set(edge.from, list);
|
|
43054
|
+
}
|
|
43055
|
+
let rank = new Map(nodeList.map((node) => [node, 1 / n]));
|
|
43056
|
+
const base = (1 - damping) / n;
|
|
43057
|
+
for (let iteration = 0; iteration < iterations; iteration++) {
|
|
43058
|
+
const next = new Map(nodeList.map((node) => [node, base]));
|
|
43059
|
+
let danglingMass = 0;
|
|
43060
|
+
for (const node of nodeList) {
|
|
43061
|
+
const links = outLinks.get(node);
|
|
43062
|
+
if (!links || links.length === 0) {
|
|
43063
|
+
danglingMass += rank.get(node) ?? 0;
|
|
43064
|
+
}
|
|
43065
|
+
}
|
|
43066
|
+
const danglingShare = damping * danglingMass / n;
|
|
43067
|
+
for (const node of nodeList) {
|
|
43068
|
+
if (danglingShare > 0) {
|
|
43069
|
+
next.set(node, (next.get(node) ?? 0) + danglingShare);
|
|
43070
|
+
}
|
|
43071
|
+
const links = outLinks.get(node);
|
|
43072
|
+
if (!links || links.length === 0) {
|
|
43073
|
+
continue;
|
|
43074
|
+
}
|
|
43075
|
+
const contribution = damping * (rank.get(node) ?? 0) / links.length;
|
|
43076
|
+
for (const target of links) {
|
|
43077
|
+
next.set(target, (next.get(target) ?? 0) + contribution);
|
|
43078
|
+
}
|
|
43079
|
+
}
|
|
43080
|
+
let delta = 0;
|
|
43081
|
+
for (const node of nodeList) {
|
|
43082
|
+
delta += Math.abs((next.get(node) ?? 0) - (rank.get(node) ?? 0));
|
|
43083
|
+
}
|
|
43084
|
+
rank = next;
|
|
43085
|
+
if (delta < tolerance) {
|
|
43086
|
+
break;
|
|
43087
|
+
}
|
|
43088
|
+
}
|
|
43089
|
+
return rank;
|
|
43090
|
+
}
|
|
43091
|
+
var DEFAULT_REPO_MAP_TOKEN_BUDGET = 1500;
|
|
43092
|
+
var MAX_SYMBOLS_PER_FILE = 6;
|
|
43093
|
+
function estimateTokens(text) {
|
|
43094
|
+
return Math.ceil(text.length / 4);
|
|
43095
|
+
}
|
|
43096
|
+
function formatEntryLine2(entry) {
|
|
43097
|
+
const parts = [`- \`${entry.path}\``];
|
|
43098
|
+
if (entry.module) {
|
|
43099
|
+
parts.push(`\xB7 ${entry.module}`);
|
|
43100
|
+
}
|
|
43101
|
+
if (entry.symbols.length > 0) {
|
|
43102
|
+
parts.push(`\xB7 ${entry.symbols.slice(0, MAX_SYMBOLS_PER_FILE).join(", ")}`);
|
|
43103
|
+
}
|
|
43104
|
+
return parts.join(" ");
|
|
43105
|
+
}
|
|
43106
|
+
function buildRepoMap(files, edges, options = {}) {
|
|
43107
|
+
const tokenBudget = options.tokenBudget ?? DEFAULT_REPO_MAP_TOKEN_BUDGET;
|
|
43108
|
+
const ranks = pageRank(
|
|
43109
|
+
files.map((file) => file.path),
|
|
43110
|
+
edges
|
|
43111
|
+
);
|
|
43112
|
+
const entries = files.map((file) => ({
|
|
43113
|
+
path: file.path,
|
|
43114
|
+
module: file.module,
|
|
43115
|
+
symbols: file.symbols ?? [],
|
|
43116
|
+
rank: ranks.get(file.path) ?? 0
|
|
43117
|
+
})).sort((left, right) => {
|
|
43118
|
+
if (right.rank !== left.rank) {
|
|
43119
|
+
return right.rank - left.rank;
|
|
43120
|
+
}
|
|
43121
|
+
return left.path < right.path ? -1 : left.path > right.path ? 1 : 0;
|
|
43122
|
+
});
|
|
43123
|
+
if (entries.length === 0) {
|
|
43124
|
+
return { entries, skeleton: "", truncated: false };
|
|
43125
|
+
}
|
|
43126
|
+
const header = `## Repo map \u2014 ${entries.length} files ranked by structural importance
|
|
43127
|
+
> Embedding-free orientation. Use it to decide where to read or grep; verify against the live files.
|
|
43128
|
+
`;
|
|
43129
|
+
let tokens = estimateTokens(header);
|
|
43130
|
+
const lines = [];
|
|
43131
|
+
let truncated = false;
|
|
43132
|
+
for (const entry of entries) {
|
|
43133
|
+
const line = formatEntryLine2(entry);
|
|
43134
|
+
const lineTokens = estimateTokens(line) + 1;
|
|
43135
|
+
if (lines.length > 0 && tokens + lineTokens > tokenBudget) {
|
|
43136
|
+
truncated = true;
|
|
43137
|
+
break;
|
|
43138
|
+
}
|
|
43139
|
+
lines.push(line);
|
|
43140
|
+
tokens += lineTokens;
|
|
43141
|
+
}
|
|
43142
|
+
const body = truncated ? `${lines.join("\n")}
|
|
43143
|
+
\u2026[repo map truncated to fit the token budget]` : lines.join("\n");
|
|
43144
|
+
return { entries, skeleton: `${header}
|
|
43145
|
+
${body}
|
|
43146
|
+
`, truncated };
|
|
43147
|
+
}
|
|
43148
|
+
async function buildProjectRepoMap(projectRoot, options) {
|
|
43149
|
+
const edges = await scanImports({
|
|
43150
|
+
projectRoot,
|
|
43151
|
+
files: options.files,
|
|
43152
|
+
aliases: options.aliases ?? { "@/": "src/" }
|
|
43153
|
+
});
|
|
43154
|
+
const files = options.files.map((path11) => ({
|
|
43155
|
+
path: path11,
|
|
43156
|
+
module: options.moduleOf?.(path11),
|
|
43157
|
+
symbols: options.symbolsOf?.(path11)
|
|
43158
|
+
}));
|
|
43159
|
+
return buildRepoMap(files, edges, { tokenBudget: options.tokenBudget });
|
|
43160
|
+
}
|
|
43161
|
+
|
|
43162
|
+
// src/context/existing-surface.ts
|
|
43163
|
+
init_contextual_blurb();
|
|
43164
|
+
var EXISTING_SURFACE_HEADING = "## Existing surface";
|
|
43165
|
+
var EXISTING_SURFACE_FRAMING = "> Before writing new helpers, check this surface \u2014 these already exist in this project.";
|
|
43166
|
+
function estimateTokens2(text) {
|
|
43167
|
+
return Math.ceil(text.length / 4);
|
|
43168
|
+
}
|
|
43169
|
+
function formatCardLine(card) {
|
|
43170
|
+
const head = card.signature?.trim() ? card.signature.trim() : card.name;
|
|
43171
|
+
const location = card.line ? `${card.file}:${card.line}` : card.file;
|
|
43172
|
+
const parts = [`- \`${head}\` \u2014 ${location}`];
|
|
43173
|
+
if (typeof card.callerCount === "number") {
|
|
43174
|
+
parts.push(`\xB7 called from ${card.callerCount} ${card.callerCount === 1 ? "place" : "places"}`);
|
|
43175
|
+
}
|
|
43176
|
+
if (card.module) {
|
|
43177
|
+
parts.push(`\xB7 ${card.module}`);
|
|
43178
|
+
}
|
|
43179
|
+
return parts.join(" ");
|
|
43180
|
+
}
|
|
43181
|
+
function headerFor(shown) {
|
|
43182
|
+
return `${EXISTING_SURFACE_HEADING} \u2014 ${shown} existing symbol${shown === 1 ? "" : "s"} for the files in play`;
|
|
43183
|
+
}
|
|
43184
|
+
function composeExistingSurfaceSection(cards, options = {}) {
|
|
43185
|
+
if (cards.length === 0) {
|
|
43186
|
+
return "";
|
|
43187
|
+
}
|
|
43188
|
+
const tokenBudget = options.tokenBudget ?? DEFAULT_EXISTING_SURFACE_TOKENS;
|
|
43189
|
+
let tokens = estimateTokens2(EXISTING_SURFACE_FRAMING) + estimateTokens2(headerFor(cards.length));
|
|
43190
|
+
const lines = [];
|
|
43191
|
+
let truncated = false;
|
|
43192
|
+
for (const card of cards) {
|
|
43193
|
+
const line = formatCardLine(card);
|
|
43194
|
+
const lineTokens = estimateTokens2(line) + 1;
|
|
43195
|
+
if (lines.length > 0 && tokens + lineTokens > tokenBudget) {
|
|
43196
|
+
truncated = true;
|
|
43197
|
+
break;
|
|
43198
|
+
}
|
|
43199
|
+
lines.push(line);
|
|
43200
|
+
tokens += lineTokens;
|
|
43201
|
+
}
|
|
43202
|
+
const remaining = cards.length - lines.length;
|
|
43203
|
+
const trailer = truncated && remaining > 0 ? `
|
|
43204
|
+
\u2026and ${remaining} more exported symbol${remaining === 1 ? "" : "s"} \u2014 run \`paqad-ai index query <name>\` to look one up.` : "";
|
|
43205
|
+
return `${headerFor(lines.length)}
|
|
43206
|
+
${EXISTING_SURFACE_FRAMING}
|
|
43207
|
+
|
|
43208
|
+
${lines.join("\n")}${trailer}
|
|
43209
|
+
`;
|
|
43210
|
+
}
|
|
43211
|
+
var SOURCE_EXT_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|php|dart)$/;
|
|
43212
|
+
function toPosix(path11) {
|
|
43213
|
+
return path11.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
43214
|
+
}
|
|
43215
|
+
function modulePrefix(path11) {
|
|
43216
|
+
return path11.split("/").slice(0, 2).join("/");
|
|
43217
|
+
}
|
|
43218
|
+
function basenameNoExt(path11) {
|
|
43219
|
+
const base = path11.slice(path11.lastIndexOf("/") + 1);
|
|
43220
|
+
const dot = base.lastIndexOf(".");
|
|
43221
|
+
return dot <= 0 ? base : base.slice(0, dot);
|
|
43222
|
+
}
|
|
43223
|
+
function selectCandidateFiles(allFiles, workingSet, query, index) {
|
|
43224
|
+
const working = new Set(workingSet);
|
|
43225
|
+
const workingModules = new Set([...working].map(modulePrefix));
|
|
43226
|
+
if (working.size === 0 && query.trim().length === 0) {
|
|
43227
|
+
return [];
|
|
43228
|
+
}
|
|
43229
|
+
const queryLower = query.toLowerCase();
|
|
43230
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
43231
|
+
for (const file of allFiles) {
|
|
43232
|
+
if (working.has(file) || workingModules.size > 0 && workingModules.has(modulePrefix(file))) {
|
|
43233
|
+
wanted.add(file);
|
|
43234
|
+
continue;
|
|
43235
|
+
}
|
|
43236
|
+
const base = basenameNoExt(file).toLowerCase();
|
|
43237
|
+
if (base.length >= 4 && queryLower.includes(base)) {
|
|
43238
|
+
wanted.add(file);
|
|
43239
|
+
}
|
|
43240
|
+
}
|
|
43241
|
+
if (index && queryLower.length > 0) {
|
|
43242
|
+
for (const symbol of index.symbols) {
|
|
43243
|
+
if (symbol.name.length >= 5 && queryLower.includes(symbol.name.toLowerCase())) {
|
|
43244
|
+
wanted.add(symbol.file);
|
|
43245
|
+
}
|
|
43246
|
+
}
|
|
43247
|
+
}
|
|
43248
|
+
const universe = new Set(allFiles);
|
|
43249
|
+
return [...wanted].filter((file) => universe.has(file));
|
|
43250
|
+
}
|
|
43251
|
+
async function gatherExistingSurface(projectRoot, options = {}) {
|
|
43252
|
+
try {
|
|
43253
|
+
const tokenBudget = options.tokenBudget ?? DEFAULT_EXISTING_SURFACE_TOKENS;
|
|
43254
|
+
const query = options.query ?? "";
|
|
43255
|
+
const index = readCodeKnowledgeIndex(projectRoot);
|
|
43256
|
+
const workingSet = (options.changedPaths ?? []).map(toPosix).filter((path11) => SOURCE_EXT_RE.test(path11));
|
|
43257
|
+
const allFiles = index ? index.files.map((file) => file.path) : scanWorkingTree(projectRoot, SOURCE_GLOBS).map(toPosix);
|
|
43258
|
+
const candidates = selectCandidateFiles(allFiles, workingSet, query, index);
|
|
43259
|
+
if (candidates.length === 0) {
|
|
43260
|
+
return "";
|
|
43261
|
+
}
|
|
43262
|
+
const symbolsByFile = /* @__PURE__ */ new Map();
|
|
43263
|
+
if (index) {
|
|
43264
|
+
for (const symbol of index.symbols) {
|
|
43265
|
+
const list = symbolsByFile.get(symbol.file) ?? [];
|
|
43266
|
+
list.push(symbol);
|
|
43267
|
+
symbolsByFile.set(symbol.file, list);
|
|
43268
|
+
}
|
|
43269
|
+
}
|
|
43270
|
+
const moduleResolver = buildModuleRoleResolver(projectRoot);
|
|
43271
|
+
const repoMap = await buildProjectRepoMap(projectRoot, {
|
|
43272
|
+
files: candidates,
|
|
43273
|
+
moduleOf: (path11) => moduleResolver(path11),
|
|
43274
|
+
symbolsOf: index ? (path11) => (symbolsByFile.get(path11) ?? []).map((symbol) => symbol.name) : (path11) => extractNames(projectRoot, path11)
|
|
43275
|
+
});
|
|
43276
|
+
const cards = [];
|
|
43277
|
+
for (const entry of repoMap.entries) {
|
|
43278
|
+
if (index) {
|
|
43279
|
+
const symbols = (symbolsByFile.get(entry.path) ?? []).slice().sort((a, b) => b.caller_count - a.caller_count || a.name.localeCompare(b.name));
|
|
43280
|
+
for (const symbol of symbols) {
|
|
43281
|
+
cards.push({
|
|
43282
|
+
name: symbol.name,
|
|
43283
|
+
signature: symbol.signature,
|
|
43284
|
+
file: symbol.file,
|
|
43285
|
+
line: symbol.line,
|
|
43286
|
+
callerCount: symbol.caller_count,
|
|
43287
|
+
module: symbol.module_slug ?? entry.module ?? void 0
|
|
43288
|
+
});
|
|
43289
|
+
}
|
|
43290
|
+
} else {
|
|
43291
|
+
for (const name of entry.symbols) {
|
|
43292
|
+
cards.push({ name, file: entry.path, module: entry.module });
|
|
43293
|
+
}
|
|
43294
|
+
}
|
|
43295
|
+
}
|
|
43296
|
+
return composeExistingSurfaceSection(cards, { tokenBudget });
|
|
43297
|
+
} catch {
|
|
43298
|
+
return "";
|
|
43299
|
+
}
|
|
43300
|
+
}
|
|
43301
|
+
function extractNames(projectRoot, relPath) {
|
|
43302
|
+
try {
|
|
43303
|
+
const content = readFileSync101(join204(projectRoot, relPath), "utf8");
|
|
43304
|
+
return extractSymbols(relPath, content).map((symbol) => symbol.name);
|
|
43305
|
+
} catch {
|
|
43306
|
+
return [];
|
|
43307
|
+
}
|
|
43308
|
+
}
|
|
43309
|
+
|
|
42988
43310
|
// src/context/retrieval-context.ts
|
|
42989
43311
|
init_esm_shims();
|
|
42990
43312
|
init_project_intelligence();
|
|
@@ -43154,11 +43476,11 @@ async function gatherWorkingSetSlices(projectRoot, options = {}) {
|
|
|
43154
43476
|
// src/pipeline/session-route.ts
|
|
43155
43477
|
init_esm_shims();
|
|
43156
43478
|
init_paths();
|
|
43157
|
-
import { mkdirSync as mkdirSync51, readFileSync as
|
|
43158
|
-
import { dirname as dirname86, join as
|
|
43479
|
+
import { mkdirSync as mkdirSync51, readFileSync as readFileSync102, writeFileSync as writeFileSync43 } from "fs";
|
|
43480
|
+
import { dirname as dirname86, join as join205 } from "path";
|
|
43159
43481
|
var SESSION_ROUTE_FILE = ".session-route.json";
|
|
43160
43482
|
function sessionRouteDir(projectRoot) {
|
|
43161
|
-
return
|
|
43483
|
+
return join205(projectRoot, dirname86(PATHS.CONTEXT_SESSION_ARTIFACT));
|
|
43162
43484
|
}
|
|
43163
43485
|
var VALID_WORKFLOWS2 = new Set(ROUTED_WORKFLOWS);
|
|
43164
43486
|
function compositionForRoute(route) {
|
|
@@ -43173,7 +43495,7 @@ function compositionForRoute(route) {
|
|
|
43173
43495
|
function readSessionRoute(projectRoot) {
|
|
43174
43496
|
try {
|
|
43175
43497
|
const parsed = JSON.parse(
|
|
43176
|
-
|
|
43498
|
+
readFileSync102(join205(sessionRouteDir(projectRoot), SESSION_ROUTE_FILE), "utf8")
|
|
43177
43499
|
);
|
|
43178
43500
|
if (typeof parsed.workflow !== "string" || !VALID_WORKFLOWS2.has(parsed.workflow)) {
|
|
43179
43501
|
return null;
|
|
@@ -43192,12 +43514,12 @@ init_recorder();
|
|
|
43192
43514
|
|
|
43193
43515
|
// src/rag/background-sync.ts
|
|
43194
43516
|
init_esm_shims();
|
|
43195
|
-
import { join as
|
|
43517
|
+
import { join as join206 } from "path";
|
|
43196
43518
|
init_paths();
|
|
43197
43519
|
init_service();
|
|
43198
43520
|
var STALE_LOCK_MS2 = 10 * 60 * 1e3;
|
|
43199
43521
|
async function backgroundIndexSync(projectRoot, providerFactory) {
|
|
43200
|
-
const lockDir =
|
|
43522
|
+
const lockDir = join206(projectRoot, PATHS.LOCKS_DIR, "rag-sync.lock");
|
|
43201
43523
|
const lock = tryAcquireLock(lockDir, { staleLockMs: STALE_LOCK_MS2 });
|
|
43202
43524
|
if (!lock.acquired) {
|
|
43203
43525
|
return { synced: false, reason: "in-flight" };
|
|
@@ -43224,8 +43546,8 @@ async function backgroundIndexSync(projectRoot, providerFactory) {
|
|
|
43224
43546
|
init_esm_shims();
|
|
43225
43547
|
init_atomic_artifact();
|
|
43226
43548
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
43227
|
-
import { readFileSync as
|
|
43228
|
-
import { join as
|
|
43549
|
+
import { readFileSync as readFileSync103 } from "fs";
|
|
43550
|
+
import { join as join207 } from "path";
|
|
43229
43551
|
|
|
43230
43552
|
// src/background/debounce-marker.ts
|
|
43231
43553
|
init_esm_shims();
|
|
@@ -43301,11 +43623,11 @@ function computeBaseDrift(projectRoot, options = {}) {
|
|
|
43301
43623
|
async function refreshBaseDrift(projectRoot, options = {}) {
|
|
43302
43624
|
const now = options.now ?? Date.now;
|
|
43303
43625
|
const minIntervalMs = options.minIntervalMs ?? DEFAULT_BASE_DRIFT_INTERVAL_MS;
|
|
43304
|
-
const markerPath =
|
|
43626
|
+
const markerPath = join207(projectRoot, PATHS.BASE_DRIFT_MARKER);
|
|
43305
43627
|
if (shouldDebounce(markerPath, minIntervalMs, now)) {
|
|
43306
43628
|
return { refreshed: false, reason: "debounced" };
|
|
43307
43629
|
}
|
|
43308
|
-
const lockDir =
|
|
43630
|
+
const lockDir = join207(projectRoot, PATHS.BASE_DRIFT_LOCK);
|
|
43309
43631
|
const lock = tryAcquireLock(lockDir, { staleLockMs: STALE_LOCK_MS3 });
|
|
43310
43632
|
if (!lock.acquired) {
|
|
43311
43633
|
return { refreshed: false, reason: "in-flight" };
|
|
@@ -43329,7 +43651,7 @@ async function refreshBaseDrift(projectRoot, options = {}) {
|
|
|
43329
43651
|
const snapshot = computeBaseDrift(projectRoot, options);
|
|
43330
43652
|
if (snapshot) {
|
|
43331
43653
|
await atomicWriteFile(
|
|
43332
|
-
|
|
43654
|
+
join207(projectRoot, PATHS.BASE_DRIFT_STATE),
|
|
43333
43655
|
`${JSON.stringify(snapshot, null, 2)}
|
|
43334
43656
|
`
|
|
43335
43657
|
);
|
|
@@ -43344,7 +43666,7 @@ async function refreshBaseDrift(projectRoot, options = {}) {
|
|
|
43344
43666
|
function loadBaseDrift(projectRoot) {
|
|
43345
43667
|
try {
|
|
43346
43668
|
const parsed = JSON.parse(
|
|
43347
|
-
|
|
43669
|
+
readFileSync103(join207(projectRoot, PATHS.BASE_DRIFT_STATE), "utf8")
|
|
43348
43670
|
);
|
|
43349
43671
|
if (typeof parsed === "object" && parsed !== null && typeof parsed.base_branch === "string" && typeof parsed.ahead === "number") {
|
|
43350
43672
|
return parsed;
|
|
@@ -43842,9 +44164,18 @@ function createRagCommand() {
|
|
|
43842
44164
|
}
|
|
43843
44165
|
const route = readSessionRoute(options.projectRoot);
|
|
43844
44166
|
const { loadRules, retrieves } = compositionForRoute(route);
|
|
43845
|
-
const
|
|
44167
|
+
const intelligence = resolveFrameworkConfig(options.projectRoot).intelligence;
|
|
44168
|
+
const existingSurfaceSection = loadRules ? await gatherExistingSurface(options.projectRoot, {
|
|
44169
|
+
changedPaths: (await loadChangeEvidence(options.projectRoot)).files,
|
|
44170
|
+
query: route?.query,
|
|
44171
|
+
tokenBudget: intelligence.existing_surface_tokens
|
|
44172
|
+
}) : "";
|
|
44173
|
+
const ragEnabled = intelligence.rag_enabled;
|
|
43846
44174
|
if (!ragEnabled) {
|
|
43847
|
-
const target2 = await refreshRuleContext(options.projectRoot, {
|
|
44175
|
+
const target2 = await refreshRuleContext(options.projectRoot, {
|
|
44176
|
+
existingSurfaceSection,
|
|
44177
|
+
loadRules
|
|
44178
|
+
});
|
|
43848
44179
|
if (!options.quiet) {
|
|
43849
44180
|
process.stdout.write(
|
|
43850
44181
|
`${target2 ? `wrote ${target2}` : "nothing to compose"}; rule-only (rag off)
|
|
@@ -43862,8 +44193,8 @@ function createRagCommand() {
|
|
|
43862
44193
|
const packEntries = usesContextPack ? distillSlices(slices, {
|
|
43863
44194
|
readFile: (path11) => {
|
|
43864
44195
|
try {
|
|
43865
|
-
return
|
|
43866
|
-
isAbsolute11(path11) ? path11 :
|
|
44196
|
+
return readFileSync104(
|
|
44197
|
+
isAbsolute11(path11) ? path11 : join208(options.projectRoot, path11),
|
|
43867
44198
|
"utf8"
|
|
43868
44199
|
);
|
|
43869
44200
|
} catch {
|
|
@@ -43879,6 +44210,7 @@ function createRagCommand() {
|
|
|
43879
44210
|
driftSection = composeBaseDriftSection(loadBaseDrift(options.projectRoot));
|
|
43880
44211
|
}
|
|
43881
44212
|
const target = await refreshRuleContext(options.projectRoot, {
|
|
44213
|
+
existingSurfaceSection,
|
|
43882
44214
|
memorySection,
|
|
43883
44215
|
retrievalSection,
|
|
43884
44216
|
driftSection,
|
|
@@ -43984,7 +44316,7 @@ function createRagCommand() {
|
|
|
43984
44316
|
}
|
|
43985
44317
|
if (options.baseline) {
|
|
43986
44318
|
const baselineSnapshot = JSON.parse(
|
|
43987
|
-
|
|
44319
|
+
readFileSync104(options.baseline, "utf8")
|
|
43988
44320
|
);
|
|
43989
44321
|
comparison = compareConfigurations(baselineSnapshot, candidateSnapshot, mode);
|
|
43990
44322
|
}
|
|
@@ -44166,8 +44498,8 @@ function createRagEvidenceCommand() {
|
|
|
44166
44498
|
// src/cli/commands/refresh.ts
|
|
44167
44499
|
init_esm_shims();
|
|
44168
44500
|
import { Command as Command30 } from "commander";
|
|
44169
|
-
import { existsSync as existsSync108, readFileSync as
|
|
44170
|
-
import { join as
|
|
44501
|
+
import { existsSync as existsSync108, readFileSync as readFileSync105, writeFileSync as writeFileSync45 } from "fs";
|
|
44502
|
+
import { join as join209 } from "path";
|
|
44171
44503
|
init_paths();
|
|
44172
44504
|
init_project_profile2();
|
|
44173
44505
|
init_service();
|
|
@@ -44297,7 +44629,7 @@ async function refreshProviderEntries(projectRoot) {
|
|
|
44297
44629
|
removeObsoleteContractDocs(projectRoot);
|
|
44298
44630
|
for (const type of ADAPTER_TYPES) {
|
|
44299
44631
|
const adapter = AdapterFactory.create(type);
|
|
44300
|
-
const configPath =
|
|
44632
|
+
const configPath = join209(projectRoot, adapter.getConfigPath());
|
|
44301
44633
|
if (!existsSync108(configPath)) {
|
|
44302
44634
|
continue;
|
|
44303
44635
|
}
|
|
@@ -44310,14 +44642,14 @@ async function refreshProviderEntries(projectRoot) {
|
|
|
44310
44642
|
}
|
|
44311
44643
|
}
|
|
44312
44644
|
function writeRefreshDrift(projectRoot, refreshDrift) {
|
|
44313
|
-
const path11 =
|
|
44645
|
+
const path11 = join209(projectRoot, PATHS.STACK_DRIFT);
|
|
44314
44646
|
const current = readExistingJson(path11);
|
|
44315
44647
|
writeFileSync45(path11, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
|
|
44316
44648
|
`);
|
|
44317
44649
|
}
|
|
44318
44650
|
function readExistingJson(path11) {
|
|
44319
44651
|
try {
|
|
44320
|
-
return JSON.parse(
|
|
44652
|
+
return JSON.parse(readFileSync105(path11, "utf8"));
|
|
44321
44653
|
} catch {
|
|
44322
44654
|
return null;
|
|
44323
44655
|
}
|
|
@@ -44326,12 +44658,12 @@ function resolveChangedFiles(projectRoot, contextChangedFiles) {
|
|
|
44326
44658
|
if (contextChangedFiles.length > 0) {
|
|
44327
44659
|
return [...new Set(contextChangedFiles)].sort();
|
|
44328
44660
|
}
|
|
44329
|
-
const trackedPath =
|
|
44661
|
+
const trackedPath = join209(projectRoot, PATHS.CHANGED_FILES);
|
|
44330
44662
|
if (!existsSync108(trackedPath)) {
|
|
44331
44663
|
return [];
|
|
44332
44664
|
}
|
|
44333
44665
|
try {
|
|
44334
|
-
const parsed = JSON.parse(
|
|
44666
|
+
const parsed = JSON.parse(readFileSync105(trackedPath, "utf8"));
|
|
44335
44667
|
if (!Array.isArray(parsed)) {
|
|
44336
44668
|
return [];
|
|
44337
44669
|
}
|
|
@@ -44399,7 +44731,7 @@ function createRulesCommand() {
|
|
|
44399
44731
|
|
|
44400
44732
|
// src/cli/commands/spec.ts
|
|
44401
44733
|
init_esm_shims();
|
|
44402
|
-
import { readFileSync as
|
|
44734
|
+
import { readFileSync as readFileSync106 } from "fs";
|
|
44403
44735
|
import { basename as basename16 } from "path";
|
|
44404
44736
|
import { Command as Command33 } from "commander";
|
|
44405
44737
|
|
|
@@ -44544,7 +44876,7 @@ function createSpecCommand() {
|
|
|
44544
44876
|
(specFile, options) => {
|
|
44545
44877
|
let markdown;
|
|
44546
44878
|
try {
|
|
44547
|
-
markdown =
|
|
44879
|
+
markdown = readFileSync106(specFile, "utf8");
|
|
44548
44880
|
} catch {
|
|
44549
44881
|
console.error(`could not read spec file "${specFile}"`);
|
|
44550
44882
|
process.exitCode = 1;
|