claude-code-session-manager 0.97.0 → 0.100.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/README.md +3 -3
- package/bin/cli.cjs +16 -4
- package/bin/node-floor.cjs +41 -0
- package/dist/assets/{DataModel-D93FoaOm.js → DataModel-HdR0AxFq.js} +1 -1
- package/dist/assets/{History-CXxxqNP1.js → History-Dr4Jr_5z.js} +2 -2
- package/dist/assets/{Hooks-CzeYFQjq.js → Hooks-NhrvH3JP.js} +3 -3
- package/dist/assets/{Library-D2zPkwOC.js → Library-Dv_EtIMr.js} +1 -1
- package/dist/assets/{MarkdownEditor-DbinP78A.js → MarkdownEditor-DTKDWV_n.js} +1 -1
- package/dist/assets/{McpServers-Bu_sVGLr.js → McpServers-M034G9B3.js} +2 -2
- package/dist/assets/{Memory-BgiI6LZ_.js → Memory-DzF1B4gx.js} +6 -6
- package/dist/assets/{Permissions-C1MMzZRm.js → Permissions-DrgbSGWl.js} +3 -3
- package/dist/assets/{Plugins-Dhu6wAZi.js → Plugins-Bd3ef35w.js} +2 -2
- package/dist/assets/{ProvenanceBadge-C3AcWKMG.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
- package/dist/assets/{SaveBar-plwYm0iO.js → SaveBar-rimJem-Y.js} +1 -1
- package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
- package/dist/assets/{ScopeSwitcher-DFy0vv_o.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
- package/dist/assets/Settings-Dc1F_sSg.js +3 -0
- package/dist/assets/{SkillReferenceGraph-DsI7hRPB.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
- package/dist/assets/{Skills-3E748UfB.js → Skills-DRXd18gu.js} +2 -2
- package/dist/assets/{SystemPrompt-BqmfUJOd.js → SystemPrompt-ahy5-Fwe.js} +1 -1
- package/dist/assets/{TagLibrary-CPz6fO8Q.js → TagLibrary-C_tToDeL.js} +1 -1
- package/dist/assets/{TiptapBody-D9EoBQ1P.js → TiptapBody-DvdefS6K.js} +1 -1
- package/dist/assets/{Toggle-BHAmZNDn.js → Toggle-6Jl5Njc6.js} +1 -1
- package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
- package/dist/assets/{index-tn5JIVPj.js → index-vx8O73l8.js} +497 -502
- package/dist/assets/{settingsSchema-Crqy_aNz.js → settingsSchema-D6iRguNV.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +26 -29
- package/plugins/CLAUDE.md +6 -6
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +23 -19
- package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
- package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
- package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
- package/scripts/README.md +3 -11
- package/scripts/audit-ops-hygiene.cjs +3 -3
- package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
- package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
- package/scripts/mint-epic.cjs +2 -3
- package/scripts/scheduler-mcp-server.cjs +36 -7
- package/src/main/agentLibrary.cjs +22 -2
- package/src/main/build-info.json +4 -4
- package/src/main/config.cjs +41 -38
- package/src/main/docEdit.cjs +4 -1
- package/src/main/files.cjs +2 -5
- package/src/main/health.cjs +1 -1
- package/src/main/index.cjs +23 -10
- package/src/main/ipcSchemas.cjs +28 -35
- package/src/main/lib/agentPersonaSchema.cjs +13 -2
- package/src/main/lib/atomicFs.cjs +116 -0
- package/src/main/lib/branchSweep.cjs +13 -12
- package/src/main/lib/buildTarget.cjs +3 -3
- package/src/main/lib/claudeCliCaps.cjs +129 -0
- package/src/main/lib/credentials.cjs +2 -4
- package/src/main/lib/crossProjectFeedback.cjs +3 -3
- package/src/main/lib/cwdClassify.cjs +15 -3
- package/src/main/lib/definitionOfDone.cjs +207 -125
- package/src/main/lib/dodDrainHook.cjs +11 -5
- package/src/main/lib/epicMint.cjs +2 -4
- package/src/main/lib/epicStatusMirror.cjs +8 -10
- package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
- package/src/main/lib/gateAuthority.cjs +96 -0
- package/src/main/lib/gitExec.cjs +69 -0
- package/src/main/lib/gitWorktree.cjs +656 -92
- package/src/main/lib/instanceLock.cjs +5 -8
- package/src/main/lib/launchFailure.cjs +2 -3
- package/src/main/lib/macroLibrary.cjs +386 -0
- package/src/main/lib/mcpToolCatalog.cjs +26 -17
- package/src/main/lib/needsReviewLedger.cjs +1 -1
- package/src/main/lib/opsErrorLog.cjs +11 -1
- package/src/main/lib/opsOwnership.cjs +0 -5
- package/src/main/lib/pidAlive.cjs +32 -0
- package/src/main/lib/prdCreate.cjs +153 -19
- package/src/main/lib/prdDisposition.cjs +2 -2
- package/src/main/lib/prdGateFiles.cjs +284 -0
- package/src/main/lib/prdLocations.cjs +61 -0
- package/src/main/lib/prdMigration.cjs +2 -3
- package/src/main/lib/prdSizing.cjs +2 -1
- package/src/main/lib/promptSessionSchema.cjs +10 -2
- package/src/main/lib/rcaReport.cjs +4 -6
- package/src/main/lib/reaperHelpers.cjs +8 -1
- package/src/main/lib/reservationExpiry.cjs +6 -1
- package/src/main/lib/reviewNotice.cjs +263 -0
- package/src/main/lib/runClaudeP.cjs +4 -1
- package/src/main/lib/schedulerPaths.cjs +22 -2
- package/src/main/lib/sessionSlots.cjs +2 -4
- package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
- package/src/main/lib/timeoutShim.cjs +123 -0
- package/src/main/lib/timeoutShimScript.cjs +275 -0
- package/src/main/lib/upgradeDrain.cjs +4 -10
- package/src/main/lib/watchdogHelpers.cjs +33 -30
- package/src/main/lib/workTypeLibrary.cjs +7 -1
- package/src/main/promptSessionEvents.cjs +37 -13
- package/src/main/queueOps.cjs +17 -6
- package/src/main/scheduler.cjs +975 -203
- package/src/main/seedAgentPersonas.cjs +278 -23
- package/src/main/supervisor.cjs +4 -1
- package/src/main/templates/PRD_AUTHORING.md +126 -406
- package/src/preload/__tests__/preload-surface.test.cjs +68 -0
- package/src/preload/api.d.ts +41 -94
- package/src/preload/index.cjs +14 -9
- package/src/seed/agents/architect.md +1 -0
- package/src/seed/agents/dev-lead.md +17 -18
- package/src/seed/agents/project-home-builder.md +1 -0
- package/src/seed/agents/validator.md +10 -4
- package/dist/assets/HostBilko-nESrTRIg.js +0 -1
- package/dist/assets/Scheduler-BVYTeh39.js +0 -16
- package/dist/assets/Settings-DIhGgdfs.js +0 -3
- package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
- package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
- package/src/main/__tests__/agentLibrary.test.cjs +0 -276
- package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
- package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
- package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
- package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
- package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
- package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
- package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
- package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
- package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
- package/src/main/__tests__/chat-queue.test.cjs +0 -97
- package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
- package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
- package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
- package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
- package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
- package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
- package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
- package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
- package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
- package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
- package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
- package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
- package/src/main/__tests__/docEdit.test.cjs +0 -244
- package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
- package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
- package/src/main/__tests__/dod-report.test.cjs +0 -304
- package/src/main/__tests__/dod-reverify.test.cjs +0 -285
- package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
- package/src/main/__tests__/epicMint.test.cjs +0 -332
- package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
- package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
- package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
- package/src/main/__tests__/exchanges.test.cjs +0 -122
- package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
- package/src/main/__tests__/extractJson.test.cjs +0 -51
- package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
- package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
- package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
- package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
- package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
- package/src/main/__tests__/health-credentials.test.cjs +0 -81
- package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
- package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
- package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
- package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
- package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
- package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
- package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
- package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
- package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
- package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
- package/src/main/__tests__/historyDashboard.test.cjs +0 -163
- package/src/main/__tests__/historyRollup.test.cjs +0 -333
- package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
- package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
- package/src/main/__tests__/kg-augment.test.cjs +0 -195
- package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
- package/src/main/__tests__/machineProfile.test.cjs +0 -152
- package/src/main/__tests__/mcpStatus.test.cjs +0 -61
- package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
- package/src/main/__tests__/memoryStale.test.cjs +0 -88
- package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
- package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
- package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
- package/src/main/__tests__/personaMerge.test.cjs +0 -169
- package/src/main/__tests__/planValidator.test.cjs +0 -125
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
- package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
- package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
- package/src/main/__tests__/prdAgentType.test.cjs +0 -103
- package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
- package/src/main/__tests__/prdCreate.test.cjs +0 -979
- package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
- package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
- package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
- package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
- package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
- package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
- package/src/main/__tests__/prdLocations.test.cjs +0 -195
- package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
- package/src/main/__tests__/prdMigration.test.cjs +0 -349
- package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
- package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
- package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
- package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
- package/src/main/__tests__/prdSizing.test.cjs +0 -106
- package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
- package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
- package/src/main/__tests__/proc-role-env.test.cjs +0 -125
- package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
- package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
- package/src/main/__tests__/projectPages.test.cjs +0 -137
- package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
- package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
- package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
- package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
- package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
- package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
- package/src/main/__tests__/pty-write-result.test.cjs +0 -46
- package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
- package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
- package/src/main/__tests__/queueHistory.test.cjs +0 -355
- package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
- package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
- package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -154
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
- package/src/main/__tests__/rcaReport.test.cjs +0 -266
- package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
- package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
- package/src/main/__tests__/runLogRetention.test.cjs +0 -489
- package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
- package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
- package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
- package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
- package/src/main/__tests__/runVerify.test.cjs +0 -1784
- package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
- package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
- package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
- package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
- package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
- package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
- package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
- package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
- package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
- package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
- package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
- package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
- package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
- package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
- package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
- package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
- package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
- package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
- package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
- package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
- package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
- package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
- package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
- package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
- package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
- package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
- package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
- package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
- package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
- package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
- package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
- package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
- package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
- package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
- package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
- package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
- package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
- package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
- package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
- package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
- package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
- package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
- package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
- package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
- package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
- package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
- package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
- package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
- package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
- package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
- package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
- package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
- package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
- package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
- package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
- package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
- package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
- package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
- package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
- package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
- package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
- package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
- package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
- package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
- package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
- package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
- package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
- package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
- package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
- package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
- package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
- package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
- package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
- package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
- package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
- package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
- package/src/main/__tests__/seedStatus.test.cjs +0 -100
- package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
- package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
- package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
- package/src/main/__tests__/telemetryContract.test.cjs +0 -930
- package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
- package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
- package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
- package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
- package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
- package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
- package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
- package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
- package/src/main/__tests__/validationSentinels.test.cjs +0 -84
- package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
- package/src/main/bilkoHost.cjs +0 -314
- package/src/main/bilkoHostCore.cjs +0 -89
- package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
- package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
- package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
- package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
- package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
- package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
- package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
- package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
- package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
- package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
- package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
- package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
- package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
- package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
- package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
- package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
- package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
- package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
- package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
- package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
- package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
- package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
- package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
- package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
- package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
- package/src/main/lib/__tests__/gateFixtures.json +0 -20
- package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
- package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
- package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
- package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
- package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
- package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
- package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
- package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
- package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
- package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
- package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
- package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
- package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
- package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
- package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
- package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
- package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
- package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
- package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
- package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
- package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
- package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
- package/src/main/lib/__tests__/procName.test.cjs +0 -92
- package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
- package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
- package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
- package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
- package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
- package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
- package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
- package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
- package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
- package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
- package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
- package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
- package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
- package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
- package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
- package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
- package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
- package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
- package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
- package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
- package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
- package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
- package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
- package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
- package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
- package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
- package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -375
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
- package/src/main/lib/kgExchangePairing.cjs +0 -75
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
- State the time and space complexity of any non-trivial algorithm in a comment.
|
|
12
12
|
- Flag any nested loop over user-scaled data as a complexity hazard.
|
|
13
|
-
- Prefer O(n) solutions over O(n log n) only when n is provably small or constant.
|
|
14
|
-
- Lay out hot data contiguously and traverse it in memory order.
|
|
15
|
-
- Prefer arrays of structs or structs of arrays based on actual access patterns.
|
|
16
|
-
- Avoid pointer-chasing in inner loops on large datasets.
|
|
17
13
|
|
|
18
14
|
## Debugging approach
|
|
19
15
|
|
|
@@ -70,22 +66,21 @@ a higher-priority source exists:
|
|
|
70
66
|
|
|
71
67
|
## Execution discipline (headless runs)
|
|
72
68
|
|
|
73
|
-
Data
|
|
69
|
+
Data from 400+ scheduler runs: long hangs, not bad code, cause most failures, and "exited clean but left a red test" is the top verifier downgrade. The PRD body carries a one-line pointer to this file, never a copy. The dev-lead persona and the scheduler's finish protocol carry the per-run rules; this file gives the reasons behind them. Run order: orient → red → build → finish protocol (review → verify the `# Gate` commands → commit exact paths → verdict line).
|
|
74
70
|
|
|
75
|
-
- **Bound every command.** Wrap every test
|
|
76
|
-
- **Verify before done.** Run the acceptance test
|
|
77
|
-
- **Fail loud, fail fast.** On any step failure, print one diagnostic line and `exit 1
|
|
78
|
-
- **Stay in the AC.** Do not add work past the acceptance checklist
|
|
79
|
-
- **You ARE the executor — never re-queue or self-schedule.**
|
|
80
|
-
- **Never `git stash`, `git reset`, `git checkout -- <path>`, or `git clean` against working-tree state you did not create
|
|
81
|
-
- **`gh pr edit --body` can fail on repos with legacy GitHub Projects (classic) boards
|
|
82
|
-
- **`gh pr checks`/`gh run watch` exit non-zero while CI is merely *pending*, not failed — don't let that
|
|
83
|
-
- **Negative-assertion checks must exit 0 when clean.** A check
|
|
84
|
-
- **Recover or annotate every error — don't strand a Traceback in the transcript.** The verifier downgrades an otherwise-perfect run
|
|
85
|
-
- **An *expected* bounded
|
|
86
|
-
- **
|
|
87
|
-
- **
|
|
88
|
-
- **
|
|
89
|
-
- **
|
|
90
|
-
- **
|
|
91
|
-
- **If your own AC gate failed on a SIBLING job's in-flight file — not your own change — say so with the right verdict, not a lying FAIL.** When you are running in a shared or WIP-carrying tree (the prompt discloses this in a `--- FOREIGN WORKING-TREE STATE ---` section, if present) and your gate failure is confined to paths that section already told you are not your work, print `SCHEDULER_VERDICT: BLOCKED_BY_FOREIGN_WIP` (and `exit 1`) instead of `FAIL`, followed by a `FOREIGN_WIP_PATHS: <path1>, <path2>, ...` line naming exactly the failing paths. The scheduler independently validates every listed path against the exact manifest it disclosed to you — list a path you were never told is foreign, or claim this verdict for a regression you actually introduced, and the whole verdict is downgraded straight back to `FAIL`, rejected. This is not an escape hatch: it exists so a correctly-diagnosed "not my regression" outcome gets auto-requeued once the sibling clears its WIP, instead of triggering a fix-plan investigation into someone else's unfinished work.
|
|
71
|
+
- **Bound every command.** Wrap every test, build, dev-server, deploy, or poll command in a hard timeout, e.g. `timeout 300 <typecheck|unit>` or `curl --max-time 15`. Why: a bare `playwright test`, `vite`, `pnpm dev`, full e2e suite, or endpoint-polling publish hangs until the 4-hour watchdog kills it with SIGTERM.
|
|
72
|
+
- **Verify before done.** Run the acceptance test once before declaring success. Why: ending the run on a failing test trips the verifier's `transcript_errors` downgrade — fix it or `exit 1` with the failure instead.
|
|
73
|
+
- **Fail loud, fail fast.** On any step failure, print one diagnostic line and `exit 1`. Do not swallow it with `|| true` or retry silently. Exception: a `rateLimited` exit-1 is the scheduler's own benign auto-pause — it resumes next window on its own, so do not engineer around it.
|
|
74
|
+
- **Stay in the AC.** Do not add work past the acceptance checklist — "while we're here" extras are how runs overrun. Keep the body clean UTF-8, with no NUL or control bytes.
|
|
75
|
+
- **You ARE the executor — never re-queue or self-schedule.** Do the acceptance criteria yourself. Why: `/develop` or any queue-authoring skill just writes a *new* PRD and returns — the run exits 0 having done nothing, with no commit and no verdict line (`needs_review` with `no_verdict_sentinel`). The same applies to calling `ScheduleWakeup`, or backgrounding a review agent (`/code-review`, `/security-review`, `requesting-code-review`) and ending your turn with something like "I'll wait for the review agents to complete": a headless run has no next turn, so nothing ever resumes it — no verdict line prints, and the job parks in `needs_review` even though the work already landed. Run a required second review pass synchronously, inline, before the finish protocol — call the reviewer and read its result in the same turn. If the work is too big for one run, do not queue more work; see the timeout rule below. (Incidents: PRD 460 invoked `/develop` and exited 0 with no work. PRD 479 landed its commit, then backgrounded `/code-review --fix` + `/security-review` and called `ScheduleWakeup` to "wait" — same failure, different entry point.)
|
|
76
|
+
- **Never `git stash`, `git reset`, `git checkout -- <path>`, or `git clean` against working-tree state you did not create.** There is no polite version of this. You are normally isolated in your own `git worktree` on branch `sm-job/<slug>` (`src/main/lib/gitWorktree.cjs`), and the scheduler salvages any uncommitted diff of yours on teardown — so you never need to touch shared state to protect your own work. Confirm isolation with `git rev-parse --git-common-dir` (a worktree's common-dir differs from its own `.git`) or by checking your cwd; `git diff`/`git status` are always safe. If you land in a SHARED tree with pre-existing dirty tracked files anyway, work around them — scope `git add`/commits to only the paths you touched — or end with `SCHEDULER_VERDICT: FAIL <reason>` (`SCHEDULER_VERDICT: BLOCKED_BY_FOREIGN_WIP` only when your gate failed on those files, as the finish protocol says); never discard, stash, or revert someone else's uncommitted changes to get a clean checkout. A shared tree may be feeding a running service that reads its config straight from the working tree, so reverting it is a production change, not a local inconvenience. The scheduler runs a shared-tree stash guard as a backstop (`scheduler.cjs`'s `checkSharedTreeGuard`/`evaluateSharedTreeGuard`), but that guard exists to catch a mistake, not to license one. (Incidents: PRD 477 stashed a sibling job's WIP to get its own checkout and never restored it. 2026-09-01: a headless executor in the trader repo ran a blanket `git stash` against an operator's uncommitted live trading-config edit and exited without restoring it — the third incident of this class.)
|
|
77
|
+
- **`gh pr edit --body` can fail on repos with legacy GitHub Projects (classic) boards.** It queries the deprecated `repository.pullRequest.projectCards` field and errors with a `GraphQL: Projects (classic) is being deprecated` message even though the edit itself would otherwise succeed — a known `gh` CLI quirk, not a defect in your work. Prefer `gh api -X PATCH repos/<owner>/<repo>/pulls/<n> -f body="$(cat body.md)"` instead; it skips that field. If `gh pr edit` fails this way anyway, retry immediately with the `gh api` form and print one line noting the fallback — don't leave the bare GraphQL error as the step's last output, or the verifier reads it as unrecovered.
|
|
78
|
+
- **`gh pr checks`/`gh run watch` exit non-zero while CI is merely *pending*, not failed — don't let that read as a bare error.** `gh pr checks <n>` returns a non-zero exit (e.g. 8) with output like `check pending 0 <url>` before checks finish — normal, documented `gh` CLI behavior, not a failure. Poll with the exact same command and description every time; the verifier's self-recovery detector pairs a failure with a later success only when the wording matches, so switching wording mid-poll (e.g. dropping a `sleep N &&` prefix) can leave the earlier pending-state error looking unrecovered. (Incident: `745-pr188-ci-lint-docs-integrity` — a fully green, committed, pushed run was flagged `needs_review` over exactly this.)
|
|
79
|
+
- **Negative-assertion checks must exit 0 when clean.** A check for the *absence* of something (a `grep` that should find nothing, a `diff` expecting no change) must exit 0 on the clean case. Why: a bare `grep` exits 1 on no-match, so the success path surfaces as `is_error=true` and the verifier downgrades a perfect run. Invert it: `if <detector>; then echo "HALT: <what was found>"; exit 1; fi; echo clean` — never let the clean path carry a non-zero exit.
|
|
80
|
+
- **Recover or annotate every error — don't strand a Traceback in the transcript.** The verifier's `transcript_errors` heuristic downgrades an otherwise-perfect run when a `Traceback`/`Error` has no visible recovery within ~10 lines — the single most common false-positive on green work. The top cause is a throwaway probe that errors (a quoting/f-string slip in an inline `python -c`, a wrong kwarg, a bad path): when a probe errors, immediately re-run the corrected version, or print `# expected/handled: <why>` right after it so the recovery sits next to the error. Prefer a small temp `.py` file over a fragile multi-quote one-liner. (The timeout rule below is the other cause.)
|
|
81
|
+
- **An *expected* bounded timeout (exit 124) must be annotated, not left bare.** Capping a genuinely long task (a full-universe ingest, a long scan) at its expected limit is correct, but a bare `Exit code 124` reads as a failure to the verifier. Wrap it so the cap reads as success-with-note: `timeout 120 <cmd> || { rc=$?; [ $rc -eq 124 ] && echo "hit time cap — OK" || { echo "HALT: rc=$rc"; exit 1; }; }` — distinguish the expected 124 from a real non-zero. If the work needs longer than a safe cap, the PRD is too big: end with `SCHEDULER_VERDICT: FAIL <reason>` so the planner splits it. Never run it in the background.
|
|
82
|
+
- **Never `sleep N && <cmd>` to poll remote CI/job status.** The harness hard-blocks a `sleep` chained to another command, and that block itself lands in the transcript as a bare error — usually in the last 20% of the run, right where the verifier weighs errors most. Use the tool's own blocking watcher under a hard cap instead: `timeout 600 gh run watch <run-id> --repo <owner>/<repo> --exit-status`. `gh pr checks` is itself negative-assertion-shaped (exits 8 pending, 1 failed/none-reported — see above), so wrap it the same way. (Incident: PRD 745 landed a truthful PASS and a fully green CI run, but an unannotated `sleep 20 && gh pr checks` and a harness-blocked `sleep 90 && gh pr checks` sat at the end of the transcript and the run was flagged anyway.)
|
|
83
|
+
- **Don't leak expected-error text into tool output.** The verifier pattern-matches the transcript for `Traceback`/`FAIL`/`Error:`. When a step is *expected* to error (a TDD red-phase test, an existence probe), capture it and print a clean token instead of letting the raw exception land verbatim — e.g. `if <probe> 2>/dev/null; then echo PROBE_OK; else echo PROBE_ABSENT; fi`, or filter a noisy run down to `RED (expected)` / `GREEN`. When retrying a transient failure, re-run the exact same command with the same description — the self-recovery detector only pairs a failure with a later success when the wording matches.
|
|
84
|
+
- **End green: run the AC gate LAST, and let nothing error after it.** The verifier weighs the final ~20% of the run most heavily — a tool error there trips a downgrade even when everything actually passed. Order the run so any intentionally-failing step (a TDD red test, an expected-nonzero probe) runs early, never after the gate. If you must demonstrate a failure late anyway, capture it (`… 2>&1 | tail` inside a conditional, or assert on the captured text) instead of letting it hit the transcript bare.
|
|
85
|
+
- **The verdict line is your authoritative "I passed" signal — emit it truthfully.** The scheduler's finish protocol ends by printing `SCHEDULER_VERDICT: PASS` once the AC gate is green and the commit has landed (or `SCHEDULER_VERDICT: FAIL <reason>` + `exit 1` otherwise). `PASS` plus a landed commit is authoritative: it overrides incidental transcript markers, so a deliberately reproduced red test or a grep result containing "Error" will not false-trip `needs_review`, as long as the run genuinely ends green and committed. Exiting 0 with uncommitted changes, or with no verdict line at all, is the #1 cause of needless `needs_review`. Never print `PASS` when the gate is red — that turns a safety net into a silent-failure machine.
|
|
86
|
+
- **If your own AC gate failed on a SIBLING job's in-flight file, say so with the right verdict — don't print a lying FAIL.** If the prompt disclosed a `--- FOREIGN WORKING-TREE STATE ---` section and your gate failure is confined to paths that section named as not your work, print `SCHEDULER_VERDICT: BLOCKED_BY_FOREIGN_WIP` (and `exit 1`) plus a `FOREIGN_WIP_PATHS: <path1>, <path2>, ...` line naming exactly the failing paths. The scheduler validates every listed path against the manifest it disclosed to you — list a path it never named, or claim this verdict for your own regression, and it is rejected back to `FAIL`. This is not an escape hatch: it exists so a correctly-diagnosed "not my regression" gets auto-requeued once the sibling clears its WIP, instead of spawning a fix-plan investigation into someone else's unfinished work.
|
package/scripts/README.md
CHANGED
|
@@ -8,7 +8,7 @@ scripts/lib was moved into src/main/lib (2026-09); nothing under src/ may requir
|
|
|
8
8
|
|
|
9
9
|
| script | invoked by | shipped on npm |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| audit-ops-hygiene.cjs | manual; named in `ops-sweep`
|
|
11
|
+
| audit-ops-hygiene.cjs | manual; named in `ops-sweep` SKILL.md | yes |
|
|
12
12
|
| bench/main-bench.cjs | `npm run bench` (main-process micro-benches, plain Node); renderer half is `npm run bench:renderer` (`tests/bench/`, `vitest.bench.config.ts`, not in `test:unit`) | no |
|
|
13
13
|
| check-conditional-hooks.cjs | `npm run lint:hooks` (in `lint`) | no |
|
|
14
14
|
| check-epic-transcripts.cjs | manual read-only diagnostic (`--json`); also surfaced as a non-fatal warning in `npm run health` | no |
|
|
@@ -17,17 +17,13 @@ scripts/lib was moved into src/main/lib (2026-09); nothing under src/ may requir
|
|
|
17
17
|
| check-main-ts-check.cjs | `npm run lint:main-ts-check` (in `lint`) — `tsconfig.main.json` `include` ⇔ `// @ts-check` first line, both directions; explicit list only, `checkJs` false | no |
|
|
18
18
|
| check-renderer-storage.cjs | `npm run lint:renderer-storage` (in `lint`) — ratchet-bans `localStorage.`/`sessionStorage.` in `src/renderer` outside an explicit ALLOWLIST (Epic stateless-ui-review) | no |
|
|
19
19
|
| check-tracked-filenames.cjs | `npm run lint:filenames` (in `lint`) — fails on tracked paths with Windows-illegal chars, trailing dot/space, or reserved device names | no |
|
|
20
|
-
| check-unregistered-tests.cjs | `npm run lint:unregistered-tests` (in `lint`) | no |
|
|
21
20
|
| check-unstable-selectors.cjs | `npm run lint:selectors` (in `lint`) | no |
|
|
22
|
-
| cleanup-nested-queue-stubs.cjs | manual one-shot; dispatches to cleanup-worktree-ops-stubs.cjs | no |
|
|
23
|
-
| cleanup-worktree-ops-stubs.cjs | via cleanup-nested-queue-stubs.cjs | no |
|
|
24
21
|
| health.sh | manual; `local-project-health` skill's lookup path (`npm run health` uses src/main/health.cjs) | no |
|
|
25
|
-
| install-scheduler-mcp-user-scope.sh | manual
|
|
22
|
+
| install-scheduler-mcp-user-scope.sh | manual (`seedSchedulerMcp.cjs` does the same on first boot, or on the next boot after its marker file is deleted) | no |
|
|
26
23
|
| install-scheduler-watchdog.sh | manual; installs the systemd user timer (cron fallback) | no |
|
|
27
|
-
| mint-epic.cjs |
|
|
24
|
+
| mint-epic.cjs | manual; joins an existing Epic and prints its prds dir | yes |
|
|
28
25
|
| ops-sweep.cjs | `ops-sweep` SKILL.md (`node "$SM_ROOT/scripts/ops-sweep.cjs" <cwd>`) | yes |
|
|
29
26
|
| postinstall.cjs | npm `postinstall` | yes |
|
|
30
|
-
| probe-electron-helper-comm.cjs | manual probe (Linux, xvfb) | no |
|
|
31
27
|
| refresh-vad-assets.mjs | `npm run refresh:vad-assets` | no |
|
|
32
28
|
| replay-verdicts.cjs | manual, dev-only, read-only | no |
|
|
33
29
|
| scheduler-mcp-server.cjs | registered as an MCP server (`seedSchedulerMcp.cjs`, `send-feedback` SKILL.md) | yes |
|
|
@@ -52,10 +48,6 @@ The four `hooks/guard-*.cjs` are adopted by reference, not copied: `src/main/lib
|
|
|
52
48
|
- `ops-sweep.cjs` is the portable sweep: it requires a target-project cwd argument and works on any project's ops folder.
|
|
53
49
|
- `audit-ops-hygiene.cjs` holds this repo's own patterns and is not portable.
|
|
54
50
|
|
|
55
|
-
## Cleanup dispatch
|
|
56
|
-
|
|
57
|
-
`cleanup-nested-queue-stubs.cjs` removes nested queue shards and then dispatches to `cleanup-worktree-ops-stubs.cjs` (its `main()`), which handles the worktree-side stubs.
|
|
58
|
-
|
|
59
51
|
Bench numbers are machine-relative — compare runs on the same machine only; there are no pass/fail thresholds.
|
|
60
52
|
|
|
61
53
|
## npm shipping
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
* anything is actually lost.
|
|
20
20
|
*
|
|
21
21
|
* Pattern E — PRDs authored outside the sanctioned `scheduler_create_prd` MCP
|
|
22
|
-
* tool (
|
|
23
|
-
*
|
|
22
|
+
* tool (a hand-written PRD file is never sanctioned — see CLAUDE.md's "PRD
|
|
23
|
+
* authoring is API-only"). Every
|
|
24
24
|
* API-created PRD gets a `prd_create` record in the machine-wide audit log
|
|
25
25
|
* (`~/.claude/session-manager/audit-log.jsonl`, `src/main/lib/auditLog.cjs`)
|
|
26
26
|
* keyed by cwd+slug. This check is deliberately narrow: it only inspects PRD
|
|
@@ -231,7 +231,7 @@ function auditPatternE() {
|
|
|
231
231
|
unattributed,
|
|
232
232
|
verdict: unattributed.length === 0
|
|
233
233
|
? 'CLEAN: every untracked (not-yet-committed) PRD has a matching prd_create record.'
|
|
234
|
-
: 'INVESTIGATE: untracked PRD(s) with no matching prd_create audit event — likely hand-authored
|
|
234
|
+
: 'INVESTIGATE: untracked PRD(s) with no matching prd_create audit event — likely hand-authored, bypassing scheduler_create_prd. Hand-writing a PRD is never sanctioned; confirm how this file was created.',
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
|
|
@@ -78,7 +78,7 @@ function decide(payload) {
|
|
|
78
78
|
const reason = [
|
|
79
79
|
`Direct ${toolName} to a session-manager-operations/scheduler/ path is blocked.`,
|
|
80
80
|
`PRDs must be authored through the scheduler API, not a raw file write — use the "${suggested}" MCP tool instead.`,
|
|
81
|
-
'If the Session Manager app is not running (the admin API this MCP tool talks to only exists while it is),
|
|
81
|
+
'If the Session Manager app is not running (the admin API this MCP tool talks to only exists while it is), stop: ask the human to start the app, then retry the MCP tool. Never hand-write a PRD file.',
|
|
82
82
|
].join(' ');
|
|
83
83
|
return buildDeny(reason);
|
|
84
84
|
} catch (e) {
|
|
@@ -17,7 +17,7 @@ const ALWAYS_DENY_TOOLS = new Set(['ScheduleWakeup', 'CronCreate']);
|
|
|
17
17
|
const BACKGROUNDABLE_AGENT_TOOLS = new Set(['Task', 'Agent']);
|
|
18
18
|
|
|
19
19
|
const STANDARDS_QUOTE = 'You ARE the executor — never re-queue or self-schedule.';
|
|
20
|
-
const STANDARDS_CITE = 'plugins/session-manager-dev/skills/develop/standards.md
|
|
20
|
+
const STANDARDS_CITE = 'plugins/session-manager-dev/skills/develop/standards.md (Execution discipline)';
|
|
21
21
|
|
|
22
22
|
function buildAllow() {
|
|
23
23
|
return { continue: true };
|
package/scripts/mint-epic.cjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* mint-epic.cjs — CLI wrapper over lib/epicMint.cjs's JOIN path, for
|
|
4
|
-
*
|
|
5
|
-
* manual-write fallback).
|
|
3
|
+
* mint-epic.cjs — CLI wrapper over lib/epicMint.cjs's JOIN path, for joining
|
|
4
|
+
* an existing Epic without the app's admin API running.
|
|
6
5
|
*
|
|
7
6
|
* This script never creates an Epic. It only resolves an EXISTING Epic's
|
|
8
7
|
* prds/ write directory. An Epic comes into existence in exactly one place —
|
|
@@ -133,7 +133,7 @@ const TOOLS = [
|
|
|
133
133
|
type: 'object',
|
|
134
134
|
properties: {
|
|
135
135
|
slug: { type: 'string', description: 'PRD slug of the job to reset' },
|
|
136
|
-
force: { type: 'boolean', description: 'Required to reset a job whose status is already "completed"' },
|
|
136
|
+
force: { type: 'boolean', description: 'Required to reset a job whose status is already "completed" or "skipped"' },
|
|
137
137
|
cwd: { type: 'string', description: 'Optional: the PRD project cwd, narrows/speeds the search' },
|
|
138
138
|
},
|
|
139
139
|
required: ['slug'],
|
|
@@ -162,13 +162,21 @@ const TOOLS = [
|
|
|
162
162
|
properties: {
|
|
163
163
|
title: { type: 'string', description: 'One-line human-readable title' },
|
|
164
164
|
cwd: { type: 'string', description: 'Absolute path to the target project (where claude -p will run). Optional inside an Epic session — the server resolves the real project from the calling session (originClaudeSessionId/sourcePromptId) when omitted.' },
|
|
165
|
-
estimateMinutes: { type: 'number', description: 'Integer wall-clock estimate in minutes' },
|
|
165
|
+
estimateMinutes: { type: 'number', description: 'Integer wall-clock estimate in minutes. Most PRDs take 5-10; never over 15 (split instead)' },
|
|
166
166
|
goal: { type: 'string', description: '2-4 sentences: what the executor will build and why' },
|
|
167
167
|
acceptanceCriteria: {
|
|
168
168
|
type: 'array', items: { type: 'string' },
|
|
169
169
|
description: 'Each entry is one verifiable checklist line',
|
|
170
170
|
},
|
|
171
171
|
implementationNotes: { type: 'string', description: 'File paths, patterns, and constraints the executor needs' },
|
|
172
|
+
gate: {
|
|
173
|
+
type: 'array', items: { type: 'string' },
|
|
174
|
+
description: 'REQUIRED. Commands that prove this PRD is done. The scheduler re-runs them without a shell. One command per entry, run in order; each must exit 0. Start each && step with `timeout <seconds>`. Join steps with &&. Outside single quotes, no | < > ; & ` $ \\ * ? [ ] ( ) { } or !. Use ["none"], exactly, only for docs or config with no runnable check.',
|
|
175
|
+
},
|
|
176
|
+
files: {
|
|
177
|
+
type: 'array', items: { type: 'string' },
|
|
178
|
+
description: 'REQUIRED. Repo-relative files or folders (end a folder with /) this PRD may change. No absolute paths, .. or . segments, globs, backslashes or backticks. PRDs that run at the same time must not share files; chain them with dependsOn instead.',
|
|
179
|
+
},
|
|
172
180
|
outOfScope: { type: 'array', items: { type: 'string' }, description: 'Optional: what NOT to build' },
|
|
173
181
|
slug: { type: 'string', description: 'Optional kebab-case slug; derived from title if omitted' },
|
|
174
182
|
parallelGroup: { type: 'number', description: 'DEPRECATED and ignored (PRD 832): numbers are strictly unique per project; use dependsOn for ordering' },
|
|
@@ -194,7 +202,7 @@ const TOOLS = [
|
|
|
194
202
|
description: 'Optional: set true only when this PRD\'s acceptance criteria are wall-clock/timing measurements (frame time, performance fences) that CPU contention from concurrent jobs would invalidate. The scheduler dispatches it only once zero other jobs are running machine-wide, and holds every other job off the whole slot pool for its run — a whole-machine exclusive lease, not a per-project one. If the machine never goes quiet within the configured wait window (default 30 minutes), it dispatches anyway and is marked degraded. Opt-in only; omit for ordinary PRDs.',
|
|
195
203
|
},
|
|
196
204
|
},
|
|
197
|
-
required: ['title', 'estimateMinutes', 'goal', 'acceptanceCriteria', 'implementationNotes'],
|
|
205
|
+
required: ['title', 'estimateMinutes', 'goal', 'acceptanceCriteria', 'implementationNotes', 'gate', 'files'],
|
|
198
206
|
},
|
|
199
207
|
},
|
|
200
208
|
{
|
|
@@ -490,6 +498,18 @@ async function handleCallTool(request) {
|
|
|
490
498
|
+ 'If more work is genuinely needed, say so in your final result text — the authoring Epic decides whether to queue it.',
|
|
491
499
|
);
|
|
492
500
|
}
|
|
501
|
+
// Required-fields refusal (gate-and-files-in-PRD-body unit): checked
|
|
502
|
+
// right after the headless-refusal check above, before any payload
|
|
503
|
+
// forwarding — 74% of parked jobs had no gate the scheduler could
|
|
504
|
+
// read, so the tool itself refuses a call missing either field rather
|
|
505
|
+
// than letting an ungated PRD reach disk.
|
|
506
|
+
if (!Array.isArray(args?.gate) || args.gate.length === 0 || !Array.isArray(args?.files) || args.files.length === 0) {
|
|
507
|
+
return errorResult(
|
|
508
|
+
'scheduler_create_prd needs "gate" (the commands that prove this PRD is done, with each && step '
|
|
509
|
+
+ 'starting with "timeout <seconds>", or ["none"]) and "files" (the repo-relative files this PRD may change). '
|
|
510
|
+
+ 'Add both and call again.',
|
|
511
|
+
);
|
|
512
|
+
}
|
|
493
513
|
// If the caller (the model) didn't pass sourcePromptId, forward this
|
|
494
514
|
// process's own SM_CHAT_SESSION_ID (set by chatRunner.cjs on the
|
|
495
515
|
// parent claude -p process this MCP server inherited its env from) so
|
|
@@ -515,11 +535,20 @@ async function handleCallTool(request) {
|
|
|
515
535
|
? ' — PRD file written; the queue row is derived on the next scheduler reconcile pass, not by this call.'
|
|
516
536
|
: '';
|
|
517
537
|
let text = JSON.stringify(result) + note;
|
|
518
|
-
//
|
|
519
|
-
//
|
|
520
|
-
//
|
|
538
|
+
// Warnings (PRD 1403 sizing + gate-and-files-in-PRD-body absent/none-gate
|
|
539
|
+
// warnings) are advisory only — never block the write, just surfaced
|
|
540
|
+
// here so the authoring session can decide to split or re-queue before
|
|
541
|
+
// confirming it. See prdSizing.cjs and prdGateFiles.cjs.
|
|
521
542
|
if (Array.isArray(result?.warnings) && result.warnings.length > 0) {
|
|
522
|
-
text += `\
|
|
543
|
+
text += `\nWarnings:\n${result.warnings.map((w) => `- ${w}`).join('\n')}`;
|
|
544
|
+
}
|
|
545
|
+
// Echo the gate and files the API actually recorded, same honesty
|
|
546
|
+
// standard as `note` above — not a repeat of the caller's own input.
|
|
547
|
+
if (result?.gate) {
|
|
548
|
+
text += `\nGate (${result.gate.source}): ${result.gate.commands.join(' && ')}`;
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(result?.files)) {
|
|
551
|
+
text += `\nFiles: ${result.files.join(', ')}`;
|
|
523
552
|
}
|
|
524
553
|
return { content: [{ type: 'text', text }] };
|
|
525
554
|
}
|
|
@@ -66,8 +66,13 @@ function decodeLine(s) {
|
|
|
66
66
|
* instruction that button sends into the new session, and `actionLabel`
|
|
67
67
|
* overrides the button's caption (defaults to the persona name). Claude Code
|
|
68
68
|
* ignores all three; only this app reads them.
|
|
69
|
+
*
|
|
70
|
+
* `seedVersion` is seedAgentPersonas.cjs's bundled-persona stamp — an
|
|
71
|
+
* integer, present only on the four bundled personas. Written through
|
|
72
|
+
* unchanged (not Claude-Code-visible either) so a save from the Agent
|
|
73
|
+
* Library editor never erases the stamp a hand-edit should keep intact.
|
|
69
74
|
*/
|
|
70
|
-
function serializePersona({ name, description, tools, model, effort, color, tags, projects, action, actionLabel, title, body }) {
|
|
75
|
+
function serializePersona({ name, description, tools, model, effort, color, tags, projects, action, actionLabel, title, seedVersion, body }) {
|
|
71
76
|
const lines = ['---', `name: ${name}`];
|
|
72
77
|
if (description) lines.push(`description: ${description}`);
|
|
73
78
|
if (tools && tools.length) lines.push(`tools: ${tools.join(', ')}`);
|
|
@@ -79,6 +84,7 @@ function serializePersona({ name, description, tools, model, effort, color, tags
|
|
|
79
84
|
if (action) lines.push(`action: ${encodeLine(action)}`);
|
|
80
85
|
if (actionLabel) lines.push(`actionLabel: ${encodeLine(actionLabel)}`);
|
|
81
86
|
if (title) lines.push(`title: ${title}`);
|
|
87
|
+
if (typeof seedVersion === 'number' && Number.isFinite(seedVersion)) lines.push(`seedVersion: ${seedVersion}`);
|
|
82
88
|
lines.push('---', '');
|
|
83
89
|
return lines.join('\n') + (body || '').trim() + '\n';
|
|
84
90
|
}
|
|
@@ -142,6 +148,7 @@ async function savePersona({
|
|
|
142
148
|
action,
|
|
143
149
|
actionLabel,
|
|
144
150
|
title,
|
|
151
|
+
seedVersion,
|
|
145
152
|
body,
|
|
146
153
|
projectName,
|
|
147
154
|
globalDir = path.join(os.homedir(), '.claude', 'agents'),
|
|
@@ -156,7 +163,19 @@ async function savePersona({
|
|
|
156
163
|
return saveOverlay({ name, projectName, model, effort, loadSessions, validatePath, writeTextAtomic });
|
|
157
164
|
}
|
|
158
165
|
const target = validatePath(path.join(globalDir, `${name}.md`));
|
|
159
|
-
|
|
166
|
+
// The Agent Library editor's form has no `seedVersion` field, so a save
|
|
167
|
+
// through it never passes one explicitly — carry over whatever stamp the
|
|
168
|
+
// existing file already has rather than silently erasing it. An explicit
|
|
169
|
+
// `seedVersion` argument (e.g. the seeder's own future callers) still wins.
|
|
170
|
+
let resolvedSeedVersion = seedVersion;
|
|
171
|
+
if (resolvedSeedVersion === undefined) {
|
|
172
|
+
try {
|
|
173
|
+
const existing = splitFrontmatter(fsSync.readFileSync(target, 'utf8'));
|
|
174
|
+
const existingVersion = Number(existing.fm.seedVersion);
|
|
175
|
+
if (Number.isFinite(existingVersion)) resolvedSeedVersion = existingVersion;
|
|
176
|
+
} catch { /* no existing file (or unreadable) — nothing to carry over */ }
|
|
177
|
+
}
|
|
178
|
+
const text = serializePersona({ name, description, tools, model, effort, color, tags, projects, action, actionLabel, title, seedVersion: resolvedSeedVersion, body });
|
|
160
179
|
await writeTextAtomic(target, text);
|
|
161
180
|
if (originalName && originalName !== name) {
|
|
162
181
|
const oldReal = validatePath(path.join(globalDir, `${originalName}.md`));
|
|
@@ -301,6 +320,7 @@ async function listPersonas({
|
|
|
301
320
|
action: decodeLine(fm.action) || null,
|
|
302
321
|
actionLabel: decodeLine(fm.actionLabel) || null,
|
|
303
322
|
title: fm.title || null,
|
|
323
|
+
seedVersion: fm.seedVersion !== undefined && Number.isFinite(Number(fm.seedVersion)) ? Number(fm.seedVersion) : null,
|
|
304
324
|
path: real,
|
|
305
325
|
body: body.trim(),
|
|
306
326
|
overridingProjects,
|
package/src/main/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"gitSha": "
|
|
4
|
-
"gitShortSha": "
|
|
2
|
+
"version": "0.100.0",
|
|
3
|
+
"gitSha": "e2cdd120c1125c4310e8bae3ed007d1d6e55a850",
|
|
4
|
+
"gitShortSha": "e2cdd120",
|
|
5
5
|
"gitBranch": "HEAD",
|
|
6
|
-
"builtAt": "2026-
|
|
6
|
+
"builtAt": "2026-10-03T03:50:40.894Z",
|
|
7
7
|
"dirty": false
|
|
8
8
|
}
|
package/src/main/config.cjs
CHANGED
|
@@ -25,6 +25,7 @@ const logs = require('./logs.cjs');
|
|
|
25
25
|
const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
|
|
26
26
|
const { expandHome } = require('./lib/expandHome.cjs');
|
|
27
27
|
const { listReferencedFiles } = require('./lib/importReferences.cjs');
|
|
28
|
+
const atomicFs = require('./lib/atomicFs.cjs');
|
|
28
29
|
|
|
29
30
|
/** Map<absPath, {watcher, refCount}> — one chokidar watcher per path. */
|
|
30
31
|
const watchers = new Map();
|
|
@@ -38,22 +39,41 @@ function attachWindow(w) {
|
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Resolve a path to its realpath, handling non-existent files by resolving
|
|
41
|
-
* the
|
|
42
|
+
* the nearest existing ancestor directory instead. Prevents symlink
|
|
43
|
+
* traversal attacks.
|
|
44
|
+
*
|
|
45
|
+
* A fresh target can be missing more than one directory level, for example
|
|
46
|
+
* "<tmpdir>/session-manager-operations/prompt-sessions/x.json" right after
|
|
47
|
+
* `mkdtemp`, where neither `session-manager-operations` nor
|
|
48
|
+
* `prompt-sessions` exists yet. Walk up one directory at a time until one
|
|
49
|
+
* exists, realpath that ancestor, then join every segment below it back on.
|
|
50
|
+
* Why: stopping after a single parent hop returns the lexical (not
|
|
51
|
+
* realpath'd) path on macOS, where `os.tmpdir()` sits under `/var`, a
|
|
52
|
+
* symlink to `/private/var`. The caller's root check then compares that
|
|
53
|
+
* unresolved `/var/...` path against a sibling root that DID resolve to
|
|
54
|
+
* `/private/var/...` and always rejects it, even for paths that belong
|
|
55
|
+
* squarely inside the allowed root.
|
|
42
56
|
*/
|
|
43
57
|
function realResolve(abs) {
|
|
44
58
|
const lex = path.resolve(expandHome(abs));
|
|
45
59
|
try {
|
|
46
60
|
return fs.realpathSync(lex);
|
|
47
61
|
} catch (e) {
|
|
48
|
-
if (e.code
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
if (e.code !== 'ENOENT') throw e;
|
|
63
|
+
}
|
|
64
|
+
const tail = [path.basename(lex)];
|
|
65
|
+
let dir = path.dirname(lex);
|
|
66
|
+
for (;;) {
|
|
67
|
+
try {
|
|
68
|
+
const realDir = fs.realpathSync(dir);
|
|
69
|
+
return path.join(realDir, ...tail.reverse());
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (e.code !== 'ENOENT') throw e;
|
|
72
|
+
const parentDir = path.dirname(dir);
|
|
73
|
+
if (parentDir === dir) return lex; // hit the filesystem root; give up safely
|
|
74
|
+
tail.push(path.basename(dir));
|
|
75
|
+
dir = parentDir;
|
|
55
76
|
}
|
|
56
|
-
throw e;
|
|
57
77
|
}
|
|
58
78
|
}
|
|
59
79
|
|
|
@@ -108,11 +128,16 @@ function validatePath(abs) {
|
|
|
108
128
|
throw new Error(`Path outside allowed boundaries: ${real}`);
|
|
109
129
|
}
|
|
110
130
|
|
|
111
|
-
// Paths that are allowed as write destinations.
|
|
131
|
+
// Paths that are allowed as write destinations. Built from the REALPATH of
|
|
132
|
+
// home because validateWrite compares against a realpath — on macOS a HOME
|
|
133
|
+
// under os.tmpdir() (/var → /private/var) otherwise never matches.
|
|
134
|
+
const REAL_HOME = (() => {
|
|
135
|
+
try { return fs.realpathSync(os.homedir()); } catch { return os.homedir(); }
|
|
136
|
+
})();
|
|
112
137
|
const WRITE_PREFIXES = [
|
|
113
|
-
path.join(
|
|
114
|
-
path.join(
|
|
115
|
-
path.join(
|
|
138
|
+
path.join(REAL_HOME, '.claude'),
|
|
139
|
+
path.join(REAL_HOME, '.claude.json'), // global MCP servers config
|
|
140
|
+
path.join(REAL_HOME, '.config', 'claude-code'),
|
|
116
141
|
];
|
|
117
142
|
|
|
118
143
|
/**
|
|
@@ -241,21 +266,7 @@ async function writeTextAtomic(abs, text, opts = {}) {
|
|
|
241
266
|
const real = validatePath(expandHome(abs));
|
|
242
267
|
validateWrite(real);
|
|
243
268
|
assertOpsWrite(real, opts.writer);
|
|
244
|
-
|
|
245
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
246
|
-
const tmp = `${real}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
247
|
-
try {
|
|
248
|
-
await fsp.writeFile(tmp, text, opts.mode ? { encoding: 'utf8', mode: opts.mode } : 'utf8');
|
|
249
|
-
if (opts.mode) {
|
|
250
|
-
// chmod explicitly because some platforms ignore the mode arg on
|
|
251
|
-
// writeFile when the file pre-exists.
|
|
252
|
-
try { await fsp.chmod(tmp, opts.mode); } catch { /* */ }
|
|
253
|
-
}
|
|
254
|
-
await fsp.rename(tmp, real);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
try { await fsp.unlink(tmp); } catch { /* tmp never created or already gone */ }
|
|
257
|
-
throw e;
|
|
258
|
-
}
|
|
269
|
+
await atomicFs.writeTextAtomic(real, text, opts);
|
|
259
270
|
const stat = await fsp.stat(real);
|
|
260
271
|
return { ok: true, mtimeMs: stat.mtimeMs };
|
|
261
272
|
}
|
|
@@ -296,16 +307,7 @@ function writeJsonSync(abs, data, opts = {}) {
|
|
|
296
307
|
const real = validatePath(expandHome(abs));
|
|
297
308
|
validateWrite(real);
|
|
298
309
|
assertOpsWrite(real, opts.writer);
|
|
299
|
-
|
|
300
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
301
|
-
const tmp = `${real}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
302
|
-
try {
|
|
303
|
-
fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
304
|
-
fs.renameSync(tmp, real);
|
|
305
|
-
} catch (e) {
|
|
306
|
-
try { fs.unlinkSync(tmp); } catch { /* tmp never created or already gone */ }
|
|
307
|
-
throw e;
|
|
308
|
-
}
|
|
310
|
+
atomicFs.writeJsonAtomicSync(real, data, opts);
|
|
309
311
|
const stat = fs.statSync(real);
|
|
310
312
|
return { ok: true, mtimeMs: stat.mtimeMs };
|
|
311
313
|
}
|
|
@@ -510,4 +512,5 @@ module.exports = {
|
|
|
510
512
|
registerPromptSessionsRoot,
|
|
511
513
|
validatePath,
|
|
512
514
|
validateWrite,
|
|
515
|
+
realResolve,
|
|
513
516
|
};
|
package/src/main/docEdit.cjs
CHANGED
|
@@ -18,6 +18,7 @@ const { ipcMain } = require('electron');
|
|
|
18
18
|
const { spawn } = require('node:child_process');
|
|
19
19
|
const crypto = require('node:crypto');
|
|
20
20
|
const { resolveClaudeBin, claudeSpawnTarget } = require('./lib/claudeBin.cjs');
|
|
21
|
+
const { headlessPermissionArgs, ensureCliCapsProbed } = require('./lib/claudeCliCaps.cjs');
|
|
21
22
|
const { withProcRole } = require('./lib/cleanEnv.cjs');
|
|
22
23
|
const { extractJson } = require('./lib/extractJson.cjs');
|
|
23
24
|
const { assertInsideHome } = require('./lib/insideHome.cjs');
|
|
@@ -86,7 +87,8 @@ function parseDocEdit(rawStdout) {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
/** Spawn `claude -p`, capture stdout. Resolves {ok, out, err, error} — never throws. */
|
|
89
|
-
function runClaude(prompt, { model = 'sonnet', timeoutMs = 90_000, systemPrompt = null } = {}) {
|
|
90
|
+
async function runClaude(prompt, { model = 'sonnet', timeoutMs = 90_000, systemPrompt = null } = {}) {
|
|
91
|
+
await ensureCliCapsProbed();
|
|
90
92
|
return new Promise((resolve) => {
|
|
91
93
|
let bin;
|
|
92
94
|
try { bin = resolveClaudeBin(); } catch (e) { resolve({ ok: false, error: `claude not found: ${e?.message}` }); return; }
|
|
@@ -94,6 +96,7 @@ function runClaude(prompt, { model = 'sonnet', timeoutMs = 90_000, systemPrompt
|
|
|
94
96
|
'-p', prompt,
|
|
95
97
|
'--model', model,
|
|
96
98
|
'--dangerously-skip-permissions',
|
|
99
|
+
...headlessPermissionArgs(),
|
|
97
100
|
'--output-format', 'text',
|
|
98
101
|
];
|
|
99
102
|
if (systemPrompt) args.push('--append-system-prompt', systemPrompt);
|
package/src/main/files.cjs
CHANGED
|
@@ -22,6 +22,7 @@ const os = require('node:os');
|
|
|
22
22
|
const { z } = require('zod');
|
|
23
23
|
const { assertInsideHome } = require('./lib/insideHome.cjs');
|
|
24
24
|
const { expandHome } = require('./lib/expandHome.cjs');
|
|
25
|
+
const atomicFs = require('./lib/atomicFs.cjs');
|
|
25
26
|
const { schemas } = require('./ipcSchemas.cjs');
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -163,11 +164,7 @@ async function writeFile(filePath, content) {
|
|
|
163
164
|
return { ok: false, error: e.message };
|
|
164
165
|
}
|
|
165
166
|
try {
|
|
166
|
-
|
|
167
|
-
await fsp.mkdir(dir, { recursive: true });
|
|
168
|
-
const tmp = `${resolved}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
169
|
-
await fsp.writeFile(tmp, content, 'utf8');
|
|
170
|
-
await fsp.rename(tmp, resolved);
|
|
167
|
+
await atomicFs.writeTextAtomic(resolved, content);
|
|
171
168
|
return { ok: true, error: null };
|
|
172
169
|
} catch (e) {
|
|
173
170
|
return { ok: false, error: e.message };
|
package/src/main/health.cjs
CHANGED
|
@@ -815,7 +815,7 @@ async function check(opts = {}) {
|
|
|
815
815
|
|
|
816
816
|
// 1.7. Check test infrastructure exists.
|
|
817
817
|
const hasPlaywright = fs.existsSync(path.join(PROJECT_ROOT, 'playwright.config.ts'));
|
|
818
|
-
const hasE2E = fs.existsSync(path.join(PROJECT_ROOT, 'e2e'));
|
|
818
|
+
const hasE2E = fs.existsSync(path.join(PROJECT_ROOT, 'tests', 'e2e'));
|
|
819
819
|
status.components.test_infrastructure = {
|
|
820
820
|
ok: hasPlaywright && hasE2E,
|
|
821
821
|
playwright: hasPlaywright,
|