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
|
@@ -31,20 +31,20 @@ const fs = require('node:fs');
|
|
|
31
31
|
const os = require('node:os');
|
|
32
32
|
const path = require('node:path');
|
|
33
33
|
const crypto = require('node:crypto');
|
|
34
|
-
const { resolveEpicPrdWriteDir } = require('
|
|
35
|
-
const { assertOpsWrite } = require('
|
|
36
|
-
const { appendAuditEvent } = require('
|
|
34
|
+
const { resolveEpicPrdWriteDir } = require('../prd/prdLocations.cjs');
|
|
35
|
+
const { assertOpsWrite } = require('../opsOwnership.cjs');
|
|
36
|
+
const { appendAuditEvent } = require('../telemetry/auditLog.cjs');
|
|
37
37
|
const { mirrorEpicStatus, removeEpicMirror } = require('./epicStatusMirror.cjs');
|
|
38
|
-
const atomicFs = require('
|
|
39
|
-
const telemetryCounters = require('
|
|
38
|
+
const atomicFs = require('../util/atomicFs.cjs');
|
|
39
|
+
const telemetryCounters = require('../telemetry/telemetryCounters.cjs');
|
|
40
40
|
// Required as the module object (not destructured) so a test can
|
|
41
41
|
// monkeypatch promptSessionSchema.assertValidPromptSession in place to
|
|
42
42
|
// simulate a corrupted construction — the real construction below is
|
|
43
43
|
// hardcoded and always valid.
|
|
44
|
-
const promptSessionSchema = require('
|
|
44
|
+
const promptSessionSchema = require('../promptSessionSchema.cjs');
|
|
45
45
|
|
|
46
46
|
// The one token that unlocks ensureEpic's mint branch. Held by
|
|
47
|
-
// lib/promptSessionsCreateEpic.cjs (the New Epic card's IPC handler) and
|
|
47
|
+
// lib/epic/promptSessionsCreateEpic.cjs (the New Epic card's IPC handler) and
|
|
48
48
|
// nothing else — grep for it before adding a second holder, that is a
|
|
49
49
|
// deliberate domain-model change, not a convenience.
|
|
50
50
|
const MINT_AUTHORITY_NEW_EPIC_UI = 'new-epic-ui';
|
|
@@ -56,7 +56,7 @@ const MINT_AUTHORITY_NEW_EPIC_UI = 'new-epic-ui';
|
|
|
56
56
|
// the `feedback/` folder retired (2026-08-02) and the scheduler correctly
|
|
57
57
|
// locked down to join-only, an agent working in Project-A had NO way to hand
|
|
58
58
|
// a finding to Project-B — the finding either died in a transcript or the
|
|
59
|
-
// human had to relay it by hand. `lib/crossProjectFeedback.cjs` restores that
|
|
59
|
+
// human had to relay it by hand. `lib/feedback-remote/crossProjectFeedback.cjs` restores that
|
|
60
60
|
// conduit, and it is the sole holder of this token.
|
|
61
61
|
//
|
|
62
62
|
// What makes it safe is the part of the SINGLE-CREATOR LAW that actually
|
|
@@ -79,7 +79,7 @@ const MINT_AUTHORITIES = Object.freeze([
|
|
|
79
79
|
function activeIndexPath(cwd) {
|
|
80
80
|
// Lazy: opsOwnership → ephemeralCwd → activeSessions; this module is
|
|
81
81
|
// required early by several of those neighbours.
|
|
82
|
-
const { opsPath } = require('
|
|
82
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
83
83
|
return opsPath(cwd, 'prompt-sessions', 'active-index.json');
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -93,7 +93,7 @@ function readActiveIndex(cwd) {
|
|
|
93
93
|
// doesn't resurrect completed/deleted Epics on its own), but every
|
|
94
94
|
// caller here does read-modify-write on the object this returns, so
|
|
95
95
|
// dropping the field would silently erase the removal tombstones
|
|
96
|
-
// lib/activeIndexMerge.cjs's mergeActiveIndex records the next time any
|
|
96
|
+
// lib/epic/activeIndexMerge.cjs's mergeActiveIndex records the next time any
|
|
97
97
|
// of ensureEpic/appendPrdCreatedEvent/removeEpic writes this file.
|
|
98
98
|
tombstones: parsed && typeof parsed.tombstones === 'object' && parsed.tombstones ? parsed.tombstones : {},
|
|
99
99
|
};
|
|
@@ -450,7 +450,7 @@ module.exports = {
|
|
|
450
450
|
writeActiveIndex,
|
|
451
451
|
personaFileExists,
|
|
452
452
|
resolvePersonaPaths,
|
|
453
|
-
// Exported so lib/activeIndexMerge.cjs's renderer-facing merge IPC handler
|
|
453
|
+
// Exported so lib/epic/activeIndexMerge.cjs's renderer-facing merge IPC handler
|
|
454
454
|
// serializes through the SAME lock instance as ensureEpic/
|
|
455
455
|
// appendPrdCreatedEvent (module-level Map, shared via Node's require
|
|
456
456
|
// cache) — one lock per active-index.json path across both callers, not
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
const fs = require('node:fs');
|
|
28
28
|
const os = require('node:os');
|
|
29
29
|
const path = require('node:path');
|
|
30
|
-
const { encodeCwd } = require('
|
|
31
|
-
const { projectRootOf } = require('
|
|
30
|
+
const { encodeCwd } = require('../util/encodeCwd.cjs');
|
|
31
|
+
const { projectRootOf } = require('../activeSessions.cjs');
|
|
32
32
|
const { readActiveIndex } = require('./epicMint.cjs');
|
|
33
33
|
const { resolveEpicSpawnCwd } = require('./epicSpawnCwd.cjs');
|
|
34
34
|
const { resolveEpicTranscriptPath } = require('./epicTranscriptPath.cjs');
|
|
@@ -56,7 +56,7 @@ function findEpic(cwd, claudeSessionId, deps) {
|
|
|
56
56
|
}
|
|
57
57
|
} catch { /* unreadable index → try archives */ }
|
|
58
58
|
try {
|
|
59
|
-
const { opsPath } = require('
|
|
59
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
60
60
|
const dir = opsPath(cwd, 'prompt-sessions');
|
|
61
61
|
for (const name of fs.readdirSync(dir)) {
|
|
62
62
|
if (!name.endsWith('.json') || name === 'active-index.json') continue;
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
const fs = require('node:fs');
|
|
29
|
-
const { assertOpsWrite, opsPath } = require('
|
|
30
|
-
const atomicFs = require('
|
|
29
|
+
const { assertOpsWrite, opsPath } = require('../opsOwnership.cjs');
|
|
30
|
+
const atomicFs = require('../util/atomicFs.cjs');
|
|
31
31
|
|
|
32
32
|
function epicMirrorPath(cwd, epicId) {
|
|
33
33
|
return opsPath(cwd, 'prompt-sessions', `${epicId}.json`);
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
const fs = require('node:fs');
|
|
18
18
|
const os = require('node:os');
|
|
19
19
|
const path = require('node:path');
|
|
20
|
-
const { encodeCwd } = require('
|
|
20
|
+
const { encodeCwd } = require('../util/encodeCwd.cjs');
|
|
21
21
|
const { readActiveIndex } = require('./epicMint.cjs');
|
|
22
|
-
const { opsPath } = require('
|
|
22
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
23
23
|
const { resolveEpicTranscriptPath } = require('./epicTranscriptPath.cjs');
|
|
24
24
|
|
|
25
25
|
/** [epicId, session] pairs: active-index rows plus archived per-Epic `<id>.json` records. */
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
const fs = require('node:fs');
|
|
26
26
|
const os = require('node:os');
|
|
27
27
|
const path = require('node:path');
|
|
28
|
-
const { encodeCwd } = require('
|
|
28
|
+
const { encodeCwd } = require('../util/encodeCwd.cjs');
|
|
29
29
|
const { readActiveIndex } = require('./epicMint.cjs');
|
|
30
30
|
const { resolveEpicSpawnCwd } = require('./epicSpawnCwd.cjs');
|
|
31
31
|
|
|
@@ -53,7 +53,7 @@ function statKey(statSync, p) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function opsFile(cwd, ...segments) {
|
|
56
|
-
const { opsPath } = require('
|
|
56
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
57
57
|
return opsPath(cwd, 'prompt-sessions', ...segments);
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* VERIFIED or REFUTED with evidence. The job's self-reported status is an
|
|
16
16
|
* input to that check, never a substitute for it.
|
|
17
17
|
*
|
|
18
|
-
* Shape mirrors lib/dodDrainHook.cjs: fire-and-forget (never throws to the
|
|
18
|
+
* Shape mirrors lib/scheduler/dodDrainHook.cjs: fire-and-forget (never throws to the
|
|
19
19
|
* caller — errors are logged), kill-switched, idempotent.
|
|
20
20
|
*
|
|
21
21
|
* Kill-switch: SM_EPIC_VALIDATION_DISABLE=1 (mirrors the SM_DOD_DISABLE
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* SESSION SLOT POOL: this module spawns NOTHING. The prompt is enqueued via
|
|
25
25
|
* chatRunner.cjs's enqueueExternalPrompt → `chat:external-send` → the
|
|
26
26
|
* renderer's chat queue → chatRunner's pump, which acquires a slot from the
|
|
27
|
-
* machine-wide lib/sessionSlots.cjs pool (chatRunner.cjs pump()) before any
|
|
27
|
+
* machine-wide lib/scheduler/sessionSlots.cjs pool (chatRunner.cjs pump()) before any
|
|
28
28
|
* `claude -p` process starts. So the validation session cannot start outside
|
|
29
29
|
* the pool — if the pool is exhausted the prompt simply waits in the chat
|
|
30
30
|
* lane's FIFO, it never fans out into an extra parallel process (the
|
|
@@ -62,7 +62,7 @@ function pairKey(epicId, prdSlug) {
|
|
|
62
62
|
*/
|
|
63
63
|
function defaultReadActiveIndex(cwd) {
|
|
64
64
|
try {
|
|
65
|
-
const { opsPath } = require('
|
|
65
|
+
const { opsPath } = require('../opsOwnership.cjs');
|
|
66
66
|
const p = opsPath(cwd, 'prompt-sessions', 'active-index.json');
|
|
67
67
|
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
68
68
|
} catch {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
* them from the command line.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
const { integrateEpicBranch, cleanupEpicWorktree } = require('
|
|
29
|
-
const { validatePath } = require('
|
|
28
|
+
const { integrateEpicBranch, cleanupEpicWorktree } = require('../git/gitWorktree.cjs');
|
|
29
|
+
const { validatePath } = require('../../config.cjs');
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* mergeEpicToMainViaIpc(cwd, epicId, branch, dir) → Promise<MergeOutcome>
|
|
@@ -54,7 +54,7 @@ async function mergeEpicToMainViaIpc(cwd, epicId, branch, dir, carriedPaths) {
|
|
|
54
54
|
|
|
55
55
|
function registerEpicWorktreeMergeHandlers() {
|
|
56
56
|
const { ipcMain } = require('electron');
|
|
57
|
-
const { schemas: s, validated: v } = require('
|
|
57
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
58
58
|
ipcMain.handle(
|
|
59
59
|
'promptSessions:merge-to-main',
|
|
60
60
|
v(s.promptSessionsMergeToMain, ({ cwd, epicId, branch, dir, carriedPaths }) => mergeEpicToMainViaIpc(cwd, epicId, branch, dir, carriedPaths)),
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* since this is likewise reachable from the renderer over IPC.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
const { createEpicWorktree } = require('
|
|
28
|
-
const { validatePath } = require('
|
|
27
|
+
const { createEpicWorktree } = require('../git/gitWorktree.cjs');
|
|
28
|
+
const { validatePath } = require('../../config.cjs');
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* createEpicWorktreeViaIpc(cwd, epicId) → Promise<EpicWorktree | null>
|
|
@@ -59,7 +59,7 @@ async function createEpicWorktreeViaIpc(cwd, epicId) {
|
|
|
59
59
|
|
|
60
60
|
function registerEpicWorktreeMintHandlers() {
|
|
61
61
|
const { ipcMain } = require('electron');
|
|
62
|
-
const { schemas: s, validated: v } = require('
|
|
62
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
63
63
|
ipcMain.handle(
|
|
64
64
|
'promptSessions:create-worktree',
|
|
65
65
|
v(s.promptSessionsCreateWorktree, ({ cwd, epicId }) => createEpicWorktreeViaIpc(cwd, epicId)),
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
const fs = require('node:fs');
|
|
36
36
|
const path = require('node:path');
|
|
37
37
|
const os = require('node:os');
|
|
38
|
-
const { assertOpsWrite, opsPath } = require('
|
|
39
|
-
const atomicFs = require('
|
|
38
|
+
const { assertOpsWrite, opsPath } = require('../opsOwnership.cjs');
|
|
39
|
+
const atomicFs = require('../util/atomicFs.cjs');
|
|
40
40
|
|
|
41
41
|
// The old machine-wide map. Read-only from here on (migration source only) —
|
|
42
42
|
// never written again, and deliberately never deleted so unmigrated projects
|
|
@@ -116,8 +116,8 @@ function setEpicWorktreeDisabledForProject(cwd, disabled, writer = 'epics') {
|
|
|
116
116
|
|
|
117
117
|
function registerEpicWorktreeProjectConfigHandlers() {
|
|
118
118
|
const { ipcMain } = require('electron');
|
|
119
|
-
const { schemas: s, validated: v } = require('
|
|
120
|
-
const { validatePath } = require('
|
|
119
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
120
|
+
const { validatePath } = require('../../config.cjs');
|
|
121
121
|
ipcMain.handle(
|
|
122
122
|
'promptSessions:get-worktree-disabled',
|
|
123
123
|
v(s.promptSessionsGetWorktreeDisabled, ({ cwd }) => {
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Step 1 of a two-PRD chain (PRD 953 here; PRD 954 routes createPromptSession
|
|
9
9
|
* through it): purely additive today — nothing calls this handler yet. Kept
|
|
10
|
-
* as a sibling module (mirrors lib/activeIndexMerge.cjs, which does the same
|
|
10
|
+
* as a sibling module (mirrors lib/epic/activeIndexMerge.cjs, which does the same
|
|
11
11
|
* "own file, own register*Handlers export, wired from index.cjs" shape for
|
|
12
12
|
* the neighboring active-index merge IPC) rather than growing epicMint.cjs
|
|
13
13
|
* itself, since this is IPC-registration plumbing, not Epic-minting logic.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const { ensureEpic, readActiveIndex, MINT_AUTHORITY_NEW_EPIC_UI } = require('./epicMint.cjs');
|
|
17
|
-
const { validatePath } = require('
|
|
17
|
+
const { validatePath } = require('../../config.cjs');
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* createEpicViaIpc(cwd, { goalText, tag?, agentType?, source? }) → Promise<{ epicId, session }>
|
|
@@ -38,7 +38,7 @@ const { validatePath } = require('../config.cjs');
|
|
|
38
38
|
* + every cwd a TAB has opened) closes the gap so this handler can't be used
|
|
39
39
|
* to make main write session-manager-operations/ into an arbitrary
|
|
40
40
|
* filesystem location — the same boundary every other renderer-facing path
|
|
41
|
-
* IPC (config:read-json/write-json, lib/activeIndexMerge.cjs's own merge) is
|
|
41
|
+
* IPC (config:read-json/write-json, lib/epic/activeIndexMerge.cjs's own merge) is
|
|
42
42
|
* already required to pass through.
|
|
43
43
|
*/
|
|
44
44
|
async function createEpicViaIpc(cwd, { goalText, tag, agentType, model, effort, source, openingPrompt, sections } = {}) {
|
|
@@ -61,7 +61,7 @@ async function createEpicViaIpc(cwd, { goalText, tag, agentType, model, effort,
|
|
|
61
61
|
|
|
62
62
|
function registerPromptSessionsCreateEpicHandlers() {
|
|
63
63
|
const { ipcMain } = require('electron');
|
|
64
|
-
const { schemas: s, validated: v } = require('
|
|
64
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
65
65
|
ipcMain.handle(
|
|
66
66
|
'promptSessions:create-epic',
|
|
67
67
|
v(s.promptSessionsCreateEpic, ({ cwd, goalText, tag, agentType, model, effort, source, openingPrompt, sections }) =>
|
|
@@ -33,7 +33,19 @@
|
|
|
33
33
|
* feedback Epic is born 'proposed' like every other Epic (epicMint.cjs's
|
|
34
34
|
* BORN-PROPOSED check applies to this mint authority verbatim), so the human
|
|
35
35
|
* in the RECEIVING project is still the one who decides whether a single token
|
|
36
|
-
* gets spent. An agent can ask; it cannot start.
|
|
36
|
+
* gets spent. An agent can ask; it cannot start on its own say-so.
|
|
37
|
+
*
|
|
38
|
+
* The one exception is a VERIFIED HUMAN REQUEST. When the human themselves
|
|
39
|
+
* asked, in chat, for work in another project, making them re-confirm in the
|
|
40
|
+
* receiving project is pure friction. So `autoStart: true` plus a
|
|
41
|
+
* `humanRequestQuote` is honored only when main can check the quote against
|
|
42
|
+
* humanPromptLedger (prompts chat:run recorded with human origin) for the
|
|
43
|
+
* originating chat session — `input.originClaudeSessionId`, taken from the MCP
|
|
44
|
+
* server's env, set only for interactive chat runs, never for scheduler jobs —
|
|
45
|
+
* AND that human prompt names the target project. Even then the Epic is still
|
|
46
|
+
* minted 'proposed'; it is only stamped `source.autoApprove` and the renderer
|
|
47
|
+
* is told to approve-and-start it through its normal approveProposed path.
|
|
48
|
+
* Anything unverifiable degrades to the ordinary proposal.
|
|
37
49
|
*
|
|
38
50
|
* Guards, all fail-closed:
|
|
39
51
|
* - both cwds go through config.cjs's validatePath (allowedRoots = home)
|
|
@@ -57,16 +69,16 @@ const fsp = require('node:fs/promises');
|
|
|
57
69
|
const os = require('node:os');
|
|
58
70
|
const path = require('node:path');
|
|
59
71
|
|
|
60
|
-
const config = require('
|
|
72
|
+
const config = require('../../config.cjs');
|
|
61
73
|
const { readBody, sendJson } = require('./localAdminHttp.cjs');
|
|
62
74
|
const {
|
|
63
75
|
ensureEpic,
|
|
64
76
|
readActiveIndex,
|
|
65
77
|
MINT_AUTHORITY_CROSS_PROJECT_FEEDBACK,
|
|
66
|
-
} = require('
|
|
67
|
-
const { appendAuditEvent } = require('
|
|
68
|
-
const { OPS_ROOT_DIR } = require('
|
|
69
|
-
const { resolveProjectContext } = require('
|
|
78
|
+
} = require('../epic/epicMint.cjs');
|
|
79
|
+
const { appendAuditEvent } = require('../telemetry/auditLog.cjs');
|
|
80
|
+
const { OPS_ROOT_DIR } = require('../opsOwnership.cjs');
|
|
81
|
+
const { resolveProjectContext } = require('../projectRootResolve.cjs');
|
|
70
82
|
|
|
71
83
|
/** Only these three Epic tags make sense for an inbound report — they are
|
|
72
84
|
* exactly the tags that route through /develop (tagLibrary.ts). 'build' and
|
|
@@ -90,6 +102,7 @@ const MAX_SERIES_KEY_CHARS = 60;
|
|
|
90
102
|
const MAX_SERIES_TITLE_CHARS = 120;
|
|
91
103
|
const MAX_SERIES_TOTAL = 50;
|
|
92
104
|
const MAX_ORIGIN_ASK_CHARS = 300;
|
|
105
|
+
const MAX_HUMAN_QUOTE_CHARS = 2000;
|
|
93
106
|
const KEBAB_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
94
107
|
|
|
95
108
|
/** Bound on how many `~/.claude/projects/` folders listFeedbackTargets will
|
|
@@ -349,6 +362,18 @@ function validateFeedbackInput(input = {}) {
|
|
|
349
362
|
series = { key, title: stitle, index: sr.index, total: sr.total };
|
|
350
363
|
}
|
|
351
364
|
|
|
365
|
+
if (input.autoStart !== undefined && input.autoStart !== null && typeof input.autoStart !== 'boolean') {
|
|
366
|
+
return bad(400, 'autoStart must be a boolean');
|
|
367
|
+
}
|
|
368
|
+
let humanRequestQuote = '';
|
|
369
|
+
if (input.humanRequestQuote !== undefined && input.humanRequestQuote !== null) {
|
|
370
|
+
if (typeof input.humanRequestQuote !== 'string') return bad(400, 'humanRequestQuote must be a string');
|
|
371
|
+
humanRequestQuote = input.humanRequestQuote.trim();
|
|
372
|
+
if (humanRequestQuote.length > MAX_HUMAN_QUOTE_CHARS) {
|
|
373
|
+
return bad(400, `humanRequestQuote is ${humanRequestQuote.length} chars; cap is ${MAX_HUMAN_QUOTE_CHARS}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
352
377
|
const referencePaths = Array.isArray(input.referencePaths) ? input.referencePaths : [];
|
|
353
378
|
if (referencePaths.length > MAX_REFERENCES) {
|
|
354
379
|
return bad(400, `too many referencePaths (${referencePaths.length}); cap is ${MAX_REFERENCES}`);
|
|
@@ -410,6 +435,8 @@ function validateFeedbackInput(input = {}) {
|
|
|
410
435
|
acceptanceCriteria: lists.acceptanceCriteria,
|
|
411
436
|
outOfScope: lists.outOfScope,
|
|
412
437
|
series,
|
|
438
|
+
autoStart: input.autoStart === true,
|
|
439
|
+
humanRequestQuote,
|
|
413
440
|
referencePaths: referencePaths.map((p) => String(p)),
|
|
414
441
|
fromEpicId: input.fromEpicId ? String(input.fromEpicId) : null,
|
|
415
442
|
agentType: input.agentType ? String(input.agentType) : DEFAULT_FEEDBACK_AGENT,
|
|
@@ -418,6 +445,44 @@ function validateFeedbackInput(input = {}) {
|
|
|
418
445
|
};
|
|
419
446
|
}
|
|
420
447
|
|
|
448
|
+
/** Tell every renderer window to approve-and-start a granted auto-start Epic.
|
|
449
|
+
* Electron is required lazily so unit tests never need it. */
|
|
450
|
+
function defaultNotifyRenderer(payload) {
|
|
451
|
+
try {
|
|
452
|
+
const { BrowserWindow } = require('electron');
|
|
453
|
+
for (const win of BrowserWindow.getAllWindows()) {
|
|
454
|
+
try {
|
|
455
|
+
win.webContents.send('promptSessions:inbound-auto-approve', payload);
|
|
456
|
+
} catch { /* window going away */ }
|
|
457
|
+
}
|
|
458
|
+
} catch { /* not running under Electron */ }
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* verifyAutoStart(v, originClaudeSessionId) → { granted: true, quote } | { granted: false, reason }
|
|
463
|
+
*
|
|
464
|
+
* Every check is fail-closed. The session identity is ONLY the caller-supplied
|
|
465
|
+
* originClaudeSessionId (MCP env), never a field an agent can pick freely.
|
|
466
|
+
*/
|
|
467
|
+
function verifyAutoStart(v, originClaudeSessionId) {
|
|
468
|
+
if (!v.autoStart) return { granted: false, reason: 'autoStart was not requested' };
|
|
469
|
+
if (!v.humanRequestQuote) return { granted: false, reason: 'no humanRequestQuote was given' };
|
|
470
|
+
if (!originClaudeSessionId) {
|
|
471
|
+
return { granted: false, reason: 'no originClaudeSessionId — only interactive chat sessions can auto-start' };
|
|
472
|
+
}
|
|
473
|
+
const { findHumanPromptContaining } = require('./humanPromptLedger.cjs');
|
|
474
|
+
const found = findHumanPromptContaining(originClaudeSessionId, v.humanRequestQuote);
|
|
475
|
+
if (!found) {
|
|
476
|
+
return { granted: false, reason: 'humanRequestQuote was not found in a prompt the human typed in this chat session' };
|
|
477
|
+
}
|
|
478
|
+
const prompt = found.text.toLowerCase();
|
|
479
|
+
const base = path.basename(v.toCwd).toLowerCase();
|
|
480
|
+
if (!(base && prompt.includes(base)) && !prompt.includes(v.toCwd.toLowerCase())) {
|
|
481
|
+
return { granted: false, reason: `the human's prompt does not name the receiving project (${path.basename(v.toCwd)})` };
|
|
482
|
+
}
|
|
483
|
+
return { granted: true, quote: v.humanRequestQuote };
|
|
484
|
+
}
|
|
485
|
+
|
|
421
486
|
/**
|
|
422
487
|
* openFeedbackSession(input, deps?) → { ok, status?, error?, epicId, toCwd, ... }
|
|
423
488
|
*
|
|
@@ -427,8 +492,8 @@ function validateFeedbackInput(input = {}) {
|
|
|
427
492
|
* best-effort: a failure there never invalidates a delivered proposal, it just
|
|
428
493
|
* reports `receiptOnOriginEpic: false`.
|
|
429
494
|
*
|
|
430
|
-
* `deps` exists so tests can inject the
|
|
431
|
-
* without an Electron/main-process boot.
|
|
495
|
+
* `deps` exists so tests can inject the side-effecting collaborators
|
|
496
|
+
* (ensureEpic, appendResponseEventIfKnown, notifyRenderer) without an Electron/main-process boot.
|
|
432
497
|
*/
|
|
433
498
|
async function openFeedbackSession(input, deps = {}) {
|
|
434
499
|
const mint = deps.ensureEpic || ensureEpic;
|
|
@@ -437,19 +502,28 @@ async function openFeedbackSession(input, deps = {}) {
|
|
|
437
502
|
// Required lazily: promptSessionEvents.cjs pulls in config.cjs's watcher
|
|
438
503
|
// machinery, and this module is also required from unit tests that never
|
|
439
504
|
// boot the main process.
|
|
440
|
-
|| ((...args) => require('
|
|
505
|
+
|| ((...args) => require('../../promptSessionEvents.cjs').appendResponseEventIfKnown(...args));
|
|
506
|
+
|
|
507
|
+
const notify = deps.notifyRenderer || defaultNotifyRenderer;
|
|
441
508
|
|
|
442
509
|
const checked = validateFeedbackInput(input);
|
|
443
510
|
if (!checked.ok) return checked;
|
|
444
511
|
const v = checked.value;
|
|
445
512
|
|
|
513
|
+
const originClaudeSessionId =
|
|
514
|
+
typeof input.originClaudeSessionId === 'string' && input.originClaudeSessionId
|
|
515
|
+
? input.originClaudeSessionId
|
|
516
|
+
: null;
|
|
517
|
+
const auto = verifyAutoStart(v, originClaudeSessionId);
|
|
518
|
+
const verifiedAt = new Date().toISOString();
|
|
519
|
+
|
|
446
520
|
// The MCP client can't know its own Epic id — it only inherits the claude
|
|
447
521
|
// session id chatRunner.cjs stamps on the `claude -p` child. Resolve it
|
|
448
522
|
// through prdCreate.cjs's existing resolver rather than a second copy of
|
|
449
523
|
// the same lookup (required lazily: prdCreate pulls in ipcSchemas/config).
|
|
450
524
|
if (!v.fromEpicId && input.originClaudeSessionId) {
|
|
451
525
|
try {
|
|
452
|
-
const { resolveSourcePromptIdFromClaudeSession } = require('
|
|
526
|
+
const { resolveSourcePromptIdFromClaudeSession } = require('../prd/prdCreate.cjs');
|
|
453
527
|
v.fromEpicId = resolveSourcePromptIdFromClaudeSession(v.fromCwd, String(input.originClaudeSessionId)) || null;
|
|
454
528
|
} catch { /* unresolvable — the proposal still delivers, just without a receipt */ }
|
|
455
529
|
}
|
|
@@ -488,6 +562,16 @@ async function openFeedbackSession(input, deps = {}) {
|
|
|
488
562
|
producer: 'cross-project-feedback',
|
|
489
563
|
fromCwd: v.fromCwd,
|
|
490
564
|
...(v.fromEpicId ? { fromEpicId: v.fromEpicId } : {}),
|
|
565
|
+
...(auto.granted
|
|
566
|
+
? {
|
|
567
|
+
autoApprove: {
|
|
568
|
+
requestedBy: 'human',
|
|
569
|
+
quote: auto.quote,
|
|
570
|
+
verifiedAt,
|
|
571
|
+
fromClaudeSessionId: originClaudeSessionId,
|
|
572
|
+
},
|
|
573
|
+
}
|
|
574
|
+
: {}),
|
|
491
575
|
proposal: {
|
|
492
576
|
motivation: v.motivation,
|
|
493
577
|
originAsk,
|
|
@@ -511,8 +595,16 @@ async function openFeedbackSession(input, deps = {}) {
|
|
|
511
595
|
tag: v.tag,
|
|
512
596
|
title: v.title,
|
|
513
597
|
series: v.series,
|
|
598
|
+
autoStartGranted: auto.granted,
|
|
599
|
+
autoStartReason: auto.granted ? 'verified human request' : auto.reason,
|
|
514
600
|
});
|
|
515
601
|
|
|
602
|
+
if (auto.granted) {
|
|
603
|
+
try {
|
|
604
|
+
notify({ cwd: v.toCwd, epicId: minted.epicId });
|
|
605
|
+
} catch { /* the Epic is delivered either way; a human can still approve it */ }
|
|
606
|
+
}
|
|
607
|
+
|
|
516
608
|
let receiptOnOriginEpic = false;
|
|
517
609
|
if (v.fromEpicId) {
|
|
518
610
|
try {
|
|
@@ -522,7 +614,9 @@ async function openFeedbackSession(input, deps = {}) {
|
|
|
522
614
|
`Feedback delivered to ${v.toCwd} as a proposed session (${minted.epicId}): "${v.title}"`
|
|
523
615
|
+ (v.series ? ` [${seriesLine(v.series)}]` : '')
|
|
524
616
|
+ '. '
|
|
525
|
-
+
|
|
617
|
+
+ (auto.granted
|
|
618
|
+
? 'It was auto-approved at the human\'s explicit request and is starting in that project.'
|
|
619
|
+
: 'It will not run until a human in that project approves it.'),
|
|
526
620
|
);
|
|
527
621
|
} catch {
|
|
528
622
|
receiptOnOriginEpic = false;
|
|
@@ -535,14 +629,18 @@ async function openFeedbackSession(input, deps = {}) {
|
|
|
535
629
|
toCwd: v.toCwd,
|
|
536
630
|
fromCwd: v.fromCwd,
|
|
537
631
|
tag: v.tag,
|
|
538
|
-
status: 'proposed',
|
|
632
|
+
status: auto.granted ? 'auto-approved' : 'proposed',
|
|
633
|
+
...(v.autoStart ? { autoStart: auto.granted ? { granted: true } : { granted: false, reason: auto.reason } } : {}),
|
|
539
634
|
receiptOnOriginEpic,
|
|
540
635
|
// Say plainly what did NOT happen, same posture as create-prd's
|
|
541
636
|
// `enqueued: false` — never let a caller report this as "work started".
|
|
542
|
-
note:
|
|
543
|
-
'
|
|
544
|
-
|
|
545
|
-
|
|
637
|
+
note: auto.granted
|
|
638
|
+
? 'Auto-approved at the human\'s explicit request (verified against their chat prompt): the session '
|
|
639
|
+
+ 'is starting in the receiving project. There is no callback: if you need an answer, ask the human '
|
|
640
|
+
+ 'to follow up.'
|
|
641
|
+
: 'Delivered as a PROPOSED session in the receiving project\'s Sessions queue. Nothing runs and no '
|
|
642
|
+
+ 'tokens are spent until a human in that project presses Approve & start. There is no callback: '
|
|
643
|
+
+ 'if you need an answer, ask the human to follow up.',
|
|
546
644
|
goalText,
|
|
547
645
|
};
|
|
548
646
|
}
|
package/src/main/lib/{customerFeedbackClient.cjs → feedback-remote/customerFeedbackClient.cjs}
RENAMED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
const path = require('node:path');
|
|
16
16
|
const fsp = require('node:fs/promises');
|
|
17
|
-
const atomicFs = require('
|
|
18
|
-
const schedulerPaths = require('
|
|
17
|
+
const atomicFs = require('../util/atomicFs.cjs');
|
|
18
|
+
const schedulerPaths = require('../scheduler/schedulerPaths.cjs');
|
|
19
19
|
|
|
20
20
|
const FEEDBACK_SLUG = 'session-manager';
|
|
21
21
|
const TAGS = /** @type {const} */ (['bug', 'feature', 'discussion']);
|
|
@@ -77,7 +77,7 @@ function defaultVersion() {
|
|
|
77
77
|
if (electron && electron.app && typeof electron.app.getVersion === 'function') return electron.app.getVersion();
|
|
78
78
|
} catch { /* not running under Electron */ }
|
|
79
79
|
try {
|
|
80
|
-
return String(require('
|
|
80
|
+
return String(require('../../../../package.json').version || 'unknown');
|
|
81
81
|
} catch {
|
|
82
82
|
return 'unknown';
|
|
83
83
|
}
|
package/src/main/lib/{customerFeedbackInbox.cjs → feedback-remote/customerFeedbackInbox.cjs}
RENAMED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
const path = require('node:path');
|
|
14
14
|
const fsp = require('node:fs/promises');
|
|
15
|
-
const atomicFs = require('
|
|
16
|
-
const schedulerPaths = require('
|
|
15
|
+
const atomicFs = require('../util/atomicFs.cjs');
|
|
16
|
+
const schedulerPaths = require('../scheduler/schedulerPaths.cjs');
|
|
17
17
|
const { resolveFeedbackBase, fromWireType, FEEDBACK_SLUG } = require('./customerFeedbackClient.cjs');
|
|
18
18
|
|
|
19
19
|
const STATUSES = /** @type {const} */ (['open', 'in_progress', 'resolved', 'wontfix']);
|
|
@@ -10,7 +10,7 @@ const REFRESH_DELAY_MS = 30_000;
|
|
|
10
10
|
*/
|
|
11
11
|
function registerCustomerFeedbackHandlers(deps = {}) {
|
|
12
12
|
const ipcMain = deps.ipcMain || require('electron').ipcMain;
|
|
13
|
-
const { schemas: s, validated: v } = require('
|
|
13
|
+
const { schemas: s, validated: v } = require('../../ipcSchemas.cjs');
|
|
14
14
|
const client = deps.client || require('./customerFeedbackClient.cjs');
|
|
15
15
|
const inbox = deps.inbox || require('./customerFeedbackInbox.cjs');
|
|
16
16
|
const timer = deps.setTimeoutImpl || setTimeout;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* humanPromptLedger.cjs — in-memory record of prompts a HUMAN typed into each
|
|
5
|
+
* chat claude session, keyed by claudeSessionId.
|
|
6
|
+
*
|
|
7
|
+
* Why it exists. The cross-project feedback conduit (crossProjectFeedback.cjs)
|
|
8
|
+
* may auto-approve a receiving-project session only when the human explicitly
|
|
9
|
+
* asked for it. An agent's say-so is not evidence of that. This ledger is the
|
|
10
|
+
* ONLY evidence that a human — not an agent, not an external/Web Remote
|
|
11
|
+
* injection, not an inbound proposal's agent-written opening prompt — typed a
|
|
12
|
+
* given prompt. Callers record only prompts that arrived from the human's own
|
|
13
|
+
* chat input, then ask `findHumanPromptContaining` whether a quoted request
|
|
14
|
+
* really appears in one.
|
|
15
|
+
*
|
|
16
|
+
* In-memory by design. Losing the ledger on restart only degrades auto-approve
|
|
17
|
+
* back to the ordinary 'proposed' path — it fails closed, so nothing is
|
|
18
|
+
* persisted to disk.
|
|
19
|
+
*
|
|
20
|
+
* Bounds: 10 prompts per session, 24h TTL, 200 sessions (least-recently-
|
|
21
|
+
* recorded evicted), 20000 chars per stored prompt. Pure Node, no Electron.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const MIN_QUOTE_CHARS = 20;
|
|
25
|
+
const MAX_PER_SESSION = 10;
|
|
26
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
27
|
+
const MAX_SESSIONS = 200;
|
|
28
|
+
const MAX_TEXT_CHARS = 20000;
|
|
29
|
+
|
|
30
|
+
/** @type {Map<string, Array<{ text: string, norm: string, at: number }>>} */
|
|
31
|
+
const ledger = new Map();
|
|
32
|
+
|
|
33
|
+
/** @param {string} s */
|
|
34
|
+
function normalize(s) {
|
|
35
|
+
return s.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {unknown} claudeSessionId
|
|
40
|
+
* @param {unknown} text
|
|
41
|
+
* @param {number} [now]
|
|
42
|
+
*/
|
|
43
|
+
function recordHumanPrompt(claudeSessionId, text, now = Date.now()) {
|
|
44
|
+
try {
|
|
45
|
+
if (typeof claudeSessionId !== 'string' || !claudeSessionId) return;
|
|
46
|
+
if (typeof text !== 'string' || !text.trim()) return;
|
|
47
|
+
const stored = text.slice(0, MAX_TEXT_CHARS);
|
|
48
|
+
const prior = (ledger.get(claudeSessionId) || []).filter((e) => now - e.at <= TTL_MS);
|
|
49
|
+
prior.push({ text: stored, norm: normalize(stored), at: now });
|
|
50
|
+
while (prior.length > MAX_PER_SESSION) prior.shift();
|
|
51
|
+
// Re-insert so Map order is least-recently-recorded first.
|
|
52
|
+
ledger.delete(claudeSessionId);
|
|
53
|
+
ledger.set(claudeSessionId, prior);
|
|
54
|
+
while (ledger.size > MAX_SESSIONS) {
|
|
55
|
+
const oldest = ledger.keys().next().value;
|
|
56
|
+
if (oldest === undefined) break;
|
|
57
|
+
ledger.delete(oldest);
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
/* never throws */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {unknown} claudeSessionId
|
|
66
|
+
* @param {unknown} quote
|
|
67
|
+
* @param {number} [now]
|
|
68
|
+
* @returns {{ text: string, at: number } | null}
|
|
69
|
+
*/
|
|
70
|
+
function findHumanPromptContaining(claudeSessionId, quote, now = Date.now()) {
|
|
71
|
+
try {
|
|
72
|
+
if (typeof claudeSessionId !== 'string' || typeof quote !== 'string') return null;
|
|
73
|
+
const q = normalize(quote);
|
|
74
|
+
if (q.length < MIN_QUOTE_CHARS) return null;
|
|
75
|
+
const entries = ledger.get(claudeSessionId);
|
|
76
|
+
if (!entries) return null;
|
|
77
|
+
const live = entries.filter((e) => now - e.at <= TTL_MS);
|
|
78
|
+
if (live.length === 0) ledger.delete(claudeSessionId);
|
|
79
|
+
else if (live.length !== entries.length) ledger.set(claudeSessionId, live);
|
|
80
|
+
for (let i = live.length - 1; i >= 0; i--) {
|
|
81
|
+
if (live[i].norm.includes(q)) return { text: live[i].text, at: live[i].at };
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _resetForTests() {
|
|
90
|
+
ledger.clear();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { recordHumanPrompt, findHumanPromptContaining, MIN_QUOTE_CHARS, _resetForTests };
|
|
@@ -35,8 +35,8 @@ const http = require('node:http');
|
|
|
35
35
|
const path = require('node:path');
|
|
36
36
|
const crypto = require('node:crypto');
|
|
37
37
|
const fsp = require('node:fs/promises');
|
|
38
|
-
const config = require('
|
|
39
|
-
const schedulerPaths = require('
|
|
38
|
+
const config = require('../../config.cjs');
|
|
39
|
+
const schedulerPaths = require('../scheduler/schedulerPaths.cjs');
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Mode-aware token file path, resolved fresh on every call (never cached at
|