instar 1.3.1145 → 1.3.1146

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.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
5
- "packageVersion": "1.3.1145",
5
+ "packageVersion": "1.3.1146",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "4a5b88caa62ae256f4868735dc66735c52ae30604a8272c977ca1f4564086e43",
2
+ "sha256": "675498ac7f3b9a5fd07a57a530eba5cc8645d84aede82b6f03348f7f502edb8a",
3
3
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
4
- "packageVersion": "1.3.1145"
4
+ "packageVersion": "1.3.1146"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
3
3
  "articleCount": 88,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1145"
5
+ "packageVersion": "1.3.1146"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1145",
3
+ "version": "1.3.1146",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -98,6 +98,162 @@ const FORBIDDEN_PATTERNS = [
98
98
 
99
99
  const EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs', '.cjs']);
100
100
 
101
+ function lineForOffset(text, offset) {
102
+ let line = 1;
103
+ for (let i = 0; i < offset; i++) {
104
+ if (text[i] === '\n') line++;
105
+ }
106
+ return line;
107
+ }
108
+
109
+ function stripCommentsPreserveLayout(text) {
110
+ let out = '';
111
+ let i = 0;
112
+ let quote = null;
113
+ let escaped = false;
114
+
115
+ while (i < text.length) {
116
+ const ch = text[i];
117
+ const next = text[i + 1];
118
+
119
+ if (quote) {
120
+ out += ch;
121
+ if (escaped) {
122
+ escaped = false;
123
+ } else if (ch === '\\') {
124
+ escaped = true;
125
+ } else if (ch === quote) {
126
+ quote = null;
127
+ }
128
+ i++;
129
+ continue;
130
+ }
131
+
132
+ if (ch === '"' || ch === "'" || ch === '`') {
133
+ quote = ch;
134
+ out += ch;
135
+ i++;
136
+ continue;
137
+ }
138
+
139
+ if (ch === '/' && next === '/') {
140
+ out += ' ';
141
+ i += 2;
142
+ while (i < text.length && text[i] !== '\n') {
143
+ out += ' ';
144
+ i++;
145
+ }
146
+ continue;
147
+ }
148
+
149
+ if (ch === '/' && next === '*') {
150
+ out += ' ';
151
+ i += 2;
152
+ while (i < text.length) {
153
+ if (text[i] === '*' && text[i + 1] === '/') {
154
+ out += ' ';
155
+ i += 2;
156
+ break;
157
+ }
158
+ out += text[i] === '\n' ? '\n' : ' ';
159
+ i++;
160
+ }
161
+ continue;
162
+ }
163
+
164
+ out += ch;
165
+ i++;
166
+ }
167
+
168
+ return out;
169
+ }
170
+
171
+ function skipWhitespace(text, index) {
172
+ while (index < text.length && /\s/.test(text[index])) index++;
173
+ return index;
174
+ }
175
+
176
+ function readStringLiteral(text, start) {
177
+ const quote = text[start];
178
+ if (quote !== '"' && quote !== "'" && quote !== '`') return null;
179
+
180
+ let value = '';
181
+ let i = start + 1;
182
+ let escaped = false;
183
+ while (i < text.length) {
184
+ const ch = text[i];
185
+ if (escaped) {
186
+ value += ch;
187
+ escaped = false;
188
+ i++;
189
+ continue;
190
+ }
191
+ if (ch === '\\') {
192
+ escaped = true;
193
+ i++;
194
+ continue;
195
+ }
196
+ if (quote === '`' && ch === '$' && text[i + 1] === '{') {
197
+ return null;
198
+ }
199
+ if (ch === quote) {
200
+ return { value, end: i + 1 };
201
+ }
202
+ value += ch;
203
+ i++;
204
+ }
205
+
206
+ return null;
207
+ }
208
+
209
+ function findFoldedStringViolations(text, rel) {
210
+ const stripped = stripCommentsPreserveLayout(text);
211
+ const violations = [];
212
+
213
+ for (let i = 0; i < stripped.length; i++) {
214
+ const first = readStringLiteral(stripped, i);
215
+ if (!first) continue;
216
+
217
+ let cursor = skipWhitespace(stripped, first.end);
218
+ if (stripped[cursor] !== '+') {
219
+ i = first.end - 1;
220
+ continue;
221
+ }
222
+
223
+ const parts = [first.value];
224
+ let end = first.end;
225
+ let literalCount = 1;
226
+ while (stripped[cursor] === '+') {
227
+ const nextStart = skipWhitespace(stripped, cursor + 1);
228
+ const nextString = readStringLiteral(stripped, nextStart);
229
+ if (!nextString) break;
230
+ parts.push(nextString.value);
231
+ literalCount++;
232
+ end = nextString.end;
233
+ cursor = skipWhitespace(stripped, nextString.end);
234
+ }
235
+
236
+ if (literalCount > 1) {
237
+ const folded = parts.join('');
238
+ const line = lineForOffset(stripped, i);
239
+ for (const pat of FORBIDDEN_PATTERNS) {
240
+ if (folded.includes(pat)) {
241
+ violations.push({
242
+ file: rel,
243
+ line,
244
+ pattern: pat,
245
+ text: folded.slice(0, 200),
246
+ folded: true,
247
+ });
248
+ }
249
+ }
250
+ i = end - 1;
251
+ }
252
+ }
253
+
254
+ return violations;
255
+ }
256
+
101
257
  function readGitignoreDirs() {
102
258
  // Skip node_modules, dist, .instar/worktrees, etc.
103
259
  return new Set(['node_modules', 'dist', 'build', '.instar', '.git', '.next', 'coverage']);
@@ -168,6 +324,7 @@ function checkFile(file) {
168
324
  }
169
325
  }
170
326
  }
327
+ violations.push(...findFoldedStringViolations(text, rel));
171
328
  return violations;
172
329
  }
173
330
 
@@ -184,7 +341,8 @@ function main() {
184
341
  console.error('src/core/ClaudeCliIntelligenceProvider.ts so the burn-detection system can');
185
342
  console.error('attribute it. See docs/specs/token-burn-detection-and-self-heal.md Phase 1.\n');
186
343
  for (const v of all) {
187
- console.error(` ${v.file}:${v.line} contains "${v.pattern}"`);
344
+ const reason = v.folded ? `folds to "${v.pattern}"` : `contains "${v.pattern}"`;
345
+ console.error(` ${v.file}:${v.line} — ${reason}`);
188
346
  console.error(` ${v.text}`);
189
347
  }
190
348
  process.exit(1);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-08-14T22:33:19.830Z",
5
- "instarVersion": "1.3.1145",
4
+ "generatedAt": "2026-08-14T22:54:06.076Z",
5
+ "instarVersion": "1.3.1146",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
5
- "packageVersion": "1.3.1145",
5
+ "packageVersion": "1.3.1146",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "4a5b88caa62ae256f4868735dc66735c52ae30604a8272c977ca1f4564086e43",
2
+ "sha256": "675498ac7f3b9a5fd07a57a530eba5cc8645d84aede82b6f03348f7f502edb8a",
3
3
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
4
- "packageVersion": "1.3.1145"
4
+ "packageVersion": "1.3.1146"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
3
3
  "articleCount": 88,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1145"
5
+ "packageVersion": "1.3.1146"
6
6
  }
@@ -0,0 +1,22 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ `scripts/lint-no-direct-llm-http.js` now folds adjacent constant string and no-expression template literals before checking for direct LLM provider hosts. A raw provider URL split as `'https://api.' + 'anthropic.com/v1/messages'` now fails the same build lint as the unsplit host.
9
+
10
+ The scope is deliberately narrow: literal-plus-literal URL construction only. Dynamic URL construction is not guessed at, and the existing file-level distinction for OAuth/profile/usage metadata endpoints remains unchanged.
11
+
12
+ ## What to Tell Your User
13
+
14
+ None — internal change (no user-facing surface).
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ None — internal change (no user-facing surface).
19
+
20
+ ## Evidence
21
+
22
+ Negative control against the shipped lint: the focused unit file failed 2 tests, both new split-host rejection cases. After the fix, `tests/unit/burn-detection-phase-1.test.ts` passes 20/20, and `node scripts/lint-no-direct-llm-http.js` exits clean against the real tree.
@@ -0,0 +1,82 @@
1
+ # Side-Effects Review — LLM HTTP lint constant folding
2
+
3
+ **Version / slug:** `llm-http-constant-folding`
4
+ **Date:** `2026-08-14`
5
+ **Author:** `Instar-codey`
6
+ **Tier:** 1 (one lint script plus focused unit coverage; no runtime code, route, config, migration, or persistence change)
7
+ **Second-pass reviewer:** `not required — CI/pre-commit lint hardening only; no runtime outbound message or session lifecycle decision`
8
+
9
+ ## Summary of the change
10
+
11
+ `scripts/lint-no-direct-llm-http.js` now folds adjacent constant string and no-expression template literals joined by `+` before checking for known LLM provider hosts. This closes the reproduced split-host bypass (`'api.' + 'anthropic.com/v1/messages'`) while keeping scope at literal URL construction only. `tests/unit/burn-detection-phase-1.test.ts` adds red/green coverage for split Anthropic, OpenAI, and Google host literals plus a non-folded dynamic construction control.
12
+
13
+ Build location re-grounding: work was built in fresh worktree `/Users/justin_instar_1/.instar/agents/instar-codey/.worktrees/agent-llm-http-constant-folding` from current `JKHeadley/main` (`4731ec6a90356ed319454a996b4eb72edcf38ab2`), created through `npx -y instar@1.3.1144 worktree create ... --base origin/main` after the local wrapper lacked an installed package. Remote verified as `origin https://github.com/JKHeadley/instar.git`; package version verified as `1.3.1144`.
14
+
15
+ ## Decision-point inventory
16
+
17
+ - `scripts/lint-no-direct-llm-http.js` — modify — build-time block/allow decision for direct provider HTTP references outside the provider chokepoint and named metadata exceptions.
18
+
19
+ ## 1. Over-block
20
+
21
+ The new over-block risk is a benign constant string in production source that names a provider host across literal pieces without making a call. That is the same policy as the existing unsplit-host lint: production source outside the allowlist should not carry raw provider host literals because they become copyable direct-call paths. The real-tree scan after the fix was clean.
22
+
23
+ OAuth/profile/usage metadata readers keep their existing allowlist/grandfather treatment; this change did not add endpoint-level bans that would collapse metadata reads into inference calls.
24
+
25
+ ## 2. Under-block
26
+
27
+ The lint still misses dynamic construction, such as `'https://api.' + providerHost + '/v1/messages'`, computed arrays joined into a host, decoded strings, or runtime config that points at a provider endpoint. That is intentional for this PR: automatic discovery/dataflow was the high-false-positive direction. The closure here is constant URL literals, not semantic HTTP-call proof.
28
+
29
+ ## 3. Level-of-abstraction fit
30
+
31
+ Correct layer: this is a deterministic CI lint in the existing `lint-no-*` family. The protected invariant is "new production raw LLM provider host literals outside the chokepoint require review." The lower-level primitive is a string-literal scanner, not an authority over runtime user intent.
32
+
33
+ ## 4. Signal vs authority compliance
34
+
35
+ Reference: [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md).
36
+
37
+ This change holds blocking authority with brittle logic, but it is a build-time hard invariant/safety guard, not a conversational judgment point. The lint blocks source code containing direct provider endpoint literals outside reviewed locations, analogous to a safety guard on data egress and spend attribution. It does not decide whether a user message is appropriate or whether an agent action should proceed at runtime.
38
+
39
+ ## 4b. Judgment-point check
40
+
41
+ No new static heuristic at a competing-signals decision point. The input is source text and an enumerated provider-host list; there are no live competing signals such as urgency, recency, ownership, or liveness.
42
+
43
+ ## 5. Interactions
44
+
45
+ - **Shadowing:** It runs inside the existing `npm run lint` chain. It may fail before later lints, as before; no downstream lint depends on side effects from this script.
46
+ - **Double-fire:** `lint-llm-attribution.js` and other provider-path checks may catch related defects, but this one reports direct HTTP host literals specifically. Duplicate CI failures are acceptable because they point at the same source change.
47
+ - **Races:** No shared state. It reads files and exits.
48
+ - **Feedback loops:** None.
49
+
50
+ ## 6. External surfaces
51
+
52
+ No runtime external surface changes. Other agents and users only see this as a stricter build/pre-commit/CI failure when source contains a newly-recognized split provider URL. No Telegram, Slack, GitHub API, dashboard, database, ledger, or generated URL behavior changes. No operator-facing action is added.
53
+
54
+ ## 6b. Operator-surface quality
55
+
56
+ No operator surface — not applicable.
57
+
58
+ ## 7. Multi-machine posture
59
+
60
+ Machine-local by design: this is a repository lint run independently in each checkout/CI runner. It emits no user-facing notices, holds no durable state, and generates no URLs. Multi-machine consistency comes from the shared git commit containing the lint and tests.
61
+
62
+ ## 8. Rollback cost
63
+
64
+ Pure code/test/docs change. Rollback is a hot-fix revert of the lint folding helper and tests. No data migration, no agent state repair, and no user-visible runtime regression while rollback propagates.
65
+
66
+ ## Conclusion
67
+
68
+ The real-tree scan stayed clean and the negative control failed for the intended old-lint cases, so the scoped constant-folding fix is clear to ship. No broader automatic actuator discovery or dynamic URL dataflow was added.
69
+
70
+ ## Second-pass review
71
+
72
+ Not required.
73
+
74
+ ## Evidence pointers
75
+
76
+ - Old-lint focused run: `npx vitest run tests/unit/burn-detection-phase-1.test.ts` failed 2 of 20 tests, specifically the two new split-host rejection tests.
77
+ - Fixed targeted run: `npx vitest run tests/unit/burn-detection-phase-1.test.ts` passed 20/20.
78
+ - Fixed real-tree scan: `node scripts/lint-no-direct-llm-http.js` exited 0.
79
+
80
+ ## Class-Closure Declaration (display-only mirror)
81
+
82
+ No agent-authored-artifact defect — not applicable.