instar 1.2.82 → 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.
- package/dist/commands/init.js +14 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +143 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +23 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +2 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +268 -3
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +43 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +123 -24
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/installCodexHooks.d.ts.map +1 -1
- package/dist/core/installCodexHooks.js +3 -2
- package/dist/core/installCodexHooks.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts +153 -0
- package/dist/monitoring/SessionReaper.d.ts.map +1 -0
- package/dist/monitoring/SessionReaper.js +376 -0
- package/dist/monitoring/SessionReaper.js.map +1 -0
- package/dist/monitoring/TokenLedger.d.ts +12 -0
- package/dist/monitoring/TokenLedger.d.ts.map +1 -1
- package/dist/monitoring/TokenLedger.js +22 -0
- package/dist/monitoring/TokenLedger.js.map +1 -1
- package/dist/monitoring/transcriptProber.d.ts +44 -0
- package/dist/monitoring/transcriptProber.d.ts.map +1 -0
- package/dist/monitoring/transcriptProber.js +57 -0
- package/dist/monitoring/transcriptProber.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +6 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +3 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +20 -2
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +8 -2
- package/dist/server/stopGate.d.ts.map +1 -1
- package/dist/server/stopGate.js +42 -2
- package/dist/server/stopGate.js.map +1 -1
- package/package.json +1 -1
- package/playbook-scripts/build-state.py +39 -1
- package/scripts/analyze-release.js +16 -8
- package/scripts/generate-builtin-manifest.cjs +2 -1
- package/src/data/builtin-manifest.json +76 -67
- package/src/scaffold/templates.ts +6 -0
- package/src/templates/hooks/build-stop-hook.sh +62 -0
- package/src/templates/hooks/settings-template.json +10 -0
- package/upgrades/1.2.83.md +26 -0
- package/upgrades/1.3.0.md +27 -0
- package/upgrades/side-effects/build-stop-hook-session-scoping.md +133 -0
- package/upgrades/side-effects/fresh-session-stop-gate-shadow-wiring.md +35 -0
- package/upgrades/side-effects/session-reaper.md +42 -0
|
@@ -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
|
|
5
|
-
*
|
|
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
|
|
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"}
|
package/dist/server/stopGate.js
CHANGED
|
@@ -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
|
|
5
|
-
*
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"stopGate.js","sourceRoot":"","sources":["../../src/server/stopGate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -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", {
|
|
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 {
|
|
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
|
|
56
|
+
return gitRead(['describe', '--tags', '--abbrev=0']).trim();
|
|
49
57
|
} catch {
|
|
50
58
|
// No tags at all — diff against the initial commit
|
|
51
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|