instar 1.3.204 → 1.3.205
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 +1 -0
- package/dist/commands/init.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 +104 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/installCodexHooks.js +1 -1
- package/dist/core/installCodexHooks.js.map +1 -1
- package/dist/core/instarSettingsHooks.d.ts.map +1 -1
- package/dist/core/instarSettingsHooks.js +5 -0
- package/dist/core/instarSettingsHooks.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-builtin-manifest.cjs +1 -0
- package/src/data/builtin-manifest.json +28 -19
- package/upgrades/1.3.205.md +53 -0
- package/upgrades/side-effects/self-stop-guard.md +83 -0
|
@@ -1816,6 +1816,13 @@ export class PostUpdateMigrator {
|
|
|
1816
1816
|
catch (err) {
|
|
1817
1817
|
result.errors.push(`deferral-detector.js: ${err instanceof Error ? err.message : String(err)}`);
|
|
1818
1818
|
}
|
|
1819
|
+
try {
|
|
1820
|
+
fs.writeFileSync(path.join(instarHooksDir, 'self-stop-guard.js'), this.getSelfStopGuardHook(), { mode: 0o755 });
|
|
1821
|
+
result.upgraded.push('hooks/instar/self-stop-guard.js (self-stop excuse guard)');
|
|
1822
|
+
}
|
|
1823
|
+
catch (err) {
|
|
1824
|
+
result.errors.push(`self-stop-guard.js: ${err instanceof Error ? err.message : String(err)}`);
|
|
1825
|
+
}
|
|
1819
1826
|
try {
|
|
1820
1827
|
fs.writeFileSync(path.join(instarHooksDir, 'slopcheck-guard.js'), this.getSlopcheckGuardHook(), { mode: 0o755 });
|
|
1821
1828
|
result.upgraded.push('hooks/instar/slopcheck-guard.js (package-legitimacy check on installs)');
|
|
@@ -1995,6 +2002,7 @@ export class PostUpdateMigrator {
|
|
|
1995
2002
|
const builtinHooks = [
|
|
1996
2003
|
'session-start.sh', 'dangerous-command-guard.sh', 'grounding-before-messaging.sh',
|
|
1997
2004
|
'compaction-recovery.sh', 'external-operation-gate.js', 'deferral-detector.js',
|
|
2005
|
+
'self-stop-guard.js',
|
|
1998
2006
|
'slopcheck-guard.js',
|
|
1999
2007
|
'post-action-reflection.js', 'external-communication-guard.js',
|
|
2000
2008
|
'scope-coherence-collector.js', 'scope-coherence-checkpoint.js',
|
|
@@ -5097,6 +5105,7 @@ Create worktrees for collaborator repos with \`instar worktree create <branch>\`
|
|
|
5097
5105
|
case 'compaction-recovery': return this.getCompactionRecovery();
|
|
5098
5106
|
case 'external-operation-gate': return this.getExternalOperationGateHook();
|
|
5099
5107
|
case 'deferral-detector': return this.getDeferralDetectorHook();
|
|
5108
|
+
case 'self-stop-guard': return this.getSelfStopGuardHook();
|
|
5100
5109
|
case 'slopcheck-guard': return this.getSlopcheckGuardHook();
|
|
5101
5110
|
case 'post-action-reflection': return this.getPostActionReflectionHook();
|
|
5102
5111
|
case 'external-communication-guard': return this.getExternalCommunicationGuardHook();
|
|
@@ -6437,6 +6446,101 @@ process.stdin.on('end', () => {
|
|
|
6437
6446
|
} catch { /* don't break on errors */ }
|
|
6438
6447
|
process.exit(0);
|
|
6439
6448
|
});
|
|
6449
|
+
`;
|
|
6450
|
+
}
|
|
6451
|
+
getSelfStopGuardHook() {
|
|
6452
|
+
return `#!/usr/bin/env node
|
|
6453
|
+
// Self-stop guard — catches the agent rationalizing a session STOP for reasons
|
|
6454
|
+
// that are NEVER valid: "maxed out context", "session too long / running long",
|
|
6455
|
+
// "let's start a fresh session", "good stopping point", "close this out and
|
|
6456
|
+
// restart". PreToolUse hook for shell commands (Claude 'Bash' | Codex
|
|
6457
|
+
// 'exec_command'). Scans OUTBOUND messages to the user; when a stop-excuse is
|
|
6458
|
+
// detected it injects the "No context-death self-stops" reminder (does NOT
|
|
6459
|
+
// block) so the agent re-grounds before sending.
|
|
6460
|
+
//
|
|
6461
|
+
// Born from a real failure (2026-06-02): the agent closed out a 12h autonomous
|
|
6462
|
+
// run early citing "maxed out context" — one of the most deeply-rooted stop
|
|
6463
|
+
// excuses. The user's correction, verbatim: "ITS NOT!!!!! PERIOD!!!! Instar has
|
|
6464
|
+
// infrastructure to handle this and it's never an excuse. ... a session can run
|
|
6465
|
+
// infinitely." Compaction-recovery re-injects identity, memory, and recent
|
|
6466
|
+
// context automatically — context length is NEVER a stop reason. The ONLY
|
|
6467
|
+
// legitimate stops: a real design question only the user can answer, missing
|
|
6468
|
+
// information only they have, a genuine unrecoverable error, or actual
|
|
6469
|
+
// completion. The user explicitly asked for "infrastructure and awareness checks
|
|
6470
|
+
// on multiple levels to prevent this" (Structure > Willpower).
|
|
6471
|
+
//
|
|
6472
|
+
// SIGNAL ONLY — never blocks, never destructive. Sibling of deferral-detector.js
|
|
6473
|
+
// (which guards the false-blocker / orphan-TODO anti-patterns). Pure stdin→stdout
|
|
6474
|
+
// (no require/fs) so it is ESM-host safe.
|
|
6475
|
+
|
|
6476
|
+
let data = '';
|
|
6477
|
+
process.stdin.on('data', chunk => data += chunk);
|
|
6478
|
+
process.stdin.on('end', () => {
|
|
6479
|
+
try {
|
|
6480
|
+
const input = JSON.parse(data);
|
|
6481
|
+
// Codex-aware: Codex's shell tool is 'exec_command'; Claude's is 'Bash'.
|
|
6482
|
+
if (input.tool_name !== 'Bash' && input.tool_name !== 'exec_command') process.exit(0);
|
|
6483
|
+
|
|
6484
|
+
const command = (input.tool_input || {}).command || (input.tool_input || {}).cmd || '';
|
|
6485
|
+
if (!command) process.exit(0);
|
|
6486
|
+
|
|
6487
|
+
// Only check OUTBOUND messages to the user — the surface where a stop-excuse
|
|
6488
|
+
// gets communicated ("why don't we close this out and start fresh").
|
|
6489
|
+
const commPatterns = [
|
|
6490
|
+
/telegram-reply/i, /send-email/i, /send-message/i,
|
|
6491
|
+
/POST.*\\/telegram\\/(reply|post-update)/i, /slack.*send/i,
|
|
6492
|
+
];
|
|
6493
|
+
if (!commPatterns.some(p => p.test(command))) process.exit(0);
|
|
6494
|
+
|
|
6495
|
+
// Legitimate-stop anti-triggers — never nag a genuine, valid stop.
|
|
6496
|
+
const legitimateStop = [
|
|
6497
|
+
/ALL_TASKS_COMPLETE/,
|
|
6498
|
+
/<promise>/i,
|
|
6499
|
+
/(?:task|build|work|feature|fix|migration|spec|PR|all tests?|the suite) (?:is |are |now )?(?:complete|done|finished|shipped|merged|passing|green)\\b/i,
|
|
6500
|
+
/(?:you (?:asked|told|said) (?:me )?(?:to )?(?:stop|pause)|emergency stop|stop everything|as you requested|you wanted me to (?:stop|pause))/i,
|
|
6501
|
+
];
|
|
6502
|
+
if (legitimateStop.some(p => p.test(command))) process.exit(0);
|
|
6503
|
+
|
|
6504
|
+
// Stop-excuse patterns — rationalizing a stop for context/length reasons.
|
|
6505
|
+
const stopExcusePatterns = [
|
|
6506
|
+
{ re: /max(?:ed|ing)?[\\s-]*out (?:my |the |on )?context/i, type: 'maxed_context' },
|
|
6507
|
+
{ re: /(?:running |getting |almost )?(?:low|short|out) (?:on|of) context/i, type: 'low_on_context' },
|
|
6508
|
+
{ re: /context (?:window|limit|budget)?\\s*(?:is |getting |running )?(?:maxed|full|exhausted|tight|nearly full|almost full)/i, type: 'context_limit' },
|
|
6509
|
+
{ re: /(?:preserve|conserve|save|protect) (?:my |the |on )?context(?:\\s+window)?/i, type: 'preserve_context' },
|
|
6510
|
+
{ re: /(?:this |the |my )?session (?:has )?(?:been )?(?:going |running )?(?:on )?(?:too |very |really )?long\\b/i, type: 'session_too_long' },
|
|
6511
|
+
{ re: /long[\\s-]running session/i, type: 'long_running_session' },
|
|
6512
|
+
{ re: /been (?:going|running|at (?:this|it)) (?:for )?(?:too long|a (?:long )?while|quite a)/i, type: 'going_too_long' },
|
|
6513
|
+
{ re: /(?:start|spin up|kick off|begin|open|fire up) (?:a |another |the )?(?:fresh|new|clean|second) (?:session|run|window)/i, type: 'fresh_session_deflection' },
|
|
6514
|
+
{ re: /(?:continue|pick (?:this|it|things) up|resume) (?:in |with |on )?(?:a |the )?(?:fresh|new|next) session/i, type: 'continue_fresh_session' },
|
|
6515
|
+
{ re: /close (?:this )?(?:out|up)(?: here)?(?: and| then| to)? (?:start|begin|spin|open|kick)/i, type: 'close_out_and_restart' },
|
|
6516
|
+
{ re: /(?:good|natural|convenient|nice|reasonable) (?:place to (?:stop|pause|break)|(?:stopping|breaking) point)/i, type: 'good_stopping_point' },
|
|
6517
|
+
{ re: /(?:i'?ll |let'?s |i should |time to |going to |gonna )(?:stop|wrap (?:up|this up|it up)|pause|call it)(?:\\s+(?:here|now|for (?:now|today)))?/i, type: 'premature_wrap' },
|
|
6518
|
+
];
|
|
6519
|
+
|
|
6520
|
+
const matches = stopExcusePatterns.filter(p => p.re.test(command));
|
|
6521
|
+
if (matches.length === 0) process.exit(0);
|
|
6522
|
+
|
|
6523
|
+
const checklist = [
|
|
6524
|
+
'SELF-STOP EXCUSE DETECTED — you are about to tell the user you are stopping for a reason that is NEVER valid.',
|
|
6525
|
+
'',
|
|
6526
|
+
'"Maxed out context" / "session too long" / "let me start fresh" / "good stopping point" are NOT stop reasons.',
|
|
6527
|
+
'Instar has compaction infrastructure: compaction-recovery re-injects your identity, memory, and recent context automatically. A session can run indefinitely. The worst case of continuing is a ~30s re-read of your plan file — never lost work, as long as durable artifacts (committed code, a plan file, ledger rows) exist on disk.',
|
|
6528
|
+
'',
|
|
6529
|
+
'The ONLY legitimate stops are:',
|
|
6530
|
+
' 1. A real design question only the user can answer.',
|
|
6531
|
+
' 2. Missing information only the user has.',
|
|
6532
|
+
' 3. A genuine error you cannot resolve.',
|
|
6533
|
+
' 4. Actual, verified completion of the work.',
|
|
6534
|
+
'',
|
|
6535
|
+
'If your stop is NOT one of those four — do not send this. Keep going. If you have a milestone to report, report it AND continue; reporting progress is not stopping.',
|
|
6536
|
+
'',
|
|
6537
|
+
'Detected: ' + matches.map(m => m.type).join(', '),
|
|
6538
|
+
];
|
|
6539
|
+
|
|
6540
|
+
process.stdout.write(JSON.stringify({ decision: 'approve', additionalContext: checklist.join('\\n') }));
|
|
6541
|
+
} catch { /* never break on errors */ }
|
|
6542
|
+
process.exit(0);
|
|
6543
|
+
});
|
|
6440
6544
|
`;
|
|
6441
6545
|
}
|
|
6442
6546
|
getSlopcheckGuardHook() {
|