instar 1.2.83 → 1.3.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.
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * stopGate.ts — UnjustifiedStopGate server infrastructure (PR0a).
3
3
  *
4
- * Provides the read-side API surface that the future stop-hook router
5
- * consumes (PR3). State is in-memory for PR0a; PR3 migrates to SQLite.
4
+ * Provides the read-side API surface that the stop-hook router consumes.
5
+ * Runtime mode persists to disk so shadow-mode rollout survives server
6
+ * restarts; per-session hot-path state remains process-local and is
7
+ * repopulated by hook events.
6
8
  *
7
9
  * Spec: docs/specs/context-death-pitfall-prevention.md
8
10
  *
@@ -20,6 +22,10 @@
20
22
  export declare const GATE_ROUTE_VERSION = 1;
21
23
  export declare const GATE_ROUTE_MINIMUM_VERSION = 1;
22
24
  export type GateMode = 'off' | 'shadow' | 'enforce';
25
+ export declare function configureStopGateState(opts?: {
26
+ modeFilePath?: string;
27
+ defaultMode?: GateMode;
28
+ }): GateMode;
23
29
  export declare function getMode(): GateMode;
24
30
  export declare function setMode(mode: GateMode): void;
25
31
  export declare function getKillSwitch(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"stopGate.d.ts","sourceRoot":"","sources":["../../src/server/stopGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAeH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAS5C,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAiBpD,wBAAgB,OAAO,IAAI,QAAQ,CAElC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAE5C;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIrD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAI/E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AAgBD,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8DAC0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CA0B7E;AASD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;8EAE0E;IAC1E,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAoBD,wBAAgB,eAAe,CAAC,IAAI,GAAE,aAAkB,GAAG,YAAY,CAatE"}
1
+ {"version":3,"file":"stopGate.d.ts","sourceRoot":"","sources":["../../src/server/stopGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAS5C,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AA6CpD,wBAAgB,sBAAsB,CAAC,IAAI,GAAE;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,QAAQ,CAAC;CACnB,GAAG,QAAQ,CAShB;AAED,wBAAgB,OAAO,IAAI,QAAQ,CAElC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAG5C;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIrD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAI/E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AAgBD,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8DAC0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,sBAA2B,GAAG,OAAO,CA0B7E;AASD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;8EAE0E;IAC1E,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAoBD,wBAAgB,eAAe,CAAC,IAAI,GAAE,aAAkB,GAAG,YAAY,CAatE"}
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * stopGate.ts — UnjustifiedStopGate server infrastructure (PR0a).
3
3
  *
4
- * Provides the read-side API surface that the future stop-hook router
5
- * consumes (PR3). State is in-memory for PR0a; PR3 migrates to SQLite.
4
+ * Provides the read-side API surface that the stop-hook router consumes.
5
+ * Runtime mode persists to disk so shadow-mode rollout survives server
6
+ * restarts; per-session hot-path state remains process-local and is
7
+ * repopulated by hook events.
6
8
  *
7
9
  * Spec: docs/specs/context-death-pitfall-prevention.md
8
10
  *
@@ -34,13 +36,50 @@ export const GATE_ROUTE_MINIMUM_VERSION = 1;
34
36
  const state = {
35
37
  mode: 'off',
36
38
  killSwitch: false,
39
+ modeFilePath: null,
37
40
  sessionStartTs: new Map(),
38
41
  };
42
+ function readPersistedMode(filePath) {
43
+ try {
44
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
45
+ const mode = parsed.mode;
46
+ if (mode === 'off' || mode === 'shadow' || mode === 'enforce')
47
+ return mode;
48
+ }
49
+ catch {
50
+ // Missing/unreadable state is not fatal; caller supplies default.
51
+ }
52
+ return null;
53
+ }
54
+ function persistMode() {
55
+ if (!state.modeFilePath)
56
+ return;
57
+ try {
58
+ fs.mkdirSync(path.dirname(state.modeFilePath), { recursive: true });
59
+ fs.writeFileSync(state.modeFilePath, JSON.stringify({ mode: state.mode, updatedAt: new Date().toISOString() }, null, 2) + '\n', { mode: 0o600 });
60
+ }
61
+ catch {
62
+ // Fail open. The route still returns the in-memory mode; persistence
63
+ // failure is reported by the caller's normal health/degradation path.
64
+ }
65
+ }
66
+ export function configureStopGateState(opts = {}) {
67
+ if (opts.modeFilePath) {
68
+ state.modeFilePath = opts.modeFilePath;
69
+ state.mode = readPersistedMode(opts.modeFilePath) ?? (opts.defaultMode ?? state.mode);
70
+ persistMode();
71
+ return state.mode;
72
+ }
73
+ if (opts.defaultMode)
74
+ state.mode = opts.defaultMode;
75
+ return state.mode;
76
+ }
39
77
  export function getMode() {
40
78
  return state.mode;
41
79
  }
42
80
  export function setMode(mode) {
43
81
  state.mode = mode;
82
+ persistMode();
44
83
  }
45
84
  export function getKillSwitch() {
46
85
  return state.killSwitch;
@@ -83,6 +122,7 @@ export function getSessionStartTs(sessionId) {
83
122
  export function _resetForTests() {
84
123
  state.mode = 'off';
85
124
  state.killSwitch = false;
125
+ state.modeFilePath = null;
86
126
  state.sessionStartTs.clear();
87
127
  }
88
128
  // ── Compaction probe (P0.6) ─────────────────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"stopGate.js","sourceRoot":"","sources":["../../src/server/stopGate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stopGate.js","sourceRoot":"","sources":["../../src/server/stopGate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.2.83",
3
+ "version": "1.3.0",
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",
@@ -206,6 +206,30 @@ def git_run(args, cwd=None):
206
206
  return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
207
207
 
208
208
 
209
+ # ─── Owner identity (BUILD-STOP-HOOK-SESSION-SCOPING-SPEC) ────────────
210
+ # A build is owned by the session that started it. We stamp the owner's stable
211
+ # tmux session name (cwd-independent) at init so the Stop hook can scope its
212
+ # "keep working" block to the OWNER alone — other concurrent sessions of the same
213
+ # agent must approve-exit without draining the owner's reinforcement budget.
214
+ # Test seams (shared with build-stop-hook.sh): INSTAR_HOOK_TMUX_SESSION (if set,
215
+ # even empty, wins) and INSTAR_HOOK_NO_TMUX=1 (forces empty). Best-effort only —
216
+ # resolution failure must never break `init`.
217
+
218
+ def resolve_owner_tmux(explicit=None):
219
+ if explicit:
220
+ return explicit.strip()
221
+ if os.environ.get("INSTAR_HOOK_NO_TMUX") == "1":
222
+ return ""
223
+ if "INSTAR_HOOK_TMUX_SESSION" in os.environ:
224
+ return os.environ["INSTAR_HOOK_TMUX_SESSION"]
225
+ try:
226
+ r = subprocess.run(["tmux", "display-message", "-p", "#S"],
227
+ capture_output=True, text=True, timeout=3)
228
+ return r.stdout.strip() if r.returncode == 0 else ""
229
+ except Exception:
230
+ return ""
231
+
232
+
209
233
  # ─── Worktree Commands ──────────────────────────────────────────
210
234
 
211
235
  def cmd_worktree_create(args):
@@ -329,10 +353,16 @@ def cmd_init(args):
329
353
  out({"error": "Invalid size. Use SMALL, STANDARD, or LARGE"})
330
354
  sys.exit(1)
331
355
 
356
+ owner = {
357
+ "tmux": resolve_owner_tmux(getattr(args, "owner_tmux", None)),
358
+ "session": (getattr(args, "owner_session", None) or "").strip(),
359
+ "stampedAt": now_iso(),
360
+ }
332
361
  state = {
333
362
  "task": args.task, "phase": "idle", "size": size,
334
363
  "protection": PROTECTION_LEVELS[size],
335
364
  "startedAt": now_iso(), "completedAt": None,
365
+ "owner": owner,
336
366
  "currentStep": 0, "totalSteps": 0, "steps": [],
337
367
  "totalTests": 0, "allPassing": True,
338
368
  "fixIterations": 0, "maxFixIterations": 3,
@@ -341,7 +371,9 @@ def cmd_init(args):
341
371
  "worktree": None,
342
372
  }
343
373
  save_state(state)
344
- append_audit("build.initialized", {"task": args.task, "size": size})
374
+ append_audit("build.initialized", {
375
+ "task": args.task, "size": size,
376
+ "ownerTmux": owner["tmux"], "ownerSession": owner["session"]})
345
377
  out({"status": "initialized", "task": args.task, "size": size,
346
378
  "protection": PROTECTION_LEVELS[size]["label"],
347
379
  "reinforcements": PROTECTION_LEVELS[size]["reinforcements"]})
@@ -583,6 +615,12 @@ def main():
583
615
  s.add_argument("task")
584
616
  s.add_argument("--size", choices=["SMALL", "STANDARD", "LARGE"],
585
617
  default="STANDARD")
618
+ # Owner identity (session-scoping). --owner-session carries the Claude session
619
+ # UUID ($CLAUDE_CODE_SESSION_ID), which child processes don't inherit, so the
620
+ # SKILL passes it explicitly. --owner-tmux is an override seam (tests / unusual
621
+ # launches); normally the tmux name is self-resolved.
622
+ s.add_argument("--owner-session", default="")
623
+ s.add_argument("--owner-tmux", default="")
586
624
 
587
625
  s = sub.add_parser("transition")
588
626
  s.add_argument("phase")
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ // safe-git-allow: release analyzer runs before TS source is compiled; read-only git only.
2
3
  /**
3
4
  * Release Change Analyzer
4
5
  *
@@ -24,11 +25,10 @@
24
25
  * node scripts/analyze-release.js --recommend-only # Just recommend bump type
25
26
  */
26
27
 
27
- import { execSync } from 'node:child_process';
28
+ import { execFileSync } from 'node:child_process';
28
29
  import fs from 'node:fs';
29
30
  import path from 'node:path';
30
31
  import { fileURLToPath } from 'node:url';
31
- import { SafeGitExecutor } from '../src/core/SafeGitExecutor.js';
32
32
 
33
33
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
34
34
  const ROOT = path.resolve(__dirname, '..');
@@ -43,18 +43,26 @@ function log(msg) {
43
43
 
44
44
  // ── Git Helpers ──────────────────────────────────────────────────────
45
45
 
46
+ function gitRead(args) {
47
+ return execFileSync('git', args, {
48
+ cwd: ROOT,
49
+ encoding: 'utf-8',
50
+ stdio: ['ignore', 'pipe', 'pipe'],
51
+ });
52
+ }
53
+
46
54
  function getLastReleaseTag() {
47
55
  try {
48
- return SafeGitExecutor.readSync(['describe', '--tags', '--abbrev=0'], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:48' }).trim();
56
+ return gitRead(['describe', '--tags', '--abbrev=0']).trim();
49
57
  } catch {
50
58
  // No tags at all — diff against the initial commit
51
- return SafeGitExecutor.readSync(['rev-list', '--max-parents=0', 'HEAD'], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:52' }).trim();
59
+ return gitRead(['rev-list', '--max-parents=0', 'HEAD']).trim();
52
60
  }
53
61
  }
54
62
 
55
63
  function getCommitsSinceTag(tag) {
56
64
  try {
57
- const raw = SafeGitExecutor.readSync(['log', `${tag}..HEAD`, '--oneline', '--no-merges'], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:getCommitsSinceTag' });
65
+ const raw = gitRead(['log', `${tag}..HEAD`, '--oneline', '--no-merges']);
58
66
  return raw.trim().split('\n').filter(Boolean).map(line => {
59
67
  const [hash, ...rest] = line.split(' ');
60
68
  return { hash, message: rest.join(' ') };
@@ -66,7 +74,7 @@ function getCommitsSinceTag(tag) {
66
74
 
67
75
  function getDiffStat(tag) {
68
76
  try {
69
- return SafeGitExecutor.readSync(['diff', `${tag}..HEAD`, '--stat'], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:getDiffStat' }).trim();
77
+ return gitRead(['diff', `${tag}..HEAD`, '--stat']).trim();
70
78
  } catch {
71
79
  return '';
72
80
  }
@@ -74,7 +82,7 @@ function getDiffStat(tag) {
74
82
 
75
83
  function getChangedFiles(tag) {
76
84
  try {
77
- const raw = SafeGitExecutor.readSync(['diff', `${tag}..HEAD`, '--name-status'], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:getChangedFiles' });
85
+ const raw = gitRead(['diff', `${tag}..HEAD`, '--name-status']);
78
86
  return raw.trim().split('\n').filter(Boolean).map(line => {
79
87
  const [status, ...pathParts] = line.split('\t');
80
88
  return { status: status.charAt(0), file: pathParts.join('\t') };
@@ -86,7 +94,7 @@ function getChangedFiles(tag) {
86
94
 
87
95
  function getFileDiff(tag, file) {
88
96
  try {
89
- return SafeGitExecutor.readSync(['diff', `${tag}..HEAD`, '--', file], { cwd: ROOT, encoding: 'utf-8', operation: 'scripts/analyze-release.js:getFileDiff' });
97
+ return gitRead(['diff', `${tag}..HEAD`, '--', file]);
90
98
  } catch {
91
99
  return '';
92
100
  }
@@ -43,7 +43,7 @@ function fileExists(filePath) {
43
43
 
44
44
  /**
45
45
  * Scan hooks from PostUpdateMigrator's migrateHooks method.
46
- * These are the 14 hook files Instar writes to .instar/hooks/instar/.
46
+ * These are the hook files Instar writes to .instar/hooks/instar/.
47
47
  */
48
48
  function scanHooks() {
49
49
  const entries = [];
@@ -63,6 +63,7 @@ function scanHooks() {
63
63
  { file: 'free-text-guard.sh', domain: 'safety' },
64
64
  { file: 'claim-intercept.js', domain: 'coherence' },
65
65
  { file: 'claim-intercept-response.js', domain: 'coherence' },
66
+ { file: 'stop-gate-router.js', domain: 'safety' },
66
67
  { file: 'auto-approve-permissions.js', domain: 'safety' },
67
68
  ];
68
69