claude-code-session-manager 0.111.0 → 0.113.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/.claude-plugin/marketplace.json +2 -2
- package/dist/assets/{AgentLibrary-rBO1daqM.js → AgentLibrary-wvrcLGGS.js} +2 -2
- package/dist/assets/{Button-DsEYRZg0.js → Button-B6h0F0XT.js} +1 -1
- package/dist/assets/{DataModel-D8sbvvBC.js → DataModel-C5pW9E3u.js} +1 -1
- package/dist/assets/{History-BEHLtxia.js → History-BV4e8YOM.js} +2 -2
- package/dist/assets/{Hooks-CKpvlXrg.js → Hooks-CrFSv4x1.js} +3 -3
- package/dist/assets/{Library-CeF4qh9d.js → Library-D-GIt3EY.js} +5 -5
- package/dist/assets/{ListDetail-DcfmxPFk.js → ListDetail-Bco_wfs6.js} +1 -1
- package/dist/assets/{MarkdownEditor-CvK1pyto.js → MarkdownEditor-C-yHSXNV.js} +1 -1
- package/dist/assets/{McpServers-D-h2ihzJ.js → McpServers-CfDekadG.js} +2 -2
- package/dist/assets/{Memory-BnF89x8v.js → Memory-CGGLexkR.js} +4 -4
- package/dist/assets/{Panel-CQY5zano.js → Panel-DGMEuYYG.js} +1 -1
- package/dist/assets/{Permissions-DLukmmsz.js → Permissions-Cx2zjtYZ.js} +3 -3
- package/dist/assets/{Plugins-0Pf0OZ4l.js → Plugins-Bc_W3IyR.js} +2 -2
- package/dist/assets/ProvenanceBadge-DiKAUR1u.js +1 -0
- package/dist/assets/RemoteMachines-8_77-WPD.js +3 -0
- package/dist/assets/{SaveBar-DjijiUb0.js → SaveBar-Blpzdq1R.js} +1 -1
- package/dist/assets/{Scheduler-Cm3EXZvE.js → Scheduler-Bd70AM4X.js} +9 -9
- package/dist/assets/{ScopeSwitcher-B-P-kSfq.js → ScopeSwitcher-wxN0h4YW.js} +1 -1
- package/dist/assets/Settings-CQ7DA3zW.js +4 -0
- package/dist/assets/{SkillReferenceGraph-Epv2GJmj.js → SkillReferenceGraph-DH1NLOiS.js} +1 -1
- package/dist/assets/Skills-CmyRyu4_.js +2 -0
- package/dist/assets/SystemPrompt-KAc3UMCd.js +1 -0
- package/dist/assets/TagLibrary-C8EvHnpg.js +1 -0
- package/dist/assets/{TiptapBody-DAMO3DhO.js → TiptapBody-d423mH6D.js} +1 -1
- package/dist/assets/{Toggle-Ba_f7q_m.js → Toggle-D1wsGE9S.js} +1 -1
- package/dist/assets/{ViewTabs-CGX6MAhc.js → ViewTabs-CjHw3kGY.js} +1 -1
- package/dist/assets/{historyTotals-vgfk8EOL.js → historyTotals-DFHzqLt7.js} +1 -1
- package/dist/assets/{index-CPieAFsl.js → index-Ci1u018F.js} +266 -266
- package/dist/assets/{settingsSchema-D0FxNrTy.js → settingsSchema-Ctf3pZVI.js} +1 -1
- package/dist/assets/{useAgentsDirWatch-DCu6BNYN.js → useAgentsDirWatch-B1NBmOAe.js} +1 -1
- package/dist/assets/{useRemotePeers-D4cdJDyh.js → useRemotePeers-BHjSJs9D.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +3 -2
- package/plugins/CLAUDE.md +5 -8
- package/plugins/session-manager-dev/.claude-plugin/plugin.json +3 -6
- package/plugins/session-manager-dev/skills/builder/1-classify-and-bump/SKILL.md +2 -2
- package/plugins/session-manager-dev/skills/builder/SKILL.md +2 -3
- package/plugins/session-manager-dev/skills/develop/SKILL.md +1 -1
- package/plugins/session-manager-dev/skills/develop/standards.md +3 -3
- package/plugins/session-manager-dev/skills/send-feedback/SKILL.md +13 -0
- package/scripts/README.md +3 -3
- package/scripts/audit-ops-hygiene.cjs +4 -4
- package/scripts/hooks/guard-destructive-git.cjs +4 -4
- package/scripts/hooks/guard-inline-implementation.cjs +1 -1
- package/scripts/hooks/guard-prd-writes.cjs +2 -2
- package/scripts/hooks/lib/guard-destructive-git-policy.cjs +1 -1
- package/scripts/mint-epic.cjs +2 -2
- package/scripts/scheduler-mcp-server.cjs +27 -9
- package/src/main/agentLibrary.cjs +5 -5
- package/src/main/agentsIpc.cjs +76 -0
- package/src/main/build-info.json +4 -4
- package/src/main/chatRunner.cjs +30 -13
- package/src/main/config.cjs +20 -3
- package/src/main/crashDiagnostics.cjs +2 -2
- package/src/main/docEdit.cjs +5 -5
- package/src/main/files.cjs +2 -2
- package/src/main/git.cjs +1 -1
- package/src/main/health.cjs +20 -18
- package/src/main/heapSnapshot.cjs +1 -1
- package/src/main/historyAggregator.cjs +2 -2
- package/src/main/index.cjs +50 -132
- package/src/main/ipcSchemas.cjs +13 -10
- package/src/main/lib/CLAUDE.md +48 -0
- package/src/main/lib/activeSessions.cjs +14 -1
- package/src/main/lib/classifyPromptTicket.cjs +2 -2
- package/src/main/lib/{agentModelResolve.cjs → claude/agentModelResolve.cjs} +7 -7
- package/src/main/lib/{claudeBin.cjs → claude/claudeBin.cjs} +4 -4
- package/src/main/lib/{effectiveModelInfo.cjs → claude/effectiveModelInfo.cjs} +9 -9
- package/src/main/lib/{modelCatalog.cjs → claude/modelCatalog.cjs} +3 -3
- package/src/main/lib/claude/rateLimitDetect.cjs +54 -0
- package/src/main/lib/{rateLimitWindow.cjs → claude/rateLimitWindow.cjs} +24 -12
- package/src/main/lib/{runClaudeP.cjs → claude/runClaudeP.cjs} +1 -1
- package/src/main/lib/credentials.cjs +18 -92
- package/src/main/lib/cwdClassify.cjs +1 -1
- package/src/main/lib/{activeIndexMerge.cjs → epic/activeIndexMerge.cjs} +3 -3
- package/src/main/lib/{activeIndexRebuild.cjs → epic/activeIndexRebuild.cjs} +1 -1
- package/src/main/lib/{delegationReadiness.cjs → epic/delegationReadiness.cjs} +21 -29
- package/src/main/lib/{epicContextDigest.cjs → epic/epicContextDigest.cjs} +1 -1
- package/src/main/lib/{epicDelegationStats.cjs → epic/epicDelegationStats.cjs} +2 -2
- package/src/main/lib/{epicMint.cjs → epic/epicMint.cjs} +11 -11
- package/src/main/lib/{epicSpawnPlan.cjs → epic/epicSpawnPlan.cjs} +3 -3
- package/src/main/lib/{epicStatusMirror.cjs → epic/epicStatusMirror.cjs} +2 -2
- package/src/main/lib/{epicTranscriptDiagnostic.cjs → epic/epicTranscriptDiagnostic.cjs} +2 -2
- package/src/main/lib/{epicTranscriptPath.cjs → epic/epicTranscriptPath.cjs} +2 -2
- package/src/main/lib/{epicValidationHook.cjs → epic/epicValidationHook.cjs} +3 -3
- package/src/main/lib/{epicWorktreeBoot.cjs → epic/epicWorktreeBoot.cjs} +1 -1
- package/src/main/lib/{epicWorktreeMerge.cjs → epic/epicWorktreeMerge.cjs} +3 -3
- package/src/main/lib/{epicWorktreeMint.cjs → epic/epicWorktreeMint.cjs} +3 -3
- package/src/main/lib/{epicWorktreeProjectConfig.cjs → epic/epicWorktreeProjectConfig.cjs} +4 -4
- package/src/main/lib/{promptSessionsCreateEpic.cjs → epic/promptSessionsCreateEpic.cjs} +4 -4
- package/src/main/lib/{crossProjectFeedback.cjs → feedback-remote/crossProjectFeedback.cjs} +114 -16
- package/src/main/lib/{customerFeedbackClient.cjs → feedback-remote/customerFeedbackClient.cjs} +3 -3
- package/src/main/lib/{customerFeedbackInbox.cjs → feedback-remote/customerFeedbackInbox.cjs} +2 -2
- package/src/main/lib/{customerFeedbackIpc.cjs → feedback-remote/customerFeedbackIpc.cjs} +1 -1
- package/src/main/lib/feedback-remote/humanPromptLedger.cjs +93 -0
- package/src/main/lib/{localAdminHttp.cjs → feedback-remote/localAdminHttp.cjs} +2 -2
- package/src/main/lib/{macroAdminRoutes.cjs → feedback-remote/macroAdminRoutes.cjs} +1 -1
- package/src/main/lib/{projectHomeAdminRoutes.cjs → feedback-remote/projectHomeAdminRoutes.cjs} +4 -4
- package/src/main/lib/{relayClientAuth.cjs → feedback-remote/relayClientAuth.cjs} +2 -2
- package/src/main/lib/{remoteClientSessions.cjs → feedback-remote/remoteClientSessions.cjs} +1 -1
- package/src/main/lib/{gitWorktree.cjs → git/gitWorktree.cjs} +7 -7
- package/src/main/lib/historyRollup.cjs +1 -1
- package/src/main/lib/importReferences.cjs +1 -1
- package/src/main/lib/machineProfile.cjs +1 -1
- package/src/main/lib/mcpToolCatalog.cjs +9 -3
- package/src/main/lib/openExternalApp.cjs +1 -1
- package/src/main/lib/opsOwnership.cjs +3 -3
- package/src/main/lib/{agentPersonaSchema.cjs → persona-macro/agentPersonaSchema.cjs} +2 -2
- package/src/main/lib/{macroLibrary.cjs → persona-macro/macroLibrary.cjs} +5 -5
- package/src/main/lib/{personaMerge.cjs → persona-macro/personaMerge.cjs} +4 -4
- package/src/main/lib/{depSlugResolve.cjs → prd/depSlugResolve.cjs} +16 -1
- package/src/main/lib/{prdAdminRoutes.cjs → prd/prdAdminRoutes.cjs} +7 -7
- package/src/main/lib/{prdAgentType.cjs → prd/prdAgentType.cjs} +3 -3
- package/src/main/lib/{prdCreate.cjs → prd/prdCreate.cjs} +12 -12
- package/src/main/lib/{prdDeclaredPaths.cjs → prd/prdDeclaredPaths.cjs} +1 -1
- package/src/main/lib/{prdGateFiles.cjs → prd/prdGateFiles.cjs} +1 -1
- package/src/main/lib/{prdLocations.cjs → prd/prdLocations.cjs} +2 -2
- package/src/main/lib/{prdMigration.cjs → prd/prdMigration.cjs} +3 -3
- package/src/main/lib/prereqs.cjs +2 -2
- package/src/main/lib/{instanceLock.cjs → process/instanceLock.cjs} +4 -11
- package/src/main/lib/{pidAlive.cjs → process/pidAlive.cjs} +1 -1
- package/src/main/lib/{procName.cjs → process/procName.cjs} +2 -2
- package/src/main/lib/{timeoutShim.cjs → process/timeoutShim.cjs} +1 -1
- package/src/main/lib/projectRootResolve.cjs +1 -1
- package/src/main/lib/promptSessionSchema.cjs +1 -1
- package/src/main/lib/{definitionOfDone.cjs → scheduler/definitionOfDone.cjs} +6 -12
- package/src/main/lib/scheduler/finalizeReason.cjs +30 -0
- package/src/main/lib/{fixChainDepth.cjs → scheduler/fixChainDepth.cjs} +1 -1
- package/src/main/lib/scheduler/flatSweepThrottle.cjs +17 -0
- package/src/main/lib/{jobDirtFilter.cjs → scheduler/jobDirtFilter.cjs} +1 -1
- package/src/main/lib/{jobSupervisorRecord.cjs → scheduler/jobSupervisorRecord.cjs} +1 -1
- package/src/main/lib/{launchFailure.cjs → scheduler/launchFailure.cjs} +2 -2
- package/src/main/lib/{queueStore.cjs → scheduler/queueStore.cjs} +6 -6
- package/src/main/lib/{quietMachineLease.cjs → scheduler/quietMachineLease.cjs} +1 -1
- package/src/main/lib/{rcaReport.cjs → scheduler/rcaReport.cjs} +4 -4
- package/src/main/lib/{reaperHelpers.cjs → scheduler/reaperHelpers.cjs} +3 -3
- package/src/main/lib/{reservationExpiry.cjs → scheduler/reservationExpiry.cjs} +4 -11
- package/src/main/lib/{reviewNotice.cjs → scheduler/reviewNotice.cjs} +1 -1
- package/src/main/lib/{runLogRetention.cjs → scheduler/runLogRetention.cjs} +34 -13
- package/src/main/lib/{scheduleJobTransitions.cjs → scheduler/scheduleJobTransitions.cjs} +3 -3
- package/src/main/lib/{schedulerBatch.cjs → scheduler/schedulerBatch.cjs} +9 -13
- package/src/main/lib/{schedulerConfig.cjs → scheduler/schedulerConfig.cjs} +1 -1
- package/src/main/lib/{schedulerRuntimeState.cjs → scheduler/schedulerRuntimeState.cjs} +1 -1
- package/src/main/lib/{sessionSlots.cjs → scheduler/sessionSlots.cjs} +2 -2
- package/src/main/lib/{upgradeDrain.cjs → scheduler/upgradeDrain.cjs} +8 -11
- package/src/main/lib/{watchdogHelpers.cjs → scheduler/watchdogHelpers.cjs} +5 -19
- package/src/main/lib/{auditLog.cjs → telemetry/auditLog.cjs} +1 -1
- package/src/main/lib/{opsErrorLog.cjs → telemetry/opsErrorLog.cjs} +4 -4
- package/src/main/lib/{telemetryBacklog.cjs → telemetry/telemetryBacklog.cjs} +4 -4
- package/src/main/lib/{telemetryBoot.cjs → telemetry/telemetryBoot.cjs} +1 -1
- package/src/main/lib/{telemetryClient.cjs → telemetry/telemetryClient.cjs} +12 -8
- package/src/main/lib/{telemetrySettings.cjs → telemetry/telemetrySettings.cjs} +1 -1
- package/src/main/lib/{atomicFs.cjs → util/atomicFs.cjs} +42 -0
- package/src/main/lib/{loopDelay.cjs → util/loopDelay.cjs} +1 -1
- package/src/main/logs.cjs +1 -1
- package/src/main/mcpStatus.cjs +2 -2
- package/src/main/memoryAggregate.cjs +3 -3
- package/src/main/memoryTool.cjs +1 -1
- package/src/main/otel.cjs +2 -2
- package/src/main/pluginInstall.cjs +29 -3
- package/src/main/projectBrief.cjs +6 -6
- package/src/main/projectPages.cjs +1 -1
- package/src/main/promptSessionEvents.cjs +2 -2
- package/src/main/pty.cjs +7 -7
- package/src/main/queueOps.cjs +6 -6
- package/src/main/remoteClient.cjs +4 -4
- package/src/main/remoteClientIpc.cjs +1 -1
- package/src/main/runVerify.cjs +6 -3
- package/src/main/scheduler/CLAUDE.md +26 -0
- package/src/main/scheduler/budget.cjs +576 -0
- package/src/main/scheduler/gitTreeGuard.cjs +672 -0
- package/src/main/scheduler/prdParser.cjs +4 -4
- package/src/main/scheduler/prdPaths.cjs +487 -0
- package/src/main/scheduler/reviewLadder.cjs +1011 -0
- package/src/main/scheduler/starvation.cjs +390 -0
- package/src/main/scheduler.cjs +331 -3320
- package/src/main/seedAgentPersonas.cjs +5 -5
- package/src/main/seedDevPlugin.cjs +70 -3
- package/src/main/seedSchedulerMcp.cjs +2 -2
- package/src/main/supervisor.cjs +50 -27
- package/src/main/telemetryIpc.cjs +51 -0
- package/src/main/transcripts.cjs +3 -3
- package/src/main/updaterIpc.cjs +1 -1
- package/src/main/usage.cjs +1 -1
- package/src/main/watchers.cjs +1 -1
- package/src/main/webRemote.cjs +22 -7
- package/src/preload/api.d.ts +14 -8
- package/src/preload/index.cjs +9 -3
- package/dist/assets/ProvenanceBadge-vC7Tj-JP.js +0 -1
- package/dist/assets/RemoteMachines-CWnKbFHc.js +0 -3
- package/dist/assets/Settings-DYDlp2m_.js +0 -4
- package/dist/assets/Skills-DHO0N0C2.js +0 -2
- package/dist/assets/SystemPrompt-DxeNofL9.js +0 -1
- package/dist/assets/TagLibrary-QOAs7ISO.js +0 -1
- package/plugins/session-manager-dev/skills/blog-for-project-feature/0-select/SKILL.md +0 -39
- package/plugins/session-manager-dev/skills/blog-for-project-feature/1-research/SKILL.md +0 -37
- package/plugins/session-manager-dev/skills/blog-for-project-feature/2-storyboard/SKILL.md +0 -64
- package/plugins/session-manager-dev/skills/blog-for-project-feature/3-capture/SKILL.md +0 -52
- package/plugins/session-manager-dev/skills/blog-for-project-feature/4-draft-copy/SKILL.md +0 -37
- package/plugins/session-manager-dev/skills/blog-for-project-feature/5-illustrate/SKILL.md +0 -50
- package/plugins/session-manager-dev/skills/blog-for-project-feature/6-compose/SKILL.md +0 -51
- package/plugins/session-manager-dev/skills/blog-for-project-feature/7-review/SKILL.md +0 -54
- package/plugins/session-manager-dev/skills/blog-for-project-feature/SKILL.md +0 -144
- package/plugins/session-manager-dev/skills/blog-for-project-feature/feature.config.yaml +0 -90
- package/plugins/session-manager-dev/skills/discover-features/SKILL.md +0 -95
- package/plugins/session-manager-dev/skills/explain-to-me/SKILL.md +0 -205
- package/plugins/session-manager-dev/skills/explain-to-me/assets/style-reference.html +0 -163
- package/plugins/session-manager-dev/skills/find-opportunity/SKILL.md +0 -83
- package/plugins/session-manager-dev/skills/issue-address/0-select/0-fetch-pool/SKILL.md +0 -38
- package/plugins/session-manager-dev/skills/issue-address/0-select/1-reject-fixed/SKILL.md +0 -64
- package/plugins/session-manager-dev/skills/issue-address/0-select/2-reject-claimed/SKILL.md +0 -71
- package/plugins/session-manager-dev/skills/issue-address/0-select/3-rank-impact/SKILL.md +0 -39
- package/plugins/session-manager-dev/skills/issue-address/0-select/SKILL.md +0 -75
- package/plugins/session-manager-dev/skills/issue-address/1-confirm-open/SKILL.md +0 -39
- package/plugins/session-manager-dev/skills/issue-address/2-claim/SKILL.md +0 -57
- package/plugins/session-manager-dev/skills/issue-address/3-reproduce/SKILL.md +0 -40
- package/plugins/session-manager-dev/skills/issue-address/4-fix/SKILL.md +0 -33
- package/plugins/session-manager-dev/skills/issue-address/5-verify/SKILL.md +0 -40
- package/plugins/session-manager-dev/skills/issue-address/SKILL.md +0 -120
- package/plugins/session-manager-dev/skills/local-project-health/SKILL.md +0 -58
- package/plugins/session-manager-dev/skills/memory-sanitation/SKILL.md +0 -147
- package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +0 -137
- package/plugins/session-manager-dev/skills/pr-review-sweep/0-fetch/SKILL.md +0 -41
- package/plugins/session-manager-dev/skills/pr-review-sweep/1-classify/SKILL.md +0 -56
- package/plugins/session-manager-dev/skills/pr-review-sweep/2-check-fixed/SKILL.md +0 -49
- package/plugins/session-manager-dev/skills/pr-review-sweep/3-queue/SKILL.md +0 -57
- package/plugins/session-manager-dev/skills/pr-review-sweep/4-land-and-resolve/SKILL.md +0 -60
- package/plugins/session-manager-dev/skills/pr-review-sweep/SKILL.md +0 -124
- package/plugins/session-manager-dev/skills/pr-signal/SKILL.md +0 -67
- package/plugins/session-manager-dev/skills/project-status/SKILL.md +0 -243
- package/plugins/session-manager-dev/skills/requesting-code-review/SKILL.md +0 -98
- package/plugins/session-manager-dev/skills/requesting-code-review/code-reviewer.md +0 -146
- package/src/main/lib/rateLimitDetect.cjs +0 -35
- /package/src/main/lib/{agentEffortResolve.cjs → claude/agentEffortResolve.cjs} +0 -0
- /package/src/main/lib/{claudeCliCaps.cjs → claude/claudeCliCaps.cjs} +0 -0
- /package/src/main/lib/{usageCircuit.cjs → claude/usageCircuit.cjs} +0 -0
- /package/src/main/lib/{epicSpawnCwd.cjs → epic/epicSpawnCwd.cjs} +0 -0
- /package/src/main/lib/{customerFeedbackAdminRoutes.cjs → feedback-remote/customerFeedbackAdminRoutes.cjs} +0 -0
- /package/src/main/lib/{remoteE2eCrypto.cjs → feedback-remote/remoteE2eCrypto.cjs} +0 -0
- /package/src/main/lib/{branchSweep.cjs → git/branchSweep.cjs} +0 -0
- /package/src/main/lib/{gitExec.cjs → git/gitExec.cjs} +0 -0
- /package/src/main/lib/{jobWorktree.cjs → git/jobWorktree.cjs} +0 -0
- /package/src/main/lib/{jobWorktreeBootLive.cjs → git/jobWorktreeBootLive.cjs} +0 -0
- /package/src/main/lib/{jobWorktreeTerminalOrphanLive.cjs → git/jobWorktreeTerminalOrphanLive.cjs} +0 -0
- /package/src/main/lib/{builtinMacros.cjs → persona-macro/builtinMacros.cjs} +0 -0
- /package/src/main/lib/{personaImportHealth.cjs → persona-macro/personaImportHealth.cjs} +0 -0
- /package/src/main/lib/{shippedPersonaSeeds.cjs → persona-macro/shippedPersonaSeeds.cjs} +0 -0
- /package/src/main/lib/{planValidator.cjs → prd/planValidator.cjs} +0 -0
- /package/src/main/lib/{prdAuthoringSeed.cjs → prd/prdAuthoringSeed.cjs} +0 -0
- /package/src/main/lib/{prdDisposition.cjs → prd/prdDisposition.cjs} +0 -0
- /package/src/main/lib/{prdFrontmatter.cjs → prd/prdFrontmatter.cjs} +0 -0
- /package/src/main/lib/{prdSizing.cjs → prd/prdSizing.cjs} +0 -0
- /package/src/main/lib/{workTypeLibrary.cjs → prd/workTypeLibrary.cjs} +0 -0
- /package/src/main/lib/{childWithLog.cjs → process/childWithLog.cjs} +0 -0
- /package/src/main/lib/{cleanEnv.cjs → process/cleanEnv.cjs} +0 -0
- /package/src/main/lib/{defaultShell.cjs → process/defaultShell.cjs} +0 -0
- /package/src/main/lib/{killTree.cjs → process/killTree.cjs} +0 -0
- /package/src/main/lib/{loginShellPath.cjs → process/loginShellPath.cjs} +0 -0
- /package/src/main/lib/{procIdentity.cjs → process/procIdentity.cjs} +0 -0
- /package/src/main/lib/{singleInstanceGuard.cjs → process/singleInstanceGuard.cjs} +0 -0
- /package/src/main/lib/{smProcNames.cjs → process/smProcNames.cjs} +0 -0
- /package/src/main/lib/{timeoutShimScript.cjs → process/timeoutShimScript.cjs} +0 -0
- /package/src/main/lib/{winSpawn.cjs → process/winSpawn.cjs} +0 -0
- /package/src/main/lib/{adoptedRunSupervisor.cjs → scheduler/adoptedRunSupervisor.cjs} +0 -0
- /package/src/main/lib/{dispatchLoop.cjs → scheduler/dispatchLoop.cjs} +0 -0
- /package/src/main/lib/{dodDrainHook.cjs → scheduler/dodDrainHook.cjs} +0 -0
- /package/src/main/lib/{fixPlanSlug.cjs → scheduler/fixPlanSlug.cjs} +0 -0
- /package/src/main/lib/{gateAuthority.cjs → scheduler/gateAuthority.cjs} +0 -0
- /package/src/main/lib/{landedSinceRun.cjs → scheduler/landedSinceRun.cjs} +0 -0
- /package/src/main/lib/{loadGate.cjs → scheduler/loadGate.cjs} +0 -0
- /package/src/main/lib/{needsReviewLedger.cjs → scheduler/needsReviewLedger.cjs} +0 -0
- /package/src/main/lib/{queueHealth.cjs → scheduler/queueHealth.cjs} +0 -0
- /package/src/main/lib/{queueHistory.cjs → scheduler/queueHistory.cjs} +0 -0
- /package/src/main/lib/{scheduleJobSchema.cjs → scheduler/scheduleJobSchema.cjs} +0 -0
- /package/src/main/lib/{schedulerPaths.cjs → scheduler/schedulerPaths.cjs} +0 -0
- /package/src/main/lib/{terminalRunOutcome.cjs → scheduler/terminalRunOutcome.cjs} +0 -0
- /package/src/main/lib/{validationSentinels.cjs → scheduler/validationSentinels.cjs} +0 -0
- /package/src/main/lib/{crashTelemetry.cjs → telemetry/crashTelemetry.cjs} +0 -0
- /package/src/main/lib/{otlpTraceExporter.cjs → telemetry/otlpTraceExporter.cjs} +0 -0
- /package/src/main/lib/{telemetryConsent.cjs → telemetry/telemetryConsent.cjs} +0 -0
- /package/src/main/lib/{telemetryCounters.cjs → telemetry/telemetryCounters.cjs} +0 -0
- /package/src/main/lib/{encodeCwd.cjs → util/encodeCwd.cjs} +0 -0
- /package/src/main/lib/{expandHome.cjs → util/expandHome.cjs} +0 -0
- /package/src/main/lib/{extractJson.cjs → util/extractJson.cjs} +0 -0
- /package/src/main/lib/{fileTail.cjs → util/fileTail.cjs} +0 -0
- /package/src/main/lib/{headTailBuffer.cjs → util/headTailBuffer.cjs} +0 -0
- /package/src/main/lib/{kebabCase.cjs → util/kebabCase.cjs} +0 -0
- /package/src/main/lib/{lruCache.cjs → util/lruCache.cjs} +0 -0
- /package/src/main/lib/{withTimeout.cjs → util/withTimeout.cjs} +0 -0
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
const fs = require('node:fs');
|
|
27
27
|
const path = require('node:path');
|
|
28
28
|
const os = require('node:os');
|
|
29
|
-
const { splitFrontmatter } = require('
|
|
30
|
-
const { resolveEpicTranscriptPath } = require('
|
|
31
|
-
const schedulerPaths = require('
|
|
29
|
+
const { splitFrontmatter } = require('../prd/prdFrontmatter.cjs');
|
|
30
|
+
const { resolveEpicTranscriptPath } = require('../epic/epicTranscriptPath.cjs');
|
|
31
|
+
const schedulerPaths = require('../scheduler/schedulerPaths.cjs');
|
|
32
32
|
|
|
33
33
|
// Deliberately stays a FIXED alias set (reviewed against the catalog-driven raw picker): it answers
|
|
34
34
|
// "alias vs concrete id", not "which options to offer", so live catalog ids must not enter it.
|
|
@@ -70,7 +70,7 @@ function isConcreteModelId(modelAlias) {
|
|
|
70
70
|
*/
|
|
71
71
|
function computeEffortEnvReachable(deps) {
|
|
72
72
|
try {
|
|
73
|
-
const { cleanChildEnv } = deps.cleanEnv || require('
|
|
73
|
+
const { cleanChildEnv } = deps.cleanEnv || require('../process/cleanEnv.cjs');
|
|
74
74
|
const probe = cleanChildEnv({ CLAUDE_EFFORT: 'high', CLAUDE_CODE_EFFORT_LEVEL: 'high' });
|
|
75
75
|
return Boolean(probe.CLAUDE_EFFORT || probe.CLAUDE_CODE_EFFORT_LEVEL);
|
|
76
76
|
} catch {
|
|
@@ -93,7 +93,7 @@ function computeEffortEnvReachable(deps) {
|
|
|
93
93
|
* for the same dangling reference.
|
|
94
94
|
*/
|
|
95
95
|
async function resolvePersonaModelAlias(cwd, agentType, deps) {
|
|
96
|
-
const getPersonaBody = deps.getPersonaBody || require('
|
|
96
|
+
const getPersonaBody = deps.getPersonaBody || require('../../agentLibrary.cjs').getPersonaBody;
|
|
97
97
|
// The overlay-vs-global provenance question itself ("which of
|
|
98
98
|
// resolvePersonaPaths' two candidates won") is answered by
|
|
99
99
|
// agentModelResolve.cjs's isProjectOverlayPersonaPath, not re-derived here
|
|
@@ -125,7 +125,7 @@ async function resolvePersonaModelAlias(cwd, agentType, deps) {
|
|
|
125
125
|
|
|
126
126
|
/** Best-effort read of `<cwd>/session-manager-operations/scheduler/state/queue.json`'s hot jobs[]. */
|
|
127
127
|
function readHotJobsForCwd(cwd, deps) {
|
|
128
|
-
const { projectQueuePath } = deps.queueStore || require('
|
|
128
|
+
const { projectQueuePath } = deps.queueStore || require('../scheduler/queueStore.cjs');
|
|
129
129
|
try {
|
|
130
130
|
const data = JSON.parse(fs.readFileSync(projectQueuePath(cwd), 'utf8'));
|
|
131
131
|
return Array.isArray(data.jobs) ? data.jobs : [];
|
|
@@ -136,7 +136,7 @@ function readHotJobsForCwd(cwd, deps) {
|
|
|
136
136
|
|
|
137
137
|
/** Best-effort read of `<cwd>/session-manager-operations/scheduler/state/history.jsonl`'s archived rows. */
|
|
138
138
|
function readHistoryEntriesForCwd(cwd, deps) {
|
|
139
|
-
const { projectHistoryPath } = deps.queueStore || require('
|
|
139
|
+
const { projectHistoryPath } = deps.queueStore || require('../scheduler/queueStore.cjs');
|
|
140
140
|
let text;
|
|
141
141
|
try {
|
|
142
142
|
text = fs.readFileSync(projectHistoryPath(cwd), 'utf8');
|
|
@@ -246,7 +246,7 @@ function findLatestSchedulerModel(cwd, agentType, deps) {
|
|
|
246
246
|
* O(min(transcriptSize, cap)) per transcript read.
|
|
247
247
|
*/
|
|
248
248
|
function findLatestTranscriptModel(cwd, agentType, deps) {
|
|
249
|
-
const readActiveIndex = deps.readActiveIndex || require('
|
|
249
|
+
const readActiveIndex = deps.readActiveIndex || require('../epic/epicMint.cjs').readActiveIndex;
|
|
250
250
|
let sessions;
|
|
251
251
|
try {
|
|
252
252
|
({ sessions } = readActiveIndex(cwd));
|
|
@@ -296,7 +296,7 @@ async function resolveEffectiveModelInfo({ cwd, agentType, deps = {} } = {}) {
|
|
|
296
296
|
if (!cwd || !agentType) return miss;
|
|
297
297
|
|
|
298
298
|
try {
|
|
299
|
-
const { projectRootOf } = deps.activeSessions || require('
|
|
299
|
+
const { projectRootOf } = deps.activeSessions || require('../activeSessions.cjs');
|
|
300
300
|
const normalizedCwd = projectRootOf(path.resolve(cwd));
|
|
301
301
|
if (!normalizedCwd) return miss;
|
|
302
302
|
|
|
@@ -29,7 +29,7 @@ const SCAN_OVERLAP_BYTES = 128;
|
|
|
29
29
|
const MODEL_ID_RE = /claude-(?:opus|sonnet|haiku|fable)-[0-9][0-9-]*/g;
|
|
30
30
|
// A real CLI binary is tens of MB; test stubs and launcher shims are tiny shell scripts.
|
|
31
31
|
const MIN_SCAN_BYTES = 1024 * 1024;
|
|
32
|
-
const SCHEMA_PATH = path.join(__dirname, '..', '..', 'renderer', 'data', 'claude-settings-schema.json');
|
|
32
|
+
const SCHEMA_PATH = path.join(__dirname, '..', '..', '..', 'renderer', 'data', 'claude-settings-schema.json');
|
|
33
33
|
|
|
34
34
|
const CATALOG_FLOOR = Object.freeze({
|
|
35
35
|
aliases: Object.freeze(['haiku', 'sonnet', 'opus', 'fable']),
|
|
@@ -118,7 +118,7 @@ function readAvailableModels(cwd, d, fsImpl) {
|
|
|
118
118
|
const home = d.homeDir ? d.homeDir() : os.homedir();
|
|
119
119
|
let root = null;
|
|
120
120
|
if (cwd) {
|
|
121
|
-
try { root = (d.projectRootOf || require('
|
|
121
|
+
try { root = (d.projectRootOf || require('../activeSessions.cjs').projectRootOf)(path.resolve(cwd)); } catch { root = path.resolve(cwd); }
|
|
122
122
|
}
|
|
123
123
|
const files = [path.join(home, '.claude', 'settings.json')];
|
|
124
124
|
if (root) files.push(path.join(root, '.claude', 'settings.json'), path.join(root, '.claude', 'settings.local.json'));
|
|
@@ -221,7 +221,7 @@ async function doResolve({ cwd, force, deps }) {
|
|
|
221
221
|
};
|
|
222
222
|
// Unknown version = unknown cache key: writing it would stamp `claudeVersion: null` over a real entry.
|
|
223
223
|
if (!degraded && cacheFile && claudeVersion) {
|
|
224
|
-
try { await (d.writeJson || require('
|
|
224
|
+
try { await (d.writeJson || require('../../config.cjs').writeJson)(cacheFile, catalog); } catch { /* cache is best-effort */ }
|
|
225
225
|
}
|
|
226
226
|
return catalog;
|
|
227
227
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* rateLimitDetect.cjs — the single source of truth for "did this claude -p
|
|
5
|
+
* log tail show a rate-limit death". Shared by spawnJob() (a still-running
|
|
6
|
+
* process that just exited) and reapDeadRunningJobs()/classifyRunOutcome()
|
|
7
|
+
* (a process the reaper found already dead) — see PRD 1117. Before this,
|
|
8
|
+
* only spawnJob checked this; the reaper had no rate-limit branch at all,
|
|
9
|
+
* so a rate-limited exit that the reaper won the race to finalize got
|
|
10
|
+
* stamped terminal 'failed' instead of retryable 'pending'. There must
|
|
11
|
+
* never be a second, independently-drifting regex set at either call site.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { readTail } = require('../util/fileTail.cjs');
|
|
15
|
+
|
|
16
|
+
/** Scan the tail of a job's log for a GENUINE rate-limit rejection. Parses the
|
|
17
|
+
* last 16 KB line by line as JSON (non-JSON / partial lines are skipped) and
|
|
18
|
+
* returns true only for: (a) a rate_limit_event whose rate_limit_info.status
|
|
19
|
+
* is 'rejected'; (b) a result event with api_error_status 429; (c) an
|
|
20
|
+
* is_error result event whose `result` text is the CLI's limit message
|
|
21
|
+
* ("You've hit your ... limit" / "You've reached your ... limit").
|
|
22
|
+
*
|
|
23
|
+
* Never substring-match the raw text: informational rate_limit_event lines
|
|
24
|
+
* (status 'allowed' / 'allowed_warning') carry rateLimitType on every run, so
|
|
25
|
+
* the old substring match turned any non-zero exit (e.g. a watchdog SIGTERM,
|
|
26
|
+
* exit 143) into a machine-wide rate_limit pause (2026-10-11 incident: 4-day
|
|
27
|
+
* pause at 58% weekly). Tool output may also mention 429 or "rate limit". */
|
|
28
|
+
function detectRateLimitInLog(logPath) {
|
|
29
|
+
try {
|
|
30
|
+
const text = readTail(logPath, 16384);
|
|
31
|
+
if (!text) return false;
|
|
32
|
+
for (const line of text.split('\n')) {
|
|
33
|
+
const t = line.trim();
|
|
34
|
+
if (!t || t[0] !== '{') continue;
|
|
35
|
+
let ev;
|
|
36
|
+
try { ev = JSON.parse(t); } catch { continue; }
|
|
37
|
+
if (!ev || typeof ev !== 'object') continue;
|
|
38
|
+
if (ev.type === 'rate_limit_event') {
|
|
39
|
+
if (ev.rate_limit_info && ev.rate_limit_info.status === 'rejected') return true;
|
|
40
|
+
} else if (ev.type === 'result') {
|
|
41
|
+
if (ev.api_error_status === 429) return true;
|
|
42
|
+
if (ev.is_error === true && typeof ev.result === 'string'
|
|
43
|
+
&& (/You'?ve hit your .*limit/.test(ev.result) || /You'?ve reached your .* limit/.test(ev.result))) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { detectRateLimitInLog };
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* unit-testable without scheduler.cjs (mirrors reaperHelpers.cjs's split).
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const { readTail } = require('
|
|
16
|
+
const { readTail } = require('../util/fileTail.cjs');
|
|
17
17
|
|
|
18
18
|
// Authoritative window block rides on the LAST rate_limit_event in the log
|
|
19
19
|
// (often the one attached to the final result), so mirror classifyRunOutcome's
|
|
@@ -21,17 +21,21 @@ const { readTail } = require('./fileTail.cjs');
|
|
|
21
21
|
const TAIL_BYTES = 64 * 1024;
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Scans a run log's tail for rate_limit_event entries
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Scans a run log's tail for rate_limit_event entries. The REJECTED event is
|
|
25
|
+
* authoritative (2026-10-11 incident: an allowed-only log with a seven_day
|
|
26
|
+
* window pause landed on the seven_day reset 4 days out): if any event has
|
|
27
|
+
* status 'rejected', the LAST one's reset wins — rate_limit_info.resetsAt, else
|
|
28
|
+
* unifiedWindows[rateLimitType].resetsAt. Otherwise, a last event carrying a
|
|
29
|
+
* status (allowed / allowed_warning) yields null, even if a window shows
|
|
30
|
+
* utilization >= 1.0 (overage is not a rejection). Legacy: a last event with
|
|
31
|
+
* no status falls back to the latest resetsAt among windows at utilization >= 1.0.
|
|
29
32
|
*/
|
|
30
33
|
function resolveBindingRateLimitReset(logPath) {
|
|
31
34
|
const text = readTail(logPath, TAIL_BYTES);
|
|
32
35
|
if (!text) return null;
|
|
33
36
|
|
|
34
|
-
let
|
|
37
|
+
let lastRejected = null;
|
|
38
|
+
let lastEvent = null;
|
|
35
39
|
for (const line of text.split('\n')) {
|
|
36
40
|
const trimmed = line.trim();
|
|
37
41
|
if (!trimmed || trimmed[0] !== '{') continue;
|
|
@@ -41,12 +45,20 @@ function resolveBindingRateLimitReset(logPath) {
|
|
|
41
45
|
} catch {
|
|
42
46
|
continue;
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
if (event?.type !== 'rate_limit_event' || !event.rate_limit_info) continue;
|
|
49
|
+
lastEvent = event.rate_limit_info;
|
|
50
|
+
if (lastEvent.status === 'rejected') lastRejected = lastEvent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (lastRejected) {
|
|
54
|
+
if (typeof lastRejected.resetsAt === 'number') return lastRejected.resetsAt;
|
|
55
|
+
const typed = lastRejected.unifiedWindows?.[lastRejected.rateLimitType]?.resetsAt;
|
|
56
|
+
return typeof typed === 'number' ? typed : null;
|
|
48
57
|
}
|
|
49
|
-
if (!
|
|
58
|
+
if (!lastEvent || lastEvent.status !== undefined) return null;
|
|
59
|
+
|
|
60
|
+
const lastWindows = lastEvent.unifiedWindows;
|
|
61
|
+
if (!lastWindows || typeof lastWindows !== 'object') return null;
|
|
50
62
|
|
|
51
63
|
let latestBoundReset = null;
|
|
52
64
|
for (const window of Object.values(lastWindows)) {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
const { spawn } = require('node:child_process');
|
|
18
18
|
const { resolveClaudeBin, claudeSpawnTarget } = require('./claudeBin.cjs');
|
|
19
19
|
const { headlessPermissionArgs, ensureCliCapsProbed } = require('./claudeCliCaps.cjs');
|
|
20
|
-
const { withProcRole } = require('
|
|
20
|
+
const { withProcRole } = require('../process/cleanEnv.cjs');
|
|
21
21
|
|
|
22
22
|
const MAX_OUT_BYTES = 8 * 1024 * 1024;
|
|
23
23
|
|
|
@@ -5,9 +5,8 @@ const fs = require('node:fs');
|
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
const os = require('node:os');
|
|
7
7
|
const { spawn, execFileSync } = require('node:child_process');
|
|
8
|
-
const { cleanChildEnv, pathWithUserBins } = require('./cleanEnv.cjs');
|
|
9
|
-
const
|
|
10
|
-
const { resolveClaudeBin, claudeSpawnTarget } = require('./claudeBin.cjs');
|
|
8
|
+
const { cleanChildEnv, pathWithUserBins } = require('./process/cleanEnv.cjs');
|
|
9
|
+
const { resolveClaudeBin, claudeSpawnTarget } = require('./claude/claudeBin.cjs');
|
|
11
10
|
|
|
12
11
|
const CREDS_PATH = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
13
12
|
|
|
@@ -47,22 +46,9 @@ function keychainAccount() {
|
|
|
47
46
|
return os.userInfo().username;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
/** Write the credential JSON back into the Keychain (-U upserts in place). */
|
|
51
|
-
function writeKeychainRaw(value) {
|
|
52
|
-
execFileSync(
|
|
53
|
-
'security',
|
|
54
|
-
['add-generic-password', '-U', '-s', KEYCHAIN_SERVICE, '-a', keychainAccount(), '-w', value],
|
|
55
|
-
{ timeout: 10_000, stdio: 'ignore' },
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
49
|
const REFRESH_LOG_PATH = path.join(os.homedir(), '.claude', 'session-manager', 'credential-refresh.log');
|
|
59
50
|
const REFRESH_LOG_MAX_BYTES = 100 * 1024;
|
|
60
51
|
|
|
61
|
-
// Standard OAuth 2.0 refresh grant — endpoint discovered from Claude Code CLI behavior.
|
|
62
|
-
// Returns { kind: 'unsupported' } if the endpoint returns 404 or cannot be reached,
|
|
63
|
-
// allowing the caller to fall back gracefully.
|
|
64
|
-
const OAUTH_TOKEN_URL = 'https://claude.ai/api/auth/oauth/token';
|
|
65
|
-
|
|
66
52
|
/** Parse a raw credential JSON blob (from file or Keychain) into a result. */
|
|
67
53
|
function parseCredsRaw(raw, source) {
|
|
68
54
|
let data;
|
|
@@ -125,14 +111,13 @@ function isExpiringSoon(creds, withinMs = 5 * 60_000) {
|
|
|
125
111
|
* isRefreshFutile(creds) → boolean
|
|
126
112
|
*
|
|
127
113
|
* True when the token is already expired AND there is no refresh token to
|
|
128
|
-
* present. In that state
|
|
129
|
-
* short-circuits to 'unsupported' (it needs `creds.refreshToken`), and the
|
|
114
|
+
* present. In that state the refresh avenue is a dead end: the
|
|
130
115
|
* `claude --version` CLI fallback performs its own silent OAuth refresh from
|
|
131
116
|
* that SAME missing refresh token, so it cannot help either. The only recovery
|
|
132
117
|
* is an out-of-band `claude login` — which refreshIfNeeded picks up on its very
|
|
133
118
|
* next call via the isExpiringSoon early-return, since fresh creds never reach
|
|
134
119
|
* this path. Left ungated, this state made pollLoop spawn a `claude --version`
|
|
135
|
-
* process and write the
|
|
120
|
+
* process and write the cli_fallback_ok →
|
|
136
121
|
* auth_failed_expired triple on EVERY 15 s poll, forever (observed 2026-09-23:
|
|
137
122
|
* expiredAtMs 1775277875159, identical triple every ~15 min across the log).
|
|
138
123
|
*/
|
|
@@ -153,17 +138,6 @@ function __resetFutileRefreshThrottle() {
|
|
|
153
138
|
lastFutileRefreshLoggedAt = null;
|
|
154
139
|
}
|
|
155
140
|
|
|
156
|
-
async function writeCredentials(rawData, freshOauth, source = 'file') {
|
|
157
|
-
const next = { ...rawData, claudeAiOauth: { ...rawData.claudeAiOauth, ...freshOauth } };
|
|
158
|
-
if (source === 'keychain') {
|
|
159
|
-
// macOS: upsert back into the Keychain. Sync + may throw — caller catches
|
|
160
|
-
// and falls back to the `claude --version` CLI refresh path.
|
|
161
|
-
writeKeychainRaw(JSON.stringify(next));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
await atomicFs.writeJsonAtomic(CREDS_PATH, next, { mode: 0o600, newline: false });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
141
|
function appendRefreshLog(entry) {
|
|
168
142
|
try {
|
|
169
143
|
const line = JSON.stringify({ ...entry, ts: new Date().toISOString() }) + '\n';
|
|
@@ -179,36 +153,7 @@ function appendRefreshLog(entry) {
|
|
|
179
153
|
} catch { /* non-fatal; telemetry must not break the main flow */ }
|
|
180
154
|
}
|
|
181
155
|
|
|
182
|
-
//
|
|
183
|
-
async function tryOAuthRefresh(creds) {
|
|
184
|
-
if (!creds.refreshToken) return { kind: 'unsupported', message: 'no refresh token in credentials' };
|
|
185
|
-
try {
|
|
186
|
-
const r = await fetch(OAUTH_TOKEN_URL, {
|
|
187
|
-
method: 'POST',
|
|
188
|
-
headers: { 'Content-Type': 'application/json' },
|
|
189
|
-
body: JSON.stringify({ grant_type: 'refresh_token', refresh_token: creds.refreshToken }),
|
|
190
|
-
signal: AbortSignal.timeout(10_000),
|
|
191
|
-
});
|
|
192
|
-
if (r.status === 404) return { kind: 'unsupported', message: 'refresh endpoint not found (HTTP 404)' };
|
|
193
|
-
if (r.status === 401 || r.status === 403) return { kind: 'auth', message: `refresh rejected: HTTP ${r.status}` };
|
|
194
|
-
if (!r.ok) return { kind: 'transient', message: `HTTP ${r.status}` };
|
|
195
|
-
const j = await r.json();
|
|
196
|
-
if (!j.access_token) return { kind: 'auth', message: 'no access_token in refresh response' };
|
|
197
|
-
return {
|
|
198
|
-
kind: 'ok',
|
|
199
|
-
fresh: {
|
|
200
|
-
accessToken: j.access_token,
|
|
201
|
-
refreshToken: j.refresh_token ?? creds.refreshToken,
|
|
202
|
-
expiresAt: j.expires_at ?? (Date.now() + (j.expires_in ?? 3600) * 1000),
|
|
203
|
-
},
|
|
204
|
-
};
|
|
205
|
-
} catch (e) {
|
|
206
|
-
if (e?.name === 'TimeoutError') return { kind: 'transient', message: 'refresh request timed out' };
|
|
207
|
-
return { kind: 'unsupported', message: `refresh error: ${e?.message}` };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Stretch fallback: spawning `claude --version` triggers silent token refresh in the CLI binary.
|
|
156
|
+
// Sole refresh avenue: spawning `claude --version` triggers silent token refresh in the CLI binary.
|
|
212
157
|
function tryCliFallback() {
|
|
213
158
|
return new Promise((resolve) => {
|
|
214
159
|
let settled = false;
|
|
@@ -244,7 +189,7 @@ function tryCliFallback() {
|
|
|
244
189
|
async function refreshIfNeeded(forceRefresh = false) {
|
|
245
190
|
const cr = await readCredentials();
|
|
246
191
|
if (cr.kind !== 'ok') return cr;
|
|
247
|
-
const { creds
|
|
192
|
+
const { creds } = cr;
|
|
248
193
|
|
|
249
194
|
if (!forceRefresh && !isExpiringSoon(creds)) {
|
|
250
195
|
return { kind: 'ok', creds };
|
|
@@ -253,12 +198,12 @@ async function refreshIfNeeded(forceRefresh = false) {
|
|
|
253
198
|
const alreadyExpired = isExpired(creds);
|
|
254
199
|
|
|
255
200
|
// Futile-refresh short-circuit: token already expired AND no refresh token
|
|
256
|
-
// to present.
|
|
257
|
-
//
|
|
258
|
-
//
|
|
201
|
+
// to present. The `claude --version` CLI fallback is a guaranteed dead end
|
|
202
|
+
// from the same missing token, so running it on every 15 s poll only spawns
|
|
203
|
+
// a doomed child process and re-logs the
|
|
259
204
|
// same triple forever (2026-09-23 storm). Re-read once — cheap, and the ONE
|
|
260
205
|
// real recovery (`claude login`) lands here — then, if still futile, return
|
|
261
|
-
// the auth verdict WITHOUT the
|
|
206
|
+
// the auth verdict WITHOUT the CLI-fallback spawn, logging
|
|
262
207
|
// at most once per FUTILE_REFRESH_COOLDOWN_MS instead of every poll.
|
|
263
208
|
if (isRefreshFutile(creds)) {
|
|
264
209
|
const recheckCr = await readCredentials();
|
|
@@ -279,38 +224,19 @@ async function refreshIfNeeded(forceRefresh = false) {
|
|
|
279
224
|
};
|
|
280
225
|
}
|
|
281
226
|
|
|
282
|
-
//
|
|
283
|
-
const
|
|
284
|
-
appendRefreshLog({ event:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const freshCr = await readCredentials();
|
|
290
|
-
if (freshCr.kind === 'ok') {
|
|
291
|
-
appendRefreshLog({ event: 'oauth_refresh_written_ok' });
|
|
292
|
-
return { kind: 'ok', creds: freshCr.creds };
|
|
293
|
-
}
|
|
294
|
-
} catch (e) {
|
|
295
|
-
appendRefreshLog({ event: 'oauth_refresh_write_failed', error: e?.message });
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Stretch: if OAuth didn't explicitly reject the token, try `claude --version` fallback.
|
|
300
|
-
if (oauthResult.kind !== 'auth') {
|
|
301
|
-
const cliResult = await tryCliFallback();
|
|
302
|
-
appendRefreshLog({ event: cliResult.ok ? 'cli_fallback_ok' : 'cli_fallback_failed', reason: cliResult.reason ?? null });
|
|
303
|
-
if (cliResult.ok) {
|
|
304
|
-
const freshCr = await readCredentials();
|
|
305
|
-
if (freshCr.kind === 'ok' && !isExpired(freshCr.creds)) {
|
|
306
|
-
return { kind: 'ok', creds: freshCr.creds };
|
|
307
|
-
}
|
|
227
|
+
// The CLI owns the real refresh contract: `claude --version` refreshes silently.
|
|
228
|
+
const cliResult = await tryCliFallback();
|
|
229
|
+
appendRefreshLog({ event: cliResult.ok ? 'cli_fallback_ok' : 'cli_fallback_failed', reason: cliResult.reason ?? null });
|
|
230
|
+
if (cliResult.ok) {
|
|
231
|
+
const freshCr = await readCredentials();
|
|
232
|
+
if (freshCr.kind === 'ok' && !isExpired(freshCr.creds)) {
|
|
233
|
+
return { kind: 'ok', creds: freshCr.creds };
|
|
308
234
|
}
|
|
309
235
|
}
|
|
310
236
|
|
|
311
237
|
if (alreadyExpired) {
|
|
312
238
|
// Re-read from disk in case credentials were externally refreshed (e.g. via
|
|
313
|
-
// `claude login`) between our initial read and the failed
|
|
239
|
+
// `claude login`) between our initial read and the failed CLI fallback.
|
|
314
240
|
const recheckCr = await readCredentials();
|
|
315
241
|
if (recheckCr.kind === 'ok' && !isExpired(recheckCr.creds)) {
|
|
316
242
|
appendRefreshLog({ event: 'externally_refreshed_ok', recheckExpiresAt: recheckCr.creds.expiresAt ?? null });
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
const fs = require('node:fs');
|
|
42
42
|
const os = require('node:os');
|
|
43
43
|
const path = require('node:path');
|
|
44
|
-
const schedulerPaths = require('./schedulerPaths.cjs');
|
|
44
|
+
const schedulerPaths = require('./scheduler/schedulerPaths.cjs');
|
|
45
45
|
|
|
46
46
|
const OPS_DIRNAME = 'session-manager-operations';
|
|
47
47
|
const WORKTREES_MARKER = `${path.sep}.git${path.sep}worktrees${path.sep}`;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
const path = require('path');
|
|
37
37
|
const { activeIndexPath, withPathLock } = require('./epicMint.cjs');
|
|
38
|
-
const config = require('
|
|
38
|
+
const config = require('../../config.cjs');
|
|
39
39
|
const { mirrorEpicStatus } = require('./epicStatusMirror.cjs');
|
|
40
40
|
|
|
41
41
|
function hasOwn(obj, key) {
|
|
@@ -73,7 +73,7 @@ async function mergeActiveIndex(cwd, { sessions: rawMemorySessions = {}, events:
|
|
|
73
73
|
if (!cwd || typeof cwd !== 'string') throw new Error('mergeActiveIndex: cwd is required');
|
|
74
74
|
// Register this project's cwd as a write-allowed root (config.cjs's
|
|
75
75
|
// validateWrite gate) — mirrors the precedent + comment in
|
|
76
|
-
// lib/prdCreate.cjs:152-155. A chat-only Epic (headless claude -p, no
|
|
76
|
+
// lib/prd/prdCreate.cjs:152-155. A chat-only Epic (headless claude -p, no
|
|
77
77
|
// Terminal PTY ever spawned for this cwd) reaches this merge on a cold
|
|
78
78
|
// boot before pty.cjs's addAllowedRoot call has ever run for it — without
|
|
79
79
|
// this, every active-index.json write for such a project fails with
|
|
@@ -181,7 +181,7 @@ async function mergeActiveIndex(cwd, { sessions: rawMemorySessions = {}, events:
|
|
|
181
181
|
|
|
182
182
|
function registerActiveIndexMergeHandlers() {
|
|
183
183
|
const { ipcMain } = require('electron');
|
|
184
|
-
const { schemas: s, validated: v } = require('
|
|
184
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
185
185
|
ipcMain.handle(
|
|
186
186
|
'promptSessions:merge-active-index',
|
|
187
187
|
v(s.promptSessionsMergeActiveIndex, ({ cwd, sessions, events, removedIds }) =>
|
|
@@ -20,7 +20,7 @@ const path = require('node:path');
|
|
|
20
20
|
const { activeIndexPath, readActiveIndex, writeActiveIndex, withPathLock } = require('./epicMint.cjs');
|
|
21
21
|
|
|
22
22
|
function promptSessionsDir(cwd) {
|
|
23
|
-
const { opsPath } = require('
|
|
23
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
24
24
|
return opsPath(cwd, 'prompt-sessions');
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -20,36 +20,28 @@ const fs = require('node:fs');
|
|
|
20
20
|
const path = require('node:path');
|
|
21
21
|
const os = require('node:os');
|
|
22
22
|
const { spawn } = require('node:child_process');
|
|
23
|
-
const { writeJson, addAllowedRoot } = require('
|
|
24
|
-
const { cleanChildEnv, pathWithUserBins } = require('
|
|
25
|
-
const { shimPath: guardShimPath, resolveShimTarget, ensureGuardShimsOrError } = require('
|
|
26
|
-
const { resolveProjectRoot } = require('
|
|
27
|
-
const { nodeShellCommand } = require('
|
|
23
|
+
const { writeJson, addAllowedRoot } = require('../../config.cjs');
|
|
24
|
+
const { cleanChildEnv, pathWithUserBins } = require('../process/cleanEnv.cjs');
|
|
25
|
+
const { shimPath: guardShimPath, resolveShimTarget, ensureGuardShimsOrError } = require('../guardShims.cjs');
|
|
26
|
+
const { resolveProjectRoot } = require('../opsOwnership.cjs');
|
|
27
|
+
const { nodeShellCommand } = require('../appRuntime.cjs');
|
|
28
|
+
const { readJsonOrSync } = require('../util/atomicFs.cjs');
|
|
28
29
|
|
|
29
30
|
const SCHEDULER_MCP_NAME = 'session-manager-scheduler';
|
|
30
31
|
const DEV_PLUGIN_ENABLED_KEY = 'session-manager-dev@session-manager';
|
|
31
|
-
const SCHEDULER_MCP_SERVER_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'scheduler-mcp-server.cjs');
|
|
32
|
-
const PRD_WRITE_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-prd-writes.cjs');
|
|
32
|
+
const SCHEDULER_MCP_SERVER_SCRIPT = path.resolve(__dirname, '..', '..', '..', '..', 'scripts', 'scheduler-mcp-server.cjs');
|
|
33
|
+
const PRD_WRITE_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', '..', 'scripts', 'hooks', 'guard-prd-writes.cjs');
|
|
33
34
|
const PRD_WRITE_GUARD_MATCHER = 'Write|Edit|NotebookEdit';
|
|
34
|
-
const DESTRUCTIVE_GIT_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-destructive-git.cjs');
|
|
35
|
+
const DESTRUCTIVE_GIT_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', '..', 'scripts', 'hooks', 'guard-destructive-git.cjs');
|
|
35
36
|
const DESTRUCTIVE_GIT_GUARD_MATCHER = 'Bash';
|
|
36
|
-
const INLINE_IMPLEMENTATION_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-inline-implementation.cjs');
|
|
37
|
+
const INLINE_IMPLEMENTATION_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', '..', 'scripts', 'hooks', 'guard-inline-implementation.cjs');
|
|
37
38
|
const INLINE_IMPLEMENTATION_GUARD_MATCHER = 'Write|Edit|NotebookEdit';
|
|
38
|
-
const SELF_SCHEDULE_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', 'scripts', 'hooks', 'guard-self-schedule.cjs');
|
|
39
|
+
const SELF_SCHEDULE_GUARD_SCRIPT = path.resolve(__dirname, '..', '..', '..', '..', 'scripts', 'hooks', 'guard-self-schedule.cjs');
|
|
39
40
|
const SELF_SCHEDULE_GUARD_MATCHER = 'ScheduleWakeup|CronCreate|Task|Agent';
|
|
40
41
|
const LIVE_PROBE_TIMEOUT_MS = 10_000;
|
|
41
42
|
const LIVE_PROBE_TTL_MS = 60_000;
|
|
42
43
|
const REQUIRED_LIVE_TOOLS = ['scheduler_create_prd', 'session_manager_help'];
|
|
43
44
|
|
|
44
|
-
/** Read + JSON.parse a file, returning `fallback` on any read/parse failure. */
|
|
45
|
-
function readJsonSafe(absPath, fallback) {
|
|
46
|
-
try {
|
|
47
|
-
return JSON.parse(fs.readFileSync(absPath, 'utf8'));
|
|
48
|
-
} catch {
|
|
49
|
-
return fallback;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
45
|
/** Lazy (not a module-load constant) so tests can toggle packaged mode. */
|
|
54
46
|
function schedulerMcpFixCmd() {
|
|
55
47
|
const cmd = nodeShellCommand(SCHEDULER_MCP_SERVER_SCRIPT);
|
|
@@ -68,10 +60,10 @@ function schedulerMcpFixCmd() {
|
|
|
68
60
|
* which is the incident this PRD closes.
|
|
69
61
|
*/
|
|
70
62
|
function checkSchedulerMcp({ cwd, homeDir }) {
|
|
71
|
-
const userConfig =
|
|
63
|
+
const userConfig = readJsonOrSync(path.join(homeDir, '.claude.json'), null);
|
|
72
64
|
const userEntry = userConfig?.mcpServers?.[SCHEDULER_MCP_NAME];
|
|
73
65
|
|
|
74
|
-
const projectConfig =
|
|
66
|
+
const projectConfig = readJsonOrSync(path.join(cwd, '.mcp.json'), null);
|
|
75
67
|
const projectHas = !!projectConfig?.mcpServers?.[SCHEDULER_MCP_NAME];
|
|
76
68
|
|
|
77
69
|
if (userEntry) {
|
|
@@ -129,10 +121,10 @@ function checkSchedulerMcp({ cwd, homeDir }) {
|
|
|
129
121
|
* (enableAllProjectMcpServers), not something this probe decides.
|
|
130
122
|
*/
|
|
131
123
|
function checkSchedulerMcpProjectDuplicate({ cwd, homeDir }) {
|
|
132
|
-
const userConfig =
|
|
124
|
+
const userConfig = readJsonOrSync(path.join(homeDir, '.claude.json'), null);
|
|
133
125
|
const userHas = !!userConfig?.mcpServers?.[SCHEDULER_MCP_NAME];
|
|
134
126
|
|
|
135
|
-
const projectConfig =
|
|
127
|
+
const projectConfig = readJsonOrSync(path.join(cwd, '.mcp.json'), null);
|
|
136
128
|
const projectHas = !!projectConfig?.mcpServers?.[SCHEDULER_MCP_NAME];
|
|
137
129
|
|
|
138
130
|
const warn = userHas && projectHas;
|
|
@@ -289,7 +281,7 @@ async function checkSchedulerMcpLive({ cwd, homeDir, schedulerMcpCheck }) {
|
|
|
289
281
|
// executed the moment its cwd is merely probed, bypassing that approval
|
|
290
282
|
// entirely. Auto-approving project-scope servers is explicitly out of
|
|
291
283
|
// scope for this probe — see this PRD's "Out of scope".
|
|
292
|
-
const userConfig =
|
|
284
|
+
const userConfig = readJsonOrSync(path.join(homeDir, '.claude.json'), null);
|
|
293
285
|
const entry = userConfig?.mcpServers?.[SCHEDULER_MCP_NAME];
|
|
294
286
|
|
|
295
287
|
if (!entry?.command) {
|
|
@@ -312,7 +304,7 @@ async function checkSchedulerMcpLive({ cwd, homeDir, schedulerMcpCheck }) {
|
|
|
312
304
|
}
|
|
313
305
|
|
|
314
306
|
function checkDevPlugin({ homeDir }) {
|
|
315
|
-
const settings =
|
|
307
|
+
const settings = readJsonOrSync(path.join(homeDir, '.claude', 'settings.json'), null);
|
|
316
308
|
const ok = settings?.enabledPlugins?.[DEV_PLUGIN_ENABLED_KEY] === true;
|
|
317
309
|
|
|
318
310
|
return {
|
|
@@ -444,7 +436,7 @@ const GUARD_DEFS = {
|
|
|
444
436
|
* while reporting green" failure mode, one hop downstream of the hook command.
|
|
445
437
|
*/
|
|
446
438
|
function checkGuard(def, { cwd, homeDir = os.homedir() }) {
|
|
447
|
-
const settings =
|
|
439
|
+
const settings = readJsonOrSync(path.join(cwd, '.claude', 'settings.json'), null);
|
|
448
440
|
const preToolUse = Array.isArray(settings?.hooks?.PreToolUse) ? settings.hooks.PreToolUse : [];
|
|
449
441
|
|
|
450
442
|
let mentioned = false;
|
|
@@ -536,7 +528,7 @@ async function installGuard(def, { cwd, homeDir = os.homedir(), skipShimEnsure =
|
|
|
536
528
|
// documents for PromptSession archive writes. `cwd` here IS a project root.
|
|
537
529
|
addAllowedRoot(cwd);
|
|
538
530
|
|
|
539
|
-
const existing = fs.existsSync(settingsPath) ?
|
|
531
|
+
const existing = fs.existsSync(settingsPath) ? readJsonOrSync(settingsPath, undefined) : {};
|
|
540
532
|
if (existing === undefined) {
|
|
541
533
|
// Unparseable settings — refuse rather than silently discarding whatever
|
|
542
534
|
// the human has in there.
|
|
@@ -629,7 +621,7 @@ async function installSelfScheduleGuard({ cwd, homeDir = os.homedir(), skipShimE
|
|
|
629
621
|
|
|
630
622
|
/**
|
|
631
623
|
* Runs all eight delegation-readiness checks for `cwd`. Every filesystem read
|
|
632
|
-
* is wrapped (
|
|
624
|
+
* is wrapped (readJsonOrSync / try-catch) so a missing or unparseable file
|
|
633
625
|
* yields ok:false with a detail, never a thrown exception. Async because
|
|
634
626
|
* scheduler-mcp-live genuinely spawns a process and waits on it (bounded by
|
|
635
627
|
* LIVE_PROBE_TIMEOUT_MS, and memoized per registration signature so repeat
|
|
@@ -673,7 +665,7 @@ function logAutoInstallEvent({ cwd, guard, action, error }) {
|
|
|
673
665
|
// A no-op outcome is not an event worth an error-log row (24 rows/3 days of boot noise).
|
|
674
666
|
if (action === 'already-installed') return;
|
|
675
667
|
try {
|
|
676
|
-
const opsErrorLog = require('
|
|
668
|
+
const opsErrorLog = require('../telemetry/opsErrorLog.cjs');
|
|
677
669
|
opsErrorLog.appendError({
|
|
678
670
|
cwd,
|
|
679
671
|
scope: 'delegationReadiness',
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* scheduler.cjs.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const { readTurns } = require('
|
|
16
|
+
const { readTurns } = require('../../promptSessionTranscript.cjs');
|
|
17
17
|
const { readActiveIndex } = require('./epicMint.cjs');
|
|
18
18
|
|
|
19
19
|
const DEFAULT_MAX_CHARS = 4000;
|
|
@@ -28,7 +28,7 @@ const fs = require('node:fs');
|
|
|
28
28
|
const os = require('node:os');
|
|
29
29
|
const path = require('node:path');
|
|
30
30
|
const { resolveEpicTranscriptPath } = require('./epicTranscriptPath.cjs');
|
|
31
|
-
const { classifyLine } = require('
|
|
31
|
+
const { classifyLine } = require('../classifyTranscriptLine.cjs');
|
|
32
32
|
|
|
33
33
|
// Same cap transcripts.cjs's readDelta uses for a single pass — bounds
|
|
34
34
|
// memory/time on a very large transcript instead of reading it whole.
|
|
@@ -40,7 +40,7 @@ const APPLICATION_SOURCE_PREFIXES = ['src/', 'scripts/', 'plugins/', 'bin/'];
|
|
|
40
40
|
function countPrdsQueued(cwd, epicId, deps = {}) {
|
|
41
41
|
const readdirSync = deps.readdirSync || fs.readdirSync;
|
|
42
42
|
try {
|
|
43
|
-
const { opsPath } = require('
|
|
43
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
44
44
|
const dir = opsPath(cwd, 'scheduler', 'epics', epicId, 'prds');
|
|
45
45
|
return readdirSync(dir).filter((name) => name.endsWith('.md')).length;
|
|
46
46
|
} catch {
|