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
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* broadcastCoalescer.test.cjs — unit tests for src/main/lib/broadcastCoalescer.cjs,
|
|
3
|
-
* the trailing-edge debounce used by scheduler.cjs's broadcast().
|
|
4
|
-
*
|
|
5
|
-
* Run: timeout 300 npx vitest run src/main/__tests__/broadcastCoalescer.test.cjs
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use strict';
|
|
9
|
-
|
|
10
|
-
import { test, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
11
|
-
|
|
12
|
-
const { createBroadcastCoalescer } = require('../lib/broadcastCoalescer.cjs');
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
vi.useFakeTimers();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
vi.useRealTimers();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
function makeCoalescer(delayMs = 200) {
|
|
23
|
-
const sent = [];
|
|
24
|
-
let counter = 0;
|
|
25
|
-
const getPayload = vi.fn(() => `state-${counter}`);
|
|
26
|
-
const send = vi.fn((payload) => sent.push(payload));
|
|
27
|
-
const coalescer = createBroadcastCoalescer({ delayMs, send, getPayload });
|
|
28
|
-
return {
|
|
29
|
-
coalescer,
|
|
30
|
-
sent,
|
|
31
|
-
send,
|
|
32
|
-
getPayload,
|
|
33
|
-
bump: () => { counter += 1; },
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
test('5 rapid schedule() calls within the window produce exactly 1 send', async () => {
|
|
38
|
-
const { coalescer, sent, bump } = makeCoalescer(200);
|
|
39
|
-
|
|
40
|
-
bump(); coalescer.schedule();
|
|
41
|
-
bump(); coalescer.schedule();
|
|
42
|
-
bump(); coalescer.schedule();
|
|
43
|
-
bump(); coalescer.schedule();
|
|
44
|
-
bump(); coalescer.schedule();
|
|
45
|
-
|
|
46
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
47
|
-
|
|
48
|
-
expect(sent.length).toBe(1);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('the trailing send reflects the LATEST state, not the state at the first schedule() call', async () => {
|
|
52
|
-
const { coalescer, sent, bump } = makeCoalescer(200);
|
|
53
|
-
|
|
54
|
-
bump(); // state-1
|
|
55
|
-
coalescer.schedule();
|
|
56
|
-
bump(); // state-2
|
|
57
|
-
coalescer.schedule(); // no-op — timer already armed
|
|
58
|
-
bump(); // state-3
|
|
59
|
-
coalescer.schedule(); // no-op
|
|
60
|
-
|
|
61
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
62
|
-
|
|
63
|
-
expect(sent).toEqual(['state-3']);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('flush() cancels the pending timer and sends immediately with the current payload', async () => {
|
|
67
|
-
const { coalescer, sent, bump } = makeCoalescer(200);
|
|
68
|
-
|
|
69
|
-
bump();
|
|
70
|
-
coalescer.schedule();
|
|
71
|
-
|
|
72
|
-
// Flush before the 200ms window elapses.
|
|
73
|
-
await vi.advanceTimersByTimeAsync(50);
|
|
74
|
-
await coalescer.flush();
|
|
75
|
-
|
|
76
|
-
expect(sent).toEqual(['state-1']);
|
|
77
|
-
|
|
78
|
-
// The window's original timer must not fire a second, stale send.
|
|
79
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
80
|
-
expect(sent).toEqual(['state-1']);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('a schedule() call after a quiet period still arrives (not dropped)', async () => {
|
|
84
|
-
const { coalescer, sent, bump } = makeCoalescer(200);
|
|
85
|
-
|
|
86
|
-
bump();
|
|
87
|
-
coalescer.schedule();
|
|
88
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
89
|
-
expect(sent).toEqual(['state-1']);
|
|
90
|
-
|
|
91
|
-
bump();
|
|
92
|
-
coalescer.schedule();
|
|
93
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
94
|
-
expect(sent).toEqual(['state-1', 'state-2']);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('flush() with no pending timer still sends (no-arm case)', async () => {
|
|
98
|
-
const { coalescer, sent, bump } = makeCoalescer(200);
|
|
99
|
-
bump();
|
|
100
|
-
await coalescer.flush();
|
|
101
|
-
expect(sent).toEqual(['state-1']);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test('a getPayload() that throws does not wedge the coalescer — the next schedule() still sends', async () => {
|
|
105
|
-
const sent = [];
|
|
106
|
-
const send = vi.fn((payload) => sent.push(payload));
|
|
107
|
-
const getPayload = vi.fn()
|
|
108
|
-
.mockRejectedValueOnce(new Error('boom'))
|
|
109
|
-
.mockResolvedValue('state-recovered');
|
|
110
|
-
const coalescer = createBroadcastCoalescer({ delayMs: 200, send, getPayload });
|
|
111
|
-
|
|
112
|
-
coalescer.schedule();
|
|
113
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
114
|
-
expect(sent).toEqual([]);
|
|
115
|
-
|
|
116
|
-
coalescer.schedule();
|
|
117
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
118
|
-
expect(sent).toEqual(['state-recovered']);
|
|
119
|
-
expect(getPayload).toHaveBeenCalledTimes(2);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
console.log('broadcastCoalescer tests: PASS');
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chat-cancel-terminal.test.cjs — regression for the "stuck thinking" hang.
|
|
3
|
-
*
|
|
4
|
-
* Bug (2026-07-05): cancelling an active chat run SIGTERM'd the child, but the
|
|
5
|
-
* exit handler's `if (!gotResult && !killed)` guard skipped every broadcast
|
|
6
|
-
* because `killed === true`. No terminal IPC event ever reached the renderer,
|
|
7
|
-
* so the chat store stayed `running:true` forever — disabled textarea, endless
|
|
8
|
-
* "running…" spinner, unresponsive chat UI.
|
|
9
|
-
*
|
|
10
|
-
* Fix: every run emits EXACTLY ONE terminal event (complete/needs-input/error),
|
|
11
|
-
* and the exit path emits a fallback `chat:run:error` when a run settled
|
|
12
|
-
* without one (cancel, crash, silent exit). This test drives the REAL spawn
|
|
13
|
-
* path (via SM_CLAUDE_BIN pointing at a stub process) and asserts a terminal
|
|
14
|
-
* event is broadcast on cancel.
|
|
15
|
-
*
|
|
16
|
-
* Run: timeout 300 npx vitest run src/main/__tests__/chat-cancel-terminal.test.cjs
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
'use strict';
|
|
20
|
-
|
|
21
|
-
delete process.env.SM_CHAT_CONCURRENCY;
|
|
22
|
-
|
|
23
|
-
import { test, afterAll } from 'vitest';
|
|
24
|
-
const assert = require('node:assert/strict');
|
|
25
|
-
const fs = require('node:fs');
|
|
26
|
-
const os = require('node:os');
|
|
27
|
-
const path = require('node:path');
|
|
28
|
-
|
|
29
|
-
// A stub "claude" that ignores stdin/args and stays alive until killed —
|
|
30
|
-
// mimics a long-running headless run so cancel() has something to SIGTERM.
|
|
31
|
-
// Shebang + chmod makes it directly spawnable as a single executable (spawn
|
|
32
|
-
// does not split a path on spaces, so SM_CLAUDE_BIN must be one binary).
|
|
33
|
-
const stubPath = require('../../../tests/helpers/claudeStub.cjs').writeClaudeStub({
|
|
34
|
-
body: 'setInterval(() => {}, 1000);',
|
|
35
|
-
});
|
|
36
|
-
process.env.SM_CLAUDE_BIN = stubPath;
|
|
37
|
-
|
|
38
|
-
const cr = require('../chatRunner.cjs');
|
|
39
|
-
|
|
40
|
-
// Scratch project dir under os.tmpdir() — never the real repo root (opsErrorLog would pollute it).
|
|
41
|
-
const scratchCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-chat-cwd-'));
|
|
42
|
-
|
|
43
|
-
const tick = () => new Promise((r) => setImmediate(r));
|
|
44
|
-
|
|
45
|
-
test('cancelling an ACTIVE run broadcasts a terminal event (unsticks the UI)', async () => {
|
|
46
|
-
const events = [];
|
|
47
|
-
// Fake BrowserWindow that captures every broadcast.
|
|
48
|
-
cr.attachWindow({
|
|
49
|
-
isDestroyed: () => false,
|
|
50
|
-
webContents: {
|
|
51
|
-
isDestroyed: () => false,
|
|
52
|
-
send: (channel, payload) => events.push({ channel, payload }),
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
cr.run({ tabId: 'T', sessionId: 'S', prompt: 'hello', cwd: scratchCwd, resume: false });
|
|
57
|
-
|
|
58
|
-
// Let the spawn happen and started event fire.
|
|
59
|
-
for (let i = 0; i < 6; i++) await tick();
|
|
60
|
-
assert.ok(
|
|
61
|
-
events.some((e) => e.channel === 'chat:run:started'),
|
|
62
|
-
'started event should fire once the run launches',
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
cr.cancel('T');
|
|
66
|
-
|
|
67
|
-
// Wait for SIGTERM → child exit → fallback terminal broadcast.
|
|
68
|
-
for (let i = 0; i < 40 && !events.some((e) => isTerminal(e.channel)); i++) {
|
|
69
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const terminal = events.filter((e) => isTerminal(e.channel));
|
|
73
|
-
assert.equal(terminal.length, 1, 'exactly one terminal event is emitted');
|
|
74
|
-
assert.equal(terminal[0].channel, 'chat:run:error', 'cancel surfaces as an error turn');
|
|
75
|
-
assert.match(terminal[0].payload.message, /cancel/i, 'message names the cancellation');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('cancel() resolves only AFTER the terminal broadcast fires, not immediately on SIGTERM (PRD 718)', async () => {
|
|
79
|
-
// Order-of-events assertion (not timing-based — a real SIGTERM can be fast
|
|
80
|
-
// enough on a lightweight stub child that a fixed-delay race would flake).
|
|
81
|
-
const order = [];
|
|
82
|
-
cr.attachWindow({
|
|
83
|
-
isDestroyed: () => false,
|
|
84
|
-
webContents: {
|
|
85
|
-
isDestroyed: () => false,
|
|
86
|
-
send: (channel, payload) => {
|
|
87
|
-
if (isTerminal(channel) && payload.tabId === 'T2') order.push('terminal');
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
cr.run({ tabId: 'T2', sessionId: 'S2', prompt: 'hello', cwd: scratchCwd, resume: false });
|
|
93
|
-
|
|
94
|
-
for (let i = 0; i < 6; i++) await tick();
|
|
95
|
-
|
|
96
|
-
await cr.cancel('T2').then(() => order.push('resolved'));
|
|
97
|
-
|
|
98
|
-
assert.deepEqual(order, ['terminal', 'resolved'], 'cancel() resolves strictly after the terminal broadcast');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test('cancel() on a tab with no in-flight or waiting run resolves immediately (no-op)', async () => {
|
|
102
|
-
cr.attachWindow({
|
|
103
|
-
isDestroyed: () => false,
|
|
104
|
-
webContents: { isDestroyed: () => false, send: () => {} },
|
|
105
|
-
});
|
|
106
|
-
await cr.cancel('no-such-tab'); // must resolve, not hang
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
function isTerminal(channel) {
|
|
110
|
-
return (
|
|
111
|
-
channel === 'chat:run:complete' ||
|
|
112
|
-
channel === 'chat:run:needs-input' ||
|
|
113
|
-
channel === 'chat:run:error'
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
afterAll(() => {
|
|
118
|
-
try { fs.unlinkSync(stubPath); } catch { /* already gone */ }
|
|
119
|
-
delete process.env.SM_CLAUDE_BIN;
|
|
120
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chat-dead-channels.test.cjs — regression guard for the removed
|
|
3
|
-
* chat:probe-context / chat:context-usage channels (PRD 897).
|
|
4
|
-
*
|
|
5
|
-
* These IPC channels were deliberately deleted (handler, broadcast, preload
|
|
6
|
-
* and zod schema all removed) rather than left half-wired. This test walks
|
|
7
|
-
* the source tree and fails if either literal string reappears anywhere
|
|
8
|
-
* under src/main, src/preload, or src/renderer — such a reintroduction must
|
|
9
|
-
* be wired end-to-end (handler + preload + zod schema + broadcast) or not
|
|
10
|
-
* added at all.
|
|
11
|
-
*
|
|
12
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/chat-dead-channels.test.cjs
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
const fs = require('fs');
|
|
18
|
-
const path = require('path');
|
|
19
|
-
|
|
20
|
-
import { test, expect } from 'vitest';
|
|
21
|
-
|
|
22
|
-
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
23
|
-
const SCAN_DIRS = ['src/main', 'src/preload', 'src/renderer'];
|
|
24
|
-
const FORBIDDEN_STRINGS = ['chat:probe-context', 'chat:context-usage'];
|
|
25
|
-
const SELF_PATH = path.resolve(__filename);
|
|
26
|
-
|
|
27
|
-
function walk(dir, files) {
|
|
28
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
29
|
-
if (entry.name === 'node_modules') continue;
|
|
30
|
-
if (entry.isSymbolicLink()) continue;
|
|
31
|
-
const full = path.join(dir, entry.name);
|
|
32
|
-
if (entry.isDirectory()) {
|
|
33
|
-
walk(full, files);
|
|
34
|
-
} else {
|
|
35
|
-
files.push(full);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
test('chat:probe-context / chat:context-usage channels stay removed', () => {
|
|
41
|
-
const files = [];
|
|
42
|
-
for (const dir of SCAN_DIRS) {
|
|
43
|
-
walk(path.join(REPO_ROOT, dir), files);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const hits = [];
|
|
47
|
-
for (const file of files) {
|
|
48
|
-
if (path.resolve(file) === SELF_PATH) continue;
|
|
49
|
-
const contents = fs.readFileSync(file, 'utf8');
|
|
50
|
-
for (const needle of FORBIDDEN_STRINGS) {
|
|
51
|
-
if (contents.includes(needle)) {
|
|
52
|
-
hits.push(`${path.relative(REPO_ROOT, file)}: contains "${needle}"`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
expect(
|
|
58
|
-
hits,
|
|
59
|
-
'chat:probe-context / chat:context-usage were deliberately removed as a dead/half-wired ' +
|
|
60
|
-
'channel (PRD 897). If reintroducing this feature, wire it end-to-end (handler, preload, ' +
|
|
61
|
-
'zod schema, broadcast) in the same change — do not add just one side.\n' + hits.join('\n'),
|
|
62
|
-
).toEqual([]);
|
|
63
|
-
});
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chat-exit-close-race.test.cjs — regression for the exit/close race that
|
|
3
|
-
* silently dropped a pure-text-only final turn (PRD 716).
|
|
4
|
-
*
|
|
5
|
-
* Bug: the terminal-event fallback was wired to `child.on('exit', ...)`
|
|
6
|
-
* instead of `child.on('close', ...)`. Node only guarantees all buffered
|
|
7
|
-
* stdout 'data' events have been delivered by 'close', not 'exit' — 'exit'
|
|
8
|
-
* can fire before the final stdout chunk (last assistant text + terminating
|
|
9
|
-
* `result` line) reaches the parent's 'data' handler. When that happened,
|
|
10
|
-
* the exit fallback ran first, set the one-shot terminalSent latch, and
|
|
11
|
-
* broadcast a misleading chat:run:error. The real result line then parsed
|
|
12
|
-
* moments later, but emitTerminal silently no-op'd and the genuine
|
|
13
|
-
* chat:run:complete was dropped.
|
|
14
|
-
*
|
|
15
|
-
* Fix: use `child.on('close', ...)` for the fallback so it only fires once
|
|
16
|
-
* Node guarantees stdout is fully drained — a real result event that arrives
|
|
17
|
-
* (even "late", right up against process exit) always wins.
|
|
18
|
-
*
|
|
19
|
-
* This test mocks node:child_process.spawn so it can deterministically
|
|
20
|
-
* reproduce the exact race ordering (exit fires, THEN the final stdout chunk
|
|
21
|
-
* arrives, THEN close fires) rather than relying on real OS/pipe timing,
|
|
22
|
-
* which is not reliably reproducible from a real child process.
|
|
23
|
-
*
|
|
24
|
-
* Run: timeout 300 npx vitest run src/main/__tests__/chat-exit-close-race.test.cjs
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
'use strict';
|
|
28
|
-
|
|
29
|
-
delete process.env.SM_CHAT_CONCURRENCY;
|
|
30
|
-
|
|
31
|
-
import { test, afterAll } from 'vitest';
|
|
32
|
-
const assert = require('node:assert/strict');
|
|
33
|
-
const EventEmitter = require('node:events');
|
|
34
|
-
const cp = require('node:child_process');
|
|
35
|
-
const fs = require('node:fs');
|
|
36
|
-
const os = require('node:os');
|
|
37
|
-
const path = require('node:path');
|
|
38
|
-
|
|
39
|
-
// Replace spawn BEFORE chatRunner.cjs is first required, so the module's
|
|
40
|
-
// top-level `const { spawn } = require('node:child_process')` destructuring
|
|
41
|
-
// captures this mock instead of the real implementation.
|
|
42
|
-
const originalSpawn = cp.spawn;
|
|
43
|
-
let nextChild = null;
|
|
44
|
-
cp.spawn = () => {
|
|
45
|
-
const child = new EventEmitter();
|
|
46
|
-
child.stdout = new EventEmitter();
|
|
47
|
-
child.stderr = new EventEmitter();
|
|
48
|
-
child.pid = 424242;
|
|
49
|
-
child.kill = () => {};
|
|
50
|
-
nextChild = child;
|
|
51
|
-
return child;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const cr = require('../chatRunner.cjs');
|
|
55
|
-
|
|
56
|
-
// Scratch project dir under os.tmpdir() — never the real repo root (opsErrorLog would pollute it).
|
|
57
|
-
const scratchCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-chat-cwd-'));
|
|
58
|
-
|
|
59
|
-
const tick = () => new Promise((r) => setImmediate(r));
|
|
60
|
-
|
|
61
|
-
test('a final-text-only turn whose stdout chunk lands after exit still surfaces chat:run:complete', async () => {
|
|
62
|
-
nextChild = null;
|
|
63
|
-
const events = [];
|
|
64
|
-
cr.attachWindow({
|
|
65
|
-
isDestroyed: () => false,
|
|
66
|
-
webContents: {
|
|
67
|
-
isDestroyed: () => false,
|
|
68
|
-
send: (channel, payload) => events.push({ channel, payload }),
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
cr.run({ tabId: 'T2', sessionId: 'S2', prompt: 'show me a sample post', cwd: scratchCwd, resume: false });
|
|
73
|
-
|
|
74
|
-
for (let i = 0; i < 20 && !nextChild; i++) await tick();
|
|
75
|
-
const child = nextChild;
|
|
76
|
-
assert.ok(child, 'spawn should have been invoked');
|
|
77
|
-
|
|
78
|
-
const text = 'Here is your sample post, all in one go.';
|
|
79
|
-
const lines =
|
|
80
|
-
JSON.stringify({ type: 'assistant', message: { content: [{ type: 'text', text }] } }) +
|
|
81
|
-
'\n' +
|
|
82
|
-
JSON.stringify({ type: 'result', subtype: 'success', result: text }) +
|
|
83
|
-
'\n';
|
|
84
|
-
|
|
85
|
-
// The exact race: 'exit' fires first (process already gone from the OS's
|
|
86
|
-
// perspective), the final stdout chunk is delivered to the 'data' handler
|
|
87
|
-
// only after that, and 'close' — which Node guarantees fires after all
|
|
88
|
-
// stdout data has been delivered — fires last.
|
|
89
|
-
child.emit('exit', 0, null);
|
|
90
|
-
child.stdout.emit('data', Buffer.from(lines));
|
|
91
|
-
child.emit('close', 0, null);
|
|
92
|
-
|
|
93
|
-
await tick();
|
|
94
|
-
await tick();
|
|
95
|
-
|
|
96
|
-
const terminal = events.filter((e) => isTerminal(e.channel));
|
|
97
|
-
assert.equal(terminal.length, 1, 'exactly one terminal event is emitted');
|
|
98
|
-
assert.equal(
|
|
99
|
-
terminal[0].channel,
|
|
100
|
-
'chat:run:complete',
|
|
101
|
-
'the real result event must win over the generic exit-fallback error',
|
|
102
|
-
);
|
|
103
|
-
assert.equal(terminal[0].payload.finalMessage, text);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('a crashed process with no result event ever emitted still fires the fallback chat:run:error', async () => {
|
|
107
|
-
nextChild = null;
|
|
108
|
-
const events = [];
|
|
109
|
-
cr.attachWindow({
|
|
110
|
-
isDestroyed: () => false,
|
|
111
|
-
webContents: {
|
|
112
|
-
isDestroyed: () => false,
|
|
113
|
-
send: (channel, payload) => events.push({ channel, payload }),
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
cr.run({ tabId: 'T3', sessionId: 'S3', prompt: 'anything', cwd: scratchCwd, resume: false });
|
|
118
|
-
|
|
119
|
-
for (let i = 0; i < 20 && !nextChild; i++) await tick();
|
|
120
|
-
const child = nextChild;
|
|
121
|
-
assert.ok(child, 'spawn should have been invoked');
|
|
122
|
-
|
|
123
|
-
// Crashes with no stdout at all — 'close' is the only event that fires.
|
|
124
|
-
child.emit('close', 1, null);
|
|
125
|
-
|
|
126
|
-
await tick();
|
|
127
|
-
await tick();
|
|
128
|
-
|
|
129
|
-
const terminal = events.filter((e) => isTerminal(e.channel));
|
|
130
|
-
assert.equal(terminal.length, 1, 'exactly one terminal event is emitted');
|
|
131
|
-
assert.equal(terminal[0].channel, 'chat:run:error', 'a crash with no result surfaces as an error turn');
|
|
132
|
-
assert.match(terminal[0].payload.message, /process exited without a result event/);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
function isTerminal(channel) {
|
|
136
|
-
return (
|
|
137
|
-
channel === 'chat:run:complete' ||
|
|
138
|
-
channel === 'chat:run:needs-input' ||
|
|
139
|
-
channel === 'chat:run:error'
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
afterAll(() => {
|
|
144
|
-
cp.spawn = originalSpawn;
|
|
145
|
-
delete process.env.SM_CHAT_CONCURRENCY;
|
|
146
|
-
});
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chat-mcp-consent-notice.test.cjs — regression for the headless MCP-consent
|
|
3
|
-
* hang: a chat run with stdin closed can never answer an MCP server's own
|
|
4
|
-
* interactive consent flow (e.g. `/design consent`). This drives the real
|
|
5
|
-
* stdout parser with a synthetic stream-json `tool_result` denial line and
|
|
6
|
-
* asserts a `chat:run:notice` event is broadcast — informational, not a
|
|
7
|
-
* terminal event.
|
|
8
|
-
*
|
|
9
|
-
* Run: timeout 300 npx vitest run src/main/__tests__/chat-mcp-consent-notice.test.cjs
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
delete process.env.SM_CHAT_CONCURRENCY;
|
|
15
|
-
|
|
16
|
-
import { test } from 'vitest';
|
|
17
|
-
const assert = require('node:assert/strict');
|
|
18
|
-
const fs = require('node:fs');
|
|
19
|
-
const os = require('node:os');
|
|
20
|
-
const path = require('node:path');
|
|
21
|
-
|
|
22
|
-
// Scratch project dir under os.tmpdir() — never the real repo root (opsErrorLog would pollute it).
|
|
23
|
-
const scratchCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-chat-cwd-'));
|
|
24
|
-
const claudeStub = require('../../../tests/helpers/claudeStub.cjs');
|
|
25
|
-
|
|
26
|
-
function writeStub(lines) {
|
|
27
|
-
const body = lines.map((l) => `process.stdout.write(${JSON.stringify(JSON.stringify(l))} + "\\n");`).join('\n');
|
|
28
|
-
return claudeStub.writeClaudeStub({ body: `${body}\nprocess.exit(0);` });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function isTerminal(channel) {
|
|
32
|
-
return (
|
|
33
|
-
channel === 'chat:run:complete' ||
|
|
34
|
-
channel === 'chat:run:needs-input' ||
|
|
35
|
-
channel === 'chat:run:error'
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
test('MCP consent denial in a tool_result surfaces a chat:run:notice event', async () => {
|
|
40
|
-
const stubPath = writeStub([
|
|
41
|
-
{
|
|
42
|
-
type: 'user',
|
|
43
|
-
message: {
|
|
44
|
-
content: [
|
|
45
|
-
{
|
|
46
|
-
type: 'tool_result',
|
|
47
|
-
tool_use_id: 'toolu_1',
|
|
48
|
-
is_error: true,
|
|
49
|
-
content: [
|
|
50
|
-
{
|
|
51
|
-
type: 'text',
|
|
52
|
-
text:
|
|
53
|
-
"Claude Design: write_files The user hasn't granted this — run /design consent " +
|
|
54
|
-
"to grant it (it can't be approved automatically in this permission mode).",
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
{ type: 'result', subtype: 'success', result: 'done anyway' },
|
|
62
|
-
]);
|
|
63
|
-
process.env.SM_CLAUDE_BIN = stubPath;
|
|
64
|
-
delete require.cache[require.resolve('../chatRunner.cjs')];
|
|
65
|
-
const cr = require('../chatRunner.cjs');
|
|
66
|
-
|
|
67
|
-
const events = [];
|
|
68
|
-
cr.attachWindow({
|
|
69
|
-
isDestroyed: () => false,
|
|
70
|
-
webContents: {
|
|
71
|
-
isDestroyed: () => false,
|
|
72
|
-
send: (channel, payload) => events.push({ channel, payload }),
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
cr.run({ tabId: 'T-notice', sessionId: 'S-notice', prompt: 'do a design thing', cwd: scratchCwd, resume: false });
|
|
77
|
-
|
|
78
|
-
for (let i = 0; i < 60 && !events.some((e) => isTerminal(e.channel)); i++) {
|
|
79
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const notice = events.find((e) => e.channel === 'chat:run:notice');
|
|
83
|
-
assert.ok(notice, 'chat:run:notice should be broadcast');
|
|
84
|
-
assert.match(notice.payload.message, /consent/i, 'message mentions consent');
|
|
85
|
-
assert.match(notice.payload.message, /terminal/i, 'message mentions the raw terminal session');
|
|
86
|
-
|
|
87
|
-
// Notice is informational, not terminal — the normal result still fires.
|
|
88
|
-
const terminal = events.filter((e) => isTerminal(e.channel));
|
|
89
|
-
assert.equal(terminal.length, 1, 'exactly one terminal event still fires');
|
|
90
|
-
assert.equal(terminal[0].channel, 'chat:run:complete');
|
|
91
|
-
|
|
92
|
-
try { fs.unlinkSync(stubPath); } catch { /* already gone */ }
|
|
93
|
-
delete process.env.SM_CLAUDE_BIN;
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('a normal tool_result with no consent marker does not fire chat:run:notice', async () => {
|
|
97
|
-
const stubPath = writeStub([
|
|
98
|
-
{
|
|
99
|
-
type: 'user',
|
|
100
|
-
message: {
|
|
101
|
-
content: [
|
|
102
|
-
{
|
|
103
|
-
type: 'tool_result',
|
|
104
|
-
tool_use_id: 'toolu_2',
|
|
105
|
-
is_error: false,
|
|
106
|
-
content: [{ type: 'text', text: 'Wrote 3 files successfully.' }],
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
{ type: 'result', subtype: 'success', result: 'all good' },
|
|
112
|
-
]);
|
|
113
|
-
process.env.SM_CLAUDE_BIN = stubPath;
|
|
114
|
-
delete require.cache[require.resolve('../chatRunner.cjs')];
|
|
115
|
-
const cr = require('../chatRunner.cjs');
|
|
116
|
-
|
|
117
|
-
const events = [];
|
|
118
|
-
cr.attachWindow({
|
|
119
|
-
isDestroyed: () => false,
|
|
120
|
-
webContents: {
|
|
121
|
-
isDestroyed: () => false,
|
|
122
|
-
send: (channel, payload) => events.push({ channel, payload }),
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
cr.run({ tabId: 'T-clean', sessionId: 'S-clean', prompt: 'do a normal thing', cwd: scratchCwd, resume: false });
|
|
127
|
-
|
|
128
|
-
for (let i = 0; i < 60 && !events.some((e) => isTerminal(e.channel)); i++) {
|
|
129
|
-
await new Promise((r) => setTimeout(r, 25));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
assert.ok(
|
|
133
|
-
!events.some((e) => e.channel === 'chat:run:notice'),
|
|
134
|
-
'no chat:run:notice should fire for a clean tool_result (no false positive)',
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
try { fs.unlinkSync(stubPath); } catch { /* already gone */ }
|
|
138
|
-
delete process.env.SM_CLAUDE_BIN;
|
|
139
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* chat-preamble-anchors.test.cjs — drift guard between chatRunner's injected
|
|
3
|
-
* instruction blocks and the renderer's splitter that hides them.
|
|
4
|
-
*
|
|
5
|
-
* `src/renderer/lib/promptPreamble.ts` anchors each block on its FIRST and
|
|
6
|
-
* LAST sentence only, because it cannot import this main-process .cjs. That
|
|
7
|
-
* indirection is safe ONLY while those anchors still bracket the real text —
|
|
8
|
-
* so this test composes the exact `fullPrompt` chatRunner builds and asserts
|
|
9
|
-
* the splitter recovers the human's words exactly. Reword either block's
|
|
10
|
-
* opening or closing sentence and this fails here, loudly, instead of the
|
|
11
|
-
* boilerplate silently reappearing in every user bubble.
|
|
12
|
-
*
|
|
13
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/chat-preamble-anchors.test.cjs
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
const path = require('path');
|
|
19
|
-
|
|
20
|
-
import { test, expect } from 'vitest';
|
|
21
|
-
|
|
22
|
-
const { STOP_SIGNAL_INSTRUCTION, CHAT_MODE_TRUTH_INSTRUCTION } = require('../chatRunner.cjs');
|
|
23
|
-
|
|
24
|
-
const HUMAN = 'Review the Alpaca limits and report back what we can trade for free.';
|
|
25
|
-
|
|
26
|
-
async function loadSplitter() {
|
|
27
|
-
const mod = await import(
|
|
28
|
-
/* @vite-ignore */ path.resolve(__dirname, '..', '..', 'renderer', 'lib', 'promptPreamble.ts')
|
|
29
|
-
);
|
|
30
|
-
return mod;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
test('the real fullPrompt splits back into exactly the human’s words', async () => {
|
|
34
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
35
|
-
// Mirrors chatRunner's own composition at its `-p` call site.
|
|
36
|
-
const fullPrompt = STOP_SIGNAL_INSTRUCTION + CHAT_MODE_TRUTH_INSTRUCTION + HUMAN;
|
|
37
|
-
|
|
38
|
-
const split = splitInjectedPreamble(fullPrompt);
|
|
39
|
-
expect(split.body).toBe(HUMAN);
|
|
40
|
-
expect(split.blockKeys).toEqual(['stop-signal', 'chat-mode-truth']);
|
|
41
|
-
expect(split.preamble).toBeTruthy();
|
|
42
|
-
// Nothing is invented or lost: preamble + body reconstitute the input.
|
|
43
|
-
expect(split.preamble.length + split.body.length).toBeLessThanOrEqual(fullPrompt.length);
|
|
44
|
-
expect(fullPrompt.startsWith(split.preamble)).toBe(true);
|
|
45
|
-
expect(fullPrompt.endsWith(split.body)).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('each block strips independently, so one being absent still works', async () => {
|
|
49
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
50
|
-
|
|
51
|
-
const onlyStop = splitInjectedPreamble(STOP_SIGNAL_INSTRUCTION + HUMAN);
|
|
52
|
-
expect(onlyStop.body).toBe(HUMAN);
|
|
53
|
-
expect(onlyStop.blockKeys).toEqual(['stop-signal']);
|
|
54
|
-
|
|
55
|
-
const onlyTruth = splitInjectedPreamble(CHAT_MODE_TRUTH_INSTRUCTION + HUMAN);
|
|
56
|
-
expect(onlyTruth.body).toBe(HUMAN);
|
|
57
|
-
expect(onlyTruth.blockKeys).toEqual(['chat-mode-truth']);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('a prompt with no injected blocks is returned untouched', async () => {
|
|
61
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
62
|
-
const split = splitInjectedPreamble(HUMAN);
|
|
63
|
-
expect(split.preamble).toBe(null);
|
|
64
|
-
expect(split.body).toBe(HUMAN);
|
|
65
|
-
expect(split.blockKeys).toEqual([]);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('EDGE: a boilerplate-only prompt is NOT stripped to an empty bubble', async () => {
|
|
69
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
70
|
-
const onlyBoilerplate = STOP_SIGNAL_INSTRUCTION + CHAT_MODE_TRUTH_INSTRUCTION;
|
|
71
|
-
const split = splitInjectedPreamble(onlyBoilerplate);
|
|
72
|
-
expect(split.preamble).toBe(null);
|
|
73
|
-
expect(split.body).toBe(onlyBoilerplate);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('EDGE: a truncated block (opening present, closing missing) is left fully intact', async () => {
|
|
77
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
78
|
-
// Simulates a reworded/cut-off block: better to over-show boilerplate than
|
|
79
|
-
// to guess at a boundary and eat the human's words.
|
|
80
|
-
const truncated = `${STOP_SIGNAL_INSTRUCTION.slice(0, 120)}\n\n${HUMAN}`;
|
|
81
|
-
const split = splitInjectedPreamble(truncated);
|
|
82
|
-
expect(split.preamble).toBe(null);
|
|
83
|
-
expect(split.body).toBe(truncated);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('the two blocks strip in either order', async () => {
|
|
87
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
88
|
-
const reversed = CHAT_MODE_TRUTH_INSTRUCTION + STOP_SIGNAL_INSTRUCTION + HUMAN;
|
|
89
|
-
const split = splitInjectedPreamble(reversed);
|
|
90
|
-
expect(split.body).toBe(HUMAN);
|
|
91
|
-
expect(split.blockKeys).toEqual(['chat-mode-truth', 'stop-signal']);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('EDGE: boilerplate quoted inside the human’s own message is never stripped', async () => {
|
|
95
|
-
const { splitInjectedPreamble } = await loadSplitter();
|
|
96
|
-
const quoting = `Why does chat prepend this?\n\n${STOP_SIGNAL_INSTRUCTION}`;
|
|
97
|
-
const split = splitInjectedPreamble(quoting);
|
|
98
|
-
expect(split.preamble).toBe(null);
|
|
99
|
-
expect(split.body).toBe(quoting);
|
|
100
|
-
});
|