@piagent/platform 1.5.5 → 1.6.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 (227) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +9 -8
  3. package/README.vi.md +9 -5
  4. package/adapters/web-frontend/profile.json +2 -4
  5. package/architecture/layers.json +18 -3
  6. package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
  7. package/benchmarks/deep-logic-v1/grade.mjs +272 -10
  8. package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
  9. package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
  10. package/benchmarks/deep-logic-v1/project/package.json +1 -1
  11. package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
  12. package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
  13. package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
  14. package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
  15. package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
  16. package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
  17. package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
  18. package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
  19. package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
  20. package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
  21. package/benchmarks/deep-logic-v1/suite.json +51 -3
  22. package/benchmarks/deep-logic-v1/variant.mjs +22 -1
  23. package/benchmarks/production-v1/spend-control.v1.json +68 -0
  24. package/benchmarks/production-v1/suite.json +42 -3
  25. package/catalog/capabilities.json +6 -6
  26. package/docs/command-reference-vietnamese.md +6 -6
  27. package/docs/context-engine.md +7 -1
  28. package/docs/distribution-standard.md +7 -7
  29. package/docs/en/architecture.md +1 -0
  30. package/docs/languages.json +4 -4
  31. package/docs/model-options.md +8 -5
  32. package/docs/operator-manual-vietnamese.md +13 -11
  33. package/docs/project-adapters.md +2 -2
  34. package/docs/publishing-for-teams.md +5 -0
  35. package/docs/quality-benchmark.md +271 -62
  36. package/docs/release-install-policy.md +10 -9
  37. package/docs/runtime-policy-design.md +4 -4
  38. package/docs/runtime-quality-baseline.md +13 -6
  39. package/docs/security-threat-model.md +2 -2
  40. package/docs/task-lifecycle-vietnamese.md +2 -2
  41. package/docs/team-onboarding.md +2 -2
  42. package/docs/usage-observability.md +7 -2
  43. package/docs/vi/architecture.md +1 -0
  44. package/docs-site/architecture.html +1 -1
  45. package/docs-site/benchmark.html +1 -1
  46. package/docs-site/commands.html +1 -1
  47. package/docs-site/context-engine.html +1 -1
  48. package/docs-site/en/architecture.html +1 -1
  49. package/docs-site/en/benchmark.html +1 -1
  50. package/docs-site/en/commands.html +1 -1
  51. package/docs-site/en/context-engine.html +1 -1
  52. package/docs-site/en/index.html +1 -1
  53. package/docs-site/en/mcp-approval.html +1 -1
  54. package/docs-site/en/mcp-auth.html +1 -1
  55. package/docs-site/en/mcp-servers.html +1 -1
  56. package/docs-site/en/mcp.html +1 -1
  57. package/docs-site/en/permissions.html +1 -1
  58. package/docs-site/en/profiles.html +1 -1
  59. package/docs-site/en/quickstart.html +1 -1
  60. package/docs-site/en/runtime.html +1 -1
  61. package/docs-site/en/scope.html +1 -1
  62. package/docs-site/en/security.html +1 -1
  63. package/docs-site/en/team.html +1 -1
  64. package/docs-site/en/whats-new.html +1 -1
  65. package/docs-site/en/workflows.html +1 -1
  66. package/docs-site/index.html +1 -1
  67. package/docs-site/mcp-approval.html +1 -1
  68. package/docs-site/mcp-auth.html +1 -1
  69. package/docs-site/mcp-servers.html +1 -1
  70. package/docs-site/mcp.html +1 -1
  71. package/docs-site/permissions.html +1 -1
  72. package/docs-site/profiles.html +1 -1
  73. package/docs-site/quickstart.html +1 -1
  74. package/docs-site/runtime.html +1 -1
  75. package/docs-site/scope.html +1 -1
  76. package/docs-site/security.html +1 -1
  77. package/docs-site/team.html +1 -1
  78. package/docs-site/whats-new.html +1 -1
  79. package/docs-site/workflows.html +1 -1
  80. package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
  81. package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
  82. package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
  83. package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
  84. package/evals/fs4-readiness-matrix.v1.json +2 -2
  85. package/evals/fs5-causal-arm.v1.json +2 -2
  86. package/evals/fs5-pilot-protocol.v1.json +2 -2
  87. package/evals/fs5-pilot-protocol.v4.json +6 -5
  88. package/evals/fs5-pilot-protocol.v5.json +7 -6
  89. package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
  90. package/package.json +3 -1
  91. package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
  92. package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
  93. package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
  94. package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
  95. package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
  96. package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
  97. package/packages/piagent-core/benchmark/benchmark-core.js +732 -661
  98. package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
  99. package/packages/piagent-core/benchmark/benchmark-forensics.js +439 -4
  100. package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
  101. package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
  102. package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
  103. package/packages/piagent-core/benchmark/benchmark-preflight.js +3 -1
  104. package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
  105. package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
  106. package/packages/piagent-core/benchmark/benchmark-record-validation.js +183 -0
  107. package/packages/piagent-core/benchmark/benchmark-report.js +116 -12
  108. package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
  109. package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
  110. package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +782 -0
  111. package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
  112. package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
  113. package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
  114. package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
  115. package/packages/piagent-core/benchmark/benchmark-suite.js +128 -2
  116. package/packages/piagent-core/benchmark/benchmark-summary-support.js +376 -0
  117. package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
  118. package/packages/piagent-core/benchmark/benchmark-usage.js +311 -0
  119. package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
  120. package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
  121. package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
  122. package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
  123. package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
  124. package/packages/piagent-core/extensions/acceptance-receipt.js +34 -11
  125. package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
  126. package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
  127. package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
  128. package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
  129. package/packages/piagent-core/extensions/context-engine.js +148 -145
  130. package/packages/piagent-core/extensions/context-evidence.js +48 -0
  131. package/packages/piagent-core/extensions/context-import-links.js +296 -0
  132. package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
  133. package/packages/piagent-core/extensions/criterion-context-pack.js +422 -7
  134. package/packages/piagent-core/extensions/criterion-graph.js +78 -8
  135. package/packages/piagent-core/extensions/guard-types.ts +2 -0
  136. package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
  137. package/packages/piagent-core/extensions/piagent-guard.ts +233 -41
  138. package/packages/piagent-core/extensions/task-contract-view.js +17 -3
  139. package/packages/piagent-core/extensions/task-lifecycle.js +7 -2
  140. package/packages/piagent-core/extensions/task-state.js +40 -134
  141. package/packages/piagent-core/extensions/verification-intelligence.js +3 -1
  142. package/packages/piagent-core/extensions/workspace-evidence-roots.js +157 -0
  143. package/packages/piagent-core/package.json +1 -1
  144. package/packages/piagent-core/policies/base-policy.json +2 -0
  145. package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
  146. package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
  147. package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
  148. package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
  149. package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
  150. package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
  151. package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
  152. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
  153. package/packages/piagent-core/runtime/hooks/completion-hook.ts +5 -6
  154. package/packages/piagent-core/runtime/hooks/input-hook.ts +11 -1
  155. package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
  156. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +7 -2
  157. package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
  158. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +84 -102
  159. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
  160. package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
  161. package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
  162. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
  163. package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +53 -0
  164. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +34 -6
  165. package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
  166. package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
  167. package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
  168. package/packages/piagent-core/runtime/orchestration/role-policy.ts +1 -1
  169. package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
  170. package/packages/piagent-core/runtime/product/efficiency-metrics.ts +4 -2
  171. package/packages/piagent-core/runtime/quality/exact-output-contract.ts +2 -1
  172. package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
  173. package/packages/piagent-core/runtime/quality/performance-assurance.ts +6 -2
  174. package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
  175. package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
  176. package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +55 -2
  177. package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
  178. package/packages/piagent-core/runtime/registration/context-commands.ts +66 -5
  179. package/packages/piagent-core/runtime/registration/policy-tools.ts +46 -11
  180. package/packages/piagent-core/runtime/registration/task-completion-tools.ts +49 -16
  181. package/packages/piagent-core/runtime/registration/task-start-guidance.ts +163 -0
  182. package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
  183. package/packages/piagent-core/runtime/registration/task-start-tool.ts +67 -62
  184. package/packages/piagent-core/runtime/session/runtime-state.ts +154 -2
  185. package/packages/piagent-core/runtime/session/system-prompt.ts +4 -4
  186. package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
  187. package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
  188. package/packages/piagent-core/runtime/workflows/task-intake.ts +43 -2
  189. package/packages/piagent-core/security/sensitive-data.js +13 -218
  190. package/packages/piagent-core/security/sensitive-project-file.js +42 -0
  191. package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
  192. package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
  193. package/packages/piagent-core/security/sensitive-text.js +234 -0
  194. package/packages/piagent-core/subagents/piagent-worker.md +1 -1
  195. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-CxeZqTte.js} +1 -1
  196. package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +176 -0
  197. package/packages/piagent-webui/dist/client/index.html +1 -1
  198. package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
  199. package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
  200. package/packages/piagent-webui/gateway/gateway-session-stream.ts +93 -7
  201. package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
  202. package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
  203. package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
  204. package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
  205. package/packages/piagent-webui/gateway/session-operation-watchdog.ts +158 -0
  206. package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
  207. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +139 -124
  208. package/packages/piagent-webui/server/loopback-server.ts +8 -0
  209. package/packages/piagent-webui/server/transcript-projection.ts +22 -4
  210. package/packages/piagent-webui/shared/text-visibility.ts +10 -0
  211. package/schemas/piagent-webui/catalog-v1.json +9 -0
  212. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
  213. package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
  214. package/schemas/task-contract.schema.json +12 -1
  215. package/scripts/benchmark-runner-core.mjs +355 -359
  216. package/scripts/benchmark-runner-finalization.mjs +309 -0
  217. package/scripts/benchmark-runner-host-readiness.mjs +94 -0
  218. package/scripts/benchmark-runner-support.mjs +200 -0
  219. package/scripts/benchmark-session.mjs +95 -41
  220. package/scripts/configure-model-scope.sh +4 -3
  221. package/scripts/helper-evaluation.mjs +1 -1
  222. package/scripts/install-global.sh +2 -2
  223. package/scripts/pi-usage-history.mjs +37 -10
  224. package/scripts/setup.sh +2 -2
  225. package/scripts/verify-local.sh +5 -1
  226. package/templates/global/settings.json +2 -1
  227. package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
@@ -0,0 +1,296 @@
1
+ import { regexCanStartAfterLexicalChunks } from "./javascript-regex-evidence.js";
2
+
3
+ function erasedLexeme(value) {
4
+ return String(value ?? "").replace(/[^\r\n]/g, " ");
5
+ }
6
+
7
+ const BOUND_IMPORT_PREFIX = "\u0001pi_import_string_";
8
+ const BOUND_IMPORT_SUFFIX = "\u0002";
9
+
10
+ function boundImportString(index) {
11
+ return `${BOUND_IMPORT_PREFIX}${index}${BOUND_IMPORT_SUFFIX}`;
12
+ }
13
+
14
+ function lexicalJavaScriptImportView(value) {
15
+ const source = String(value ?? "");
16
+ const output = [];
17
+ const strings = [];
18
+ let index = 0;
19
+ let scanCode;
20
+
21
+ const scanTemplate = () => {
22
+ const start = index;
23
+ const outputStart = output.length;
24
+ const stringsStart = strings.length;
25
+ output.push("__pi_template_literal__");
26
+ index += 1;
27
+ let rawStart = index;
28
+ while (index < source.length) {
29
+ if (source[index] === "\\") {
30
+ index = Math.min(source.length, index + 2);
31
+ continue;
32
+ }
33
+ if (source[index] === "`") {
34
+ output.push(erasedLexeme(source.slice(rawStart, index + 1)));
35
+ index += 1;
36
+ return true;
37
+ }
38
+ if (source[index] === "$" && source[index + 1] === "{") {
39
+ output.push(erasedLexeme(source.slice(rawStart, index + 2)));
40
+ output.push("(");
41
+ index += 2;
42
+ if (!scanCode(true) || source[index] !== "}") break;
43
+ output.push(")");
44
+ index += 1;
45
+ rawStart = index;
46
+ continue;
47
+ }
48
+ index += 1;
49
+ }
50
+ output.splice(outputStart);
51
+ strings.splice(stringsStart);
52
+ output.push(erasedLexeme(source.slice(start, index)));
53
+ return false;
54
+ };
55
+
56
+ scanCode = (stopAtTemplateExpression = false) => {
57
+ let braceDepth = 0;
58
+ while (index < source.length) {
59
+ const current = source[index], next = source[index + 1];
60
+ if (stopAtTemplateExpression && current === "}" && braceDepth === 0) return true;
61
+ if (current === "/" && next === "/") {
62
+ let end = index + 2;
63
+ while (end < source.length && !"\r\n".includes(source[end])) end += 1;
64
+ output.push(erasedLexeme(source.slice(index, end)));
65
+ index = end;
66
+ continue;
67
+ }
68
+ if (current === "/" && next === "*") {
69
+ const closing = source.indexOf("*/", index + 2);
70
+ const end = closing === -1 ? source.length : closing + 2;
71
+ output.push(erasedLexeme(source.slice(index, end)));
72
+ index = end;
73
+ continue;
74
+ }
75
+ if (current === "'" || current === '"') {
76
+ const quote = current;
77
+ let end = index + 1, payload = "", closed = false;
78
+ while (end < source.length) {
79
+ const character = source[end];
80
+ if (character === "\\") {
81
+ payload += source.slice(end, Math.min(source.length, end + 2));
82
+ end += 2;
83
+ continue;
84
+ }
85
+ if (character === quote) {
86
+ end += 1;
87
+ closed = true;
88
+ break;
89
+ }
90
+ if (character === "\r" || character === "\n") break;
91
+ payload += character;
92
+ end += 1;
93
+ }
94
+ if (!closed) output.push(erasedLexeme(source.slice(index, end)));
95
+ else {
96
+ output.push(boundImportString(strings.length));
97
+ strings.push(payload);
98
+ }
99
+ index = end;
100
+ continue;
101
+ }
102
+ if (current === "`") {
103
+ const closed = scanTemplate();
104
+ if (!closed && stopAtTemplateExpression) return false;
105
+ continue;
106
+ }
107
+ if (current === "/" && next !== "=" && regexCanStartAfterLexicalChunks(output)) {
108
+ let end = index + 1, inClass = false, closed = false;
109
+ while (end < source.length) {
110
+ const character = source[end];
111
+ if (character === "\\") {
112
+ end += 2;
113
+ continue;
114
+ }
115
+ if (character === "[") inClass = true;
116
+ else if (character === "]") inClass = false;
117
+ else if (character === "/" && !inClass) {
118
+ end += 1;
119
+ while (/[a-z]/iu.test(source[end] ?? "")) end += 1;
120
+ closed = true;
121
+ break;
122
+ } else if (character === "\r" || character === "\n") break;
123
+ end += 1;
124
+ }
125
+ if (closed) {
126
+ output.push(erasedLexeme(source.slice(index, end)));
127
+ index = end;
128
+ continue;
129
+ }
130
+ }
131
+ if (current === "{") braceDepth += 1;
132
+ else if (current === "}" && braceDepth > 0) braceDepth -= 1;
133
+ output.push(current);
134
+ index += 1;
135
+ }
136
+ return !stopAtTemplateExpression;
137
+ };
138
+
139
+ scanCode(false);
140
+ return { code: output.join(""), strings };
141
+ }
142
+
143
+ const BOUND_IMPORT_STRING = `${BOUND_IMPORT_PREFIX}(\\d+)${BOUND_IMPORT_SUFFIX}`;
144
+ const JAVASCRIPT_IMPORT_PATTERNS = [
145
+ new RegExp(String.raw`(?<![.$\w])(?:import|export)\s+(?:type\s+)?[\w$*{},\s]+?\s+from\s+(${BOUND_IMPORT_STRING})`, "gu"),
146
+ new RegExp(String.raw`(?<![.$\w])import\s+(${BOUND_IMPORT_STRING})`, "gu"),
147
+ new RegExp(String.raw`(?<![.$\w])require\s*\(\s*(${BOUND_IMPORT_STRING})\s*\)`, "gu"),
148
+ new RegExp(String.raw`(?<![.$\w])import\s*\(\s*(${BOUND_IMPORT_STRING})\s*\)`, "gu")
149
+ ];
150
+
151
+ function tagEnd(code, start) {
152
+ let braces = 0;
153
+ for (let index = start + 1; index < code.length; index += 1) {
154
+ if (code[index] === "{") braces += 1;
155
+ else if (code[index] === "}") braces = Math.max(0, braces - 1);
156
+ else if (code[index] === ">" && braces === 0) return index + 1;
157
+ }
158
+ return -1;
159
+ }
160
+
161
+ function jsxTagAt(code, start) {
162
+ if (code[start] !== "<") return undefined;
163
+ const end = tagEnd(code, start);
164
+ if (end === -1) return undefined;
165
+ const raw = code.slice(start, end);
166
+ if (/^<\s*>$/u.test(raw)) return code.slice(end).includes("</>") ? { kind: "open", name: "", end } : undefined;
167
+ if (/^<\/\s*>$/u.test(raw)) return { kind: "close", name: "", end };
168
+ const closing = raw.match(/^<\/\s*([A-Za-z][\w.$:-]*)\s*>$/u);
169
+ if (closing) return { kind: "close", name: closing[1], end };
170
+ const opening = raw.match(/^<\s*([A-Za-z][\w.$:-]*)(?:\s|\/?>)/u);
171
+ if (!opening) return undefined;
172
+ if (/\/\s*>$/u.test(raw)) return { kind: "self", name: opening[1], end };
173
+ const escaped = opening[1].replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
174
+ return new RegExp(`<\\/\\s*${escaped}\\s*>`, "u").test(code.slice(end))
175
+ ? { kind: "open", name: opening[1], end }
176
+ : undefined;
177
+ }
178
+
179
+ function jsxTextOffsets(code, offsets) {
180
+ const orderedOffsets = [...new Set(offsets)].sort((left, right) => left - right);
181
+ const textOffsets = new Set();
182
+ const stack = [];
183
+ let braces = 0, index = 0;
184
+ for (const offset of orderedOffsets) {
185
+ while (index < offset) {
186
+ if (code[index] === "<") {
187
+ const tag = jsxTagAt(code, index);
188
+ if (tag && tag.end <= offset) {
189
+ if (tag.kind === "open") stack.push({ name: tag.name, braces });
190
+ else if (tag.kind === "close" && stack.at(-1)?.name === tag.name) stack.pop();
191
+ index = tag.end;
192
+ continue;
193
+ }
194
+ }
195
+ if (code[index] === "{") braces += 1;
196
+ else if (code[index] === "}") braces = Math.max(0, braces - 1);
197
+ index += 1;
198
+ }
199
+ if (stack.length > 0 && braces === stack.at(-1).braces) textOffsets.add(offset);
200
+ }
201
+ return textOffsets;
202
+ }
203
+
204
+ function shadowsCommonJsRequire(code) {
205
+ return /\b(?:class|function|let|const|var)\s+require\b/u.test(code)
206
+ || /(?<![.$\w])import\s+(?:type\s+)?(?:require\b|\*\s+as\s+require\b|(?:[\w$]+\s*,\s*)?\{[^}\n]*\brequire\b[^}\n]*\})/u.test(code)
207
+ || /\b(?:function\s*[\w$]*|catch)\s*\([^)]*\brequire\b[^)]*\)/u.test(code)
208
+ || /(?:\([^)]*\brequire\b[^)]*\)|(?<![.$\w])require)\s*=>/u.test(code)
209
+ || /\b(?:let|const|var)\s*\{[^}\n]*\brequire\b[^}\n]*\}/u.test(code)
210
+ || /(?<![.$\w])require\s*(?:=(?!=)|\|\|=|&&=|\?\?=|\*\*=|[+*/%&|^-]=)/u.test(code);
211
+ }
212
+
213
+ function executableJavaScriptImports(source, lineOffset = 0, { jsx = false } = {}) {
214
+ const { code, strings } = lexicalJavaScriptImportView(source);
215
+ const imports = [];
216
+ const requireShadowed = shadowsCommonJsRequire(code);
217
+ const candidates = [];
218
+ for (const [patternIndex, pattern] of JAVASCRIPT_IMPORT_PATTERNS.entries()) {
219
+ if (patternIndex === 2 && requireShadowed) continue;
220
+ for (const match of code.matchAll(pattern)) {
221
+ candidates.push(match);
222
+ }
223
+ }
224
+ const jsxText = jsx ? jsxTextOffsets(code, candidates.map((match) => match.index)) : new Set();
225
+ const pending = [];
226
+ for (const match of candidates) {
227
+ if (jsxText.has(match.index)) continue;
228
+ const stringIndex = Number(match.at(-1));
229
+ const specifier = strings[stringIndex];
230
+ if (typeof specifier !== "string" || !specifier || specifier.length > 300) continue;
231
+ const sentinelOffset = match.index + match[0].lastIndexOf(boundImportString(stringIndex));
232
+ pending.push({ specifier, offset: sentinelOffset });
233
+ }
234
+ const newlines = [];
235
+ for (let offset = code.indexOf("\n"); offset !== -1; offset = code.indexOf("\n", offset + 1)) newlines.push(offset);
236
+ const lineAt = (offset) => {
237
+ let low = 0, high = newlines.length;
238
+ while (low < high) {
239
+ const middle = (low + high) >>> 1;
240
+ if (newlines[middle] < offset) low = middle + 1;
241
+ else high = middle;
242
+ }
243
+ return lineOffset + low + 1;
244
+ };
245
+ for (const candidate of pending) {
246
+ imports.push({ ...candidate, line: lineAt(candidate.offset) });
247
+ }
248
+ return imports;
249
+ }
250
+
251
+ /**
252
+ * Extract executable JS/TS module edges without treating comments, examples,
253
+ * string documentation, templates, or regular expressions as live imports.
254
+ */
255
+ export function extractJavaScriptModuleImports(value, { embedded = false, jsx = false } = {}) {
256
+ const source = String(value ?? "");
257
+ const imports = [];
258
+ if (!embedded) imports.push(...executableJavaScriptImports(source, 0, { jsx }));
259
+ else {
260
+ const visible = source.replace(/<!--[\s\S]*?-->/gu, (comment) => erasedLexeme(comment));
261
+ // HTML end tags may carry whitespace, a self-closing slash, or ignored
262
+ // attributes. Stop at the first complete `script` end tag instead of
263
+ // letting its body absorb later template markup or another script block.
264
+ const script = /^[\t ]*<script(?:>|[\t\n\f\r /][^>]*>)([\s\S]*?)<\/script(?:>|[\t\n\f\r /][^>]*>)/gimu;
265
+ for (const match of visible.matchAll(script)) {
266
+ const content = match[1];
267
+ const contentOffset = match.index + match[0].indexOf(content);
268
+ const lineOffset = visible.slice(0, contentOffset).split(/\r?\n/).length - 1;
269
+ imports.push(...executableJavaScriptImports(content, lineOffset));
270
+ }
271
+ }
272
+ return imports
273
+ .sort((left, right) => left.line - right.line || left.offset - right.offset)
274
+ .slice(0, 300)
275
+ .map(({ specifier, line }) => ({ specifier, line }));
276
+ }
277
+
278
+ export function directExplicitImportLinks(importRows, explicitRows) {
279
+ const explicitPaths = new Set(explicitRows.map((row) => row.path));
280
+ const byPath = new Map();
281
+ const rankingRows = [];
282
+ const add = (candidatePath, kind, explicitPath) => {
283
+ const links = byPath.get(candidatePath) ?? [];
284
+ if (!links.some((link) => link.kind === kind && link.path === explicitPath)) {
285
+ links.push({ kind, path: explicitPath });
286
+ rankingRows.push({ path: candidatePath });
287
+ }
288
+ byPath.set(candidatePath, links);
289
+ };
290
+ for (const row of importRows) {
291
+ if (typeof row.specifier !== "string" || !/^\.{1,2}\//.test(row.specifier)) continue;
292
+ if (explicitPaths.has(row.file_path)) add(row.target_path, "explicit-imports-candidate", row.file_path);
293
+ if (explicitPaths.has(row.target_path)) add(row.file_path, "candidate-imports-explicit", row.target_path);
294
+ }
295
+ return { byPath, rankingRows };
296
+ }
@@ -0,0 +1,65 @@
1
+ import fs from "node:fs";
2
+
3
+ import { resolveLocalStatePath } from "./local-state-path.js";
4
+
5
+ const DEFAULT_LIMIT = 50_000;
6
+ const DEFAULT_MAX_BYTES = 32 * 1024 * 1024;
7
+
8
+ function clampInteger(value, fallback, min, max) {
9
+ const number = Number(value);
10
+ if (!Number.isFinite(number)) return fallback;
11
+ return Math.max(min, Math.min(max, Math.trunc(number)));
12
+ }
13
+
14
+ function readTelemetryFile(filePath, maximumBytes) {
15
+ const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
16
+ try {
17
+ const stat = fs.fstatSync(descriptor);
18
+ if (!stat.isFile()) throw new Error("Context telemetry must be a regular file");
19
+ const start = Math.max(0, stat.size - maximumBytes);
20
+ const buffer = Buffer.allocUnsafe(stat.size - start);
21
+ fs.readSync(descriptor, buffer, 0, buffer.length, start);
22
+ let text = buffer.toString("utf8");
23
+ if (start > 0) text = text.slice(Math.max(0, text.indexOf("\n") + 1));
24
+ return { text, truncated: start > 0 };
25
+ } finally {
26
+ fs.closeSync(descriptor);
27
+ }
28
+ }
29
+
30
+ /** Fail-closed JSONL inspection used when telemetry becomes benchmark evidence. */
31
+ export function inspectContextTelemetryIntegrity(projectRoot, telemetryPath, options = {}) {
32
+ const limit = clampInteger(options.limit, DEFAULT_LIMIT, 1, DEFAULT_LIMIT);
33
+ const maximumBytes = clampInteger(options.maxBytes, DEFAULT_MAX_BYTES, 64 * 1024, 256 * 1024 * 1024);
34
+ const records = [];
35
+ let exists = false, integrityFailures = 0, recoverableTailBytes = 0, inputTruncated = false, rotated = false;
36
+ for (const [index, source] of [`${telemetryPath}.1`, telemetryPath].entries()) {
37
+ const safe = resolveLocalStatePath(projectRoot, source, { label: "Context telemetry" });
38
+ try {
39
+ const stat = fs.lstatSync(safe);
40
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new Error("Context telemetry must be a regular file");
41
+ exists = true;
42
+ if (index === 0) rotated = true;
43
+ } catch (error) {
44
+ if (error?.code === "ENOENT") continue;
45
+ throw error;
46
+ }
47
+ const read = readTelemetryFile(safe, maximumBytes);
48
+ inputTruncated ||= read.truncated;
49
+ const complete = read.text.endsWith("\n") || read.text.endsWith("\r");
50
+ const lines = read.text.split(/\r?\n/);
51
+ if (!complete && lines.at(-1)) recoverableTailBytes += Buffer.byteLength(lines.at(-1));
52
+ for (const [lineIndex, line] of lines.entries()) {
53
+ if (!line) continue;
54
+ try {
55
+ const record = JSON.parse(line);
56
+ if (!record || typeof record !== "object" || Array.isArray(record) || record.truncated === true) integrityFailures += 1;
57
+ else records.push(record);
58
+ } catch {
59
+ if (complete || lineIndex !== lines.length - 1) integrityFailures += 1;
60
+ }
61
+ }
62
+ }
63
+ inputTruncated ||= rotated || records.length > limit;
64
+ return { records: records.slice(-limit), exists, integrityFailures, recoverableTailBytes, inputTruncated };
65
+ }