instar 1.3.1024 → 1.3.1026

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 (40) hide show
  1. package/dist/commands/init.js +5 -0
  2. package/dist/commands/init.js.map +1 -1
  3. package/dist/core/PostUpdateMigrator.d.ts +2 -1
  4. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  5. package/dist/core/PostUpdateMigrator.js +109 -0
  6. package/dist/core/PostUpdateMigrator.js.map +1 -1
  7. package/dist/core/types.d.ts +10 -0
  8. package/dist/core/types.d.ts.map +1 -1
  9. package/dist/core/types.js.map +1 -1
  10. package/dist/monitoring/GrowthDigestPublisher.d.ts +143 -2
  11. package/dist/monitoring/GrowthDigestPublisher.d.ts.map +1 -1
  12. package/dist/monitoring/GrowthDigestPublisher.js +404 -21
  13. package/dist/monitoring/GrowthDigestPublisher.js.map +1 -1
  14. package/dist/monitoring/GrowthMilestoneAnalyst.d.ts.map +1 -1
  15. package/dist/monitoring/GrowthMilestoneAnalyst.js +8 -2
  16. package/dist/monitoring/GrowthMilestoneAnalyst.js.map +1 -1
  17. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  18. package/dist/monitoring/guardManifest.js +15 -0
  19. package/dist/monitoring/guardManifest.js.map +1 -1
  20. package/dist/server/AgentServer.d.ts.map +1 -1
  21. package/dist/server/AgentServer.js +13 -1
  22. package/dist/server/AgentServer.js.map +1 -1
  23. package/dist/server/routes.d.ts.map +1 -1
  24. package/dist/server/routes.js +23 -0
  25. package/dist/server/routes.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/data/builtin-manifest.json +65 -65
  28. package/src/data/state-coherence-registry.json +18 -0
  29. package/src/templates/hooks/settings-template.json +10 -0
  30. package/upgrades/1.2.39.md +13 -35
  31. package/upgrades/1.3.1025.md +76 -0
  32. package/upgrades/1.3.1026.md +80 -0
  33. package/upgrades/analysis-paralysis-guard-esm-safe.eli16.md +21 -0
  34. package/upgrades/analysis-paralysis-guard-init-parity.eli16.md +16 -0
  35. package/upgrades/growth-digest-fallback-tags.eli16.md +27 -0
  36. package/upgrades/side-effects/analysis-paralysis-guard-esm-safe.md +34 -0
  37. package/upgrades/side-effects/analysis-paralysis-guard-init-parity.md +34 -0
  38. package/upgrades/side-effects/analysis-paralysis-guard.md +66 -0
  39. package/upgrades/side-effects/growth-digest-fallback-tags.md +46 -0
  40. package/upgrades/side-effects/maturation-followthrough-fix-standard-c.md +138 -0
@@ -4437,6 +4437,13 @@ export class PostUpdateMigrator {
4437
4437
  catch (err) {
4438
4438
  result.errors.push(`slopcheck-guard.js: ${err instanceof Error ? err.message : String(err)}`);
4439
4439
  }
4440
+ try {
4441
+ fs.writeFileSync(path.join(instarHooksDir, 'analysis-paralysis-guard.js'), this.getAnalysisParalysisGuardHook(), { mode: 0o755 });
4442
+ result.upgraded.push('hooks/instar/analysis-paralysis-guard.js (act-or-report-blocked checklist)');
4443
+ }
4444
+ catch (err) {
4445
+ result.errors.push(`analysis-paralysis-guard.js: ${err instanceof Error ? err.message : String(err)}`);
4446
+ }
4440
4447
  try {
4441
4448
  fs.writeFileSync(path.join(instarHooksDir, 'post-action-reflection.js'), this.getPostActionReflectionHook(), { mode: 0o755 });
4442
4449
  result.upgraded.push('hooks/instar/post-action-reflection.js (evolution awareness)');
@@ -4628,6 +4635,7 @@ export class PostUpdateMigrator {
4628
4635
  'compaction-recovery.sh', 'external-operation-gate.js', 'deferral-detector.js',
4629
4636
  'self-stop-guard.js',
4630
4637
  'slopcheck-guard.js',
4638
+ 'analysis-paralysis-guard.js',
4631
4639
  'post-action-reflection.js', 'external-communication-guard.js',
4632
4640
  'scope-coherence-collector.js', 'scope-coherence-checkpoint.js',
4633
4641
  'instructions-loaded-tracker.js', 'subagent-start-tracker.js',
@@ -10837,6 +10845,7 @@ Two layers keep my machine-to-machine \"ropes\" (Tailscale / LAN / Cloudflare) h
10837
10845
  case 'deferral-detector': return this.getDeferralDetectorHook();
10838
10846
  case 'self-stop-guard': return this.getSelfStopGuardHook();
10839
10847
  case 'slopcheck-guard': return this.getSlopcheckGuardHook();
10848
+ case 'analysis-paralysis-guard': return this.getAnalysisParalysisGuardHook();
10840
10849
  case 'post-action-reflection': return this.getPostActionReflectionHook();
10841
10850
  case 'external-communication-guard': return this.getExternalCommunicationGuardHook();
10842
10851
  case 'scope-coherence-collector': return this.getScopeCoherenceCollectorHook();
@@ -13014,6 +13023,106 @@ process.stdin.on('end', () => {
13014
13023
  } catch { /* never block on errors */ }
13015
13024
  process.exit(0);
13016
13025
  })();
13026
+ `;
13027
+ }
13028
+ getAnalysisParalysisGuardHook() {
13029
+ return `#!/usr/bin/env node
13030
+ // Analysis-Paralysis Guard — catches agents stuck in a read-loop without acting.
13031
+ // PostToolUse hook. Tracks a sliding window of recent tool calls in a small
13032
+ // state file. If READ_ONLY tools (Read/Grep/Glob/WebFetch) fire 5+ times
13033
+ // in a row without an ACTION tool (Edit/Write/Bash/NotebookEdit) in between,
13034
+ // injects a "act or report blocked" checklist.
13035
+ //
13036
+ // Borrowed from gsd-executor's prompt — proven to kill a known failure mode
13037
+ // where agents spend the whole session researching and never commit.
13038
+ //
13039
+ // Cherry-picked into Instar's hook layer 2026-05-23 from the GSD-Instar
13040
+ // integration spike (docs/specs/topic-intent-layer.md + the spike report).
13041
+ // Signal-only — never blocks. Decision: approve + additionalContext.
13042
+
13043
+ // NOTE: uses \`await import('node:fs')\` inside the handler rather than a
13044
+ // top-level \`require\` — a bare require crashes outright in ESM-mode agents
13045
+ // (the hook-event-reporter lesson: an install-if-missing CJS hook left ESM
13046
+ // hosts permanently broken). Dynamic import works in both module systems.
13047
+
13048
+ const READ_ONLY_TOOLS = new Set(['Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch']);
13049
+ const ACTION_TOOLS = new Set(['Edit', 'Write', 'Bash', 'NotebookEdit']);
13050
+ const PARALYSIS_THRESHOLD = 5;
13051
+ const STATE_FILE_REL = '.instar/state/analysis-paralysis-state.json';
13052
+
13053
+ let data = '';
13054
+ process.stdin.on('data', chunk => data += chunk);
13055
+ process.stdin.on('end', async () => {
13056
+ try {
13057
+ const fs = await import('node:fs');
13058
+ const path = await import('node:path');
13059
+ const input = JSON.parse(data);
13060
+ const toolName = input.tool_name || '';
13061
+ if (!toolName) process.exit(0);
13062
+
13063
+ // Locate state file. CLAUDE_PROJECT_DIR is set by Claude Code on every hook.
13064
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
13065
+ const stateFile = path.join(projectDir, STATE_FILE_REL);
13066
+ let state = { recent: [] };
13067
+ try {
13068
+ if (fs.existsSync(stateFile)) {
13069
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
13070
+ if (!Array.isArray(state.recent)) state.recent = [];
13071
+ }
13072
+ } catch { state = { recent: [] }; }
13073
+
13074
+ const sessionId = input.session_id || 'default';
13075
+ const now = new Date().toISOString();
13076
+
13077
+ // Action tool → reset the per-session window
13078
+ if (ACTION_TOOLS.has(toolName)) {
13079
+ state.recent = state.recent.filter(e => e.sessionId !== sessionId);
13080
+ try {
13081
+ fs.mkdirSync(path.dirname(stateFile), { recursive: true });
13082
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
13083
+ } catch { /* best effort */ }
13084
+ process.exit(0);
13085
+ }
13086
+
13087
+ // Read-only tool → append to the window
13088
+ if (READ_ONLY_TOOLS.has(toolName)) {
13089
+ state.recent.push({ sessionId, tool: toolName, at: now });
13090
+ // Cap total entries across sessions to bound state file size
13091
+ if (state.recent.length > 200) state.recent = state.recent.slice(-200);
13092
+ try {
13093
+ fs.mkdirSync(path.dirname(stateFile), { recursive: true });
13094
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
13095
+ } catch { /* best effort */ }
13096
+
13097
+ // Count contiguous read-only entries for THIS session
13098
+ const sessionEntries = state.recent.filter(e => e.sessionId === sessionId);
13099
+ const consecutiveRO = sessionEntries.length;
13100
+
13101
+ if (consecutiveRO >= PARALYSIS_THRESHOLD) {
13102
+ const checklist = [
13103
+ 'ANALYSIS-PARALYSIS DETECTED — ' + consecutiveRO + ' consecutive read-only tool calls (' +
13104
+ sessionEntries.slice(-5).map(e => e.tool).join(' → ') + ') without an Edit / Write / Bash.',
13105
+ '',
13106
+ 'You have been researching without acting. Two paths from here:',
13107
+ '',
13108
+ '1. ACT — pick the smallest concrete action you can take with what you already know and DO it.',
13109
+ ' The next Edit / Write / Bash resets this counter.',
13110
+ '',
13111
+ '2. REPORT BLOCKED — if you genuinely cannot proceed, state precisely what is missing:',
13112
+ ' - a specific file or value you need access to',
13113
+ ' - a decision only the user can make',
13114
+ ' - an external dependency that has not been provisioned',
13115
+ '',
13116
+ 'If neither path is true, you are avoiding the hard part. Pick option 1.',
13117
+ ];
13118
+ process.stdout.write(JSON.stringify({ decision: 'approve', additionalContext: checklist.join('\\n') }));
13119
+ process.exit(0);
13120
+ }
13121
+ }
13122
+ // Other tools (TaskCreate, etc.) — pass through unchanged
13123
+ } catch { /* never block on errors */ }
13124
+ process.exit(0);
13125
+ });
13017
13126
  `;
13018
13127
  }
13019
13128
  getPostActionReflectionHook() {