claude-code-session-manager 0.87.0 → 0.88.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 +26 -53
- package/dist/assets/{AgentLibrary-DyLWzZDf.js → AgentLibrary-BZ6IY2g1.js} +1 -1
- package/dist/assets/{DataModel--mISIJ6h.js → DataModel-dAoGAODX.js} +1 -1
- package/dist/assets/{History-C2ahUXTg.js → History-CF157HyX.js} +1 -1
- package/dist/assets/{Hooks-BiC6oyR2.js → Hooks-CCPPipBk.js} +1 -1
- package/dist/assets/{HostBilko-BPleEOld.js → HostBilko-Dlmz2m06.js} +1 -1
- package/dist/assets/{Library-Dc8Qst1R.js → Library-BaXcboWX.js} +1 -1
- package/dist/assets/{ListDetail-DIXh-OLX.js → ListDetail-CoUCzG5S.js} +1 -1
- package/dist/assets/{MarkdownEditor-C90bkLXK.js → MarkdownEditor-DTg3JlOT.js} +1 -1
- package/dist/assets/{McpServers-DqcbLOLZ.js → McpServers-DdjY1sA3.js} +1 -1
- package/dist/assets/{Memory-CW62MXlh.js → Memory-BJ3Jlw0C.js} +1 -1
- package/dist/assets/{Panel-Bw1FhRuF.js → Panel-ygRSgc41.js} +1 -1
- package/dist/assets/{Permissions-BcUC-5y8.js → Permissions-m0KAnccF.js} +1 -1
- package/dist/assets/{Plugins-BnKx9flD.js → Plugins-CJRl6B3Q.js} +2 -2
- package/dist/assets/{ProvenanceBadge-Bw5vNVPT.js → ProvenanceBadge-w8cnlVvW.js} +1 -1
- package/dist/assets/{SaveBar-CWr0O_w-.js → SaveBar-BpyPcUIk.js} +1 -1
- package/dist/assets/{Scheduler-DYdLuUqq.js → Scheduler-D2ppxSfy.js} +7 -7
- package/dist/assets/{ScopeSwitcher-CrBLbg8s.js → ScopeSwitcher-EyuIwt-j.js} +1 -1
- package/dist/assets/{Settings-DluB-vN1.js → Settings-BHSGGFEc.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-CHLSseay.js → SkillReferenceGraph-BNaZ2JCF.js} +1 -1
- package/dist/assets/{Skills-gNdo_HNK.js → Skills-Dl3q75QV.js} +1 -1
- package/dist/assets/{SystemPrompt-Cru05-Ia.js → SystemPrompt-Bg6F-Cyp.js} +1 -1
- package/dist/assets/{TagLibrary-DNHY0xou.js → TagLibrary-BSutflCy.js} +1 -1
- package/dist/assets/{TiptapBody-I4lmbCgP.js → TiptapBody-CXih4xrc.js} +1 -1
- package/dist/assets/{Toggle-bWMHjmRh.js → Toggle-2qtUHhA9.js} +1 -1
- package/dist/assets/{index-fc_JjdxL.js → index-B3emy2oI.js} +356 -356
- package/dist/assets/{index-DV3PorRY.css → index-BHTX4OTc.css} +1 -1
- package/dist/assets/{settingsSchema-BfhtZnGD.js → settingsSchema-CdzxaqwM.js} +1 -1
- package/dist/assets/{whisperWorker-Dbia1OpC.js → whisperWorker-C7ZGQwKg.js} +7 -7
- package/dist/index.html +2 -2
- package/dist/vad/ort-wasm-simd-threaded.asyncify.mjs +106 -110
- package/dist/vad/ort-wasm-simd-threaded.asyncify.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.jsep.mjs +98 -98
- package/dist/vad/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.jspi.mjs +99 -102
- package/dist/vad/ort-wasm-simd-threaded.jspi.wasm +0 -0
- package/dist/vad/ort-wasm-simd-threaded.mjs +46 -46
- package/dist/vad/ort-wasm-simd-threaded.wasm +0 -0
- package/package.json +10 -13
- package/scripts/README.md +59 -0
- package/scripts/audit-ops-hygiene.cjs +350 -0
- package/scripts/hooks/guard-destructive-git.cjs +10 -34
- package/scripts/hooks/guard-inline-implementation.cjs +14 -8
- package/scripts/hooks/guard-prd-writes.cjs +7 -36
- package/scripts/hooks/guard-self-schedule.cjs +175 -0
- package/scripts/ops-sweep.cjs +355 -0
- package/scripts/scheduler-mcp-server.cjs +28 -71
- package/src/main/__tests__/bilkoHost-integration.test.cjs +3 -3
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +6 -9
- package/src/main/__tests__/chat-exit-close-race.test.cjs +3 -3
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +4 -5
- package/src/main/__tests__/chat-queue.test.cjs +2 -2
- package/src/main/__tests__/chat-stop-signal.test.cjs +2 -2
- package/src/main/__tests__/dep-orphan-archive-health.test.cjs +77 -0
- package/src/main/__tests__/dod-batchkey.test.cjs +2 -2
- package/src/main/__tests__/dod-drain-hook.test.cjs +2 -2
- package/src/main/__tests__/dod-report.test.cjs +2 -2
- package/src/main/__tests__/dod-reverify.test.cjs +2 -2
- package/src/main/__tests__/epicMint.test.cjs +2 -2
- package/src/main/__tests__/exchanges.test.cjs +2 -2
- package/src/main/__tests__/extractJson.test.cjs +2 -2
- package/src/main/__tests__/files-reject-credentials.test.cjs +1 -1
- package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +556 -0
- package/src/main/__tests__/health-build-freshness.test.cjs +39 -0
- package/src/main/__tests__/health-delegation-chain.test.cjs +15 -1
- package/src/main/__tests__/health-queue-dispatch.test.cjs +58 -7
- package/src/main/__tests__/health-tick-liveness.test.cjs +11 -3
- package/src/main/__tests__/health-usage-poller.test.cjs +70 -23
- package/src/main/__tests__/historyRollup.test.cjs +2 -2
- package/src/main/__tests__/kg-augment.test.cjs +2 -2
- package/src/main/__tests__/mcpStatus.test.cjs +2 -2
- package/src/main/__tests__/memoryAggregate.test.cjs +1 -1
- package/src/main/__tests__/memoryStale.test.cjs +1 -1
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +25 -1
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +33 -3
- package/src/main/__tests__/prd-group-allocator.test.cjs +2 -2
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +2 -0
- package/src/main/__tests__/prdAdminRoutes.test.cjs +14 -2
- package/src/main/__tests__/prdAuthoringSeed.test.cjs +39 -0
- package/src/main/__tests__/prdLocationsArchived.test.cjs +20 -13
- package/src/main/__tests__/proc-role-env.test.cjs +125 -0
- package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +304 -0
- package/src/main/__tests__/procname-sm-processes.test.cjs +127 -0
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +81 -401
- package/src/main/__tests__/projectPages.test.cjs +63 -149
- package/src/main/__tests__/queue-health-verdict.test.cjs +9 -9
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +117 -20
- package/src/main/__tests__/queueHistory.test.cjs +2 -2
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +38 -3
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +181 -0
- package/src/main/__tests__/runVerify.test.cjs +5 -5
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +3 -3
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +2 -2
- package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +143 -0
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +2 -2
- package/src/main/__tests__/scheduler-autopromote.test.cjs +2 -2
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +3 -5
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +78 -97
- package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +161 -0
- package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +58 -0
- package/src/main/__tests__/scheduler-epic-digest.test.cjs +3 -5
- package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +2 -2
- package/src/main/__tests__/scheduler-gate-shadow.test.cjs +119 -0
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +46 -0
- package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +80 -0
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +25 -18
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +4 -4
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +3 -5
- package/src/main/__tests__/scheduler-looks-done.test.cjs +26 -7
- package/src/main/__tests__/scheduler-manual-pause.test.cjs +118 -0
- package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +26 -3
- package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +17 -2
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +3 -5
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +41 -6
- package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +62 -6
- package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +3 -5
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +23 -4
- package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +100 -0
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +3 -3
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +4 -4
- package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +110 -0
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +81 -1
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +4 -4
- package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +245 -0
- package/src/main/__tests__/scheduler-supervisor-record.test.cjs +81 -0
- package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +2 -2
- package/src/main/__tests__/scheduler-tick-wedge.test.cjs +172 -0
- package/src/main/__tests__/scheduler-transient-failure.test.cjs +2 -2
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +37 -11
- package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +3 -5
- package/src/main/__tests__/usageSingleFlight.test.cjs +157 -0
- package/src/main/__tests__/workTypeLibrary.test.cjs +1 -1
- package/src/main/bilkoHost.cjs +16 -7
- package/src/main/build-info.json +8 -0
- package/src/main/chatRunner.cjs +4 -2
- package/src/main/config.cjs +2 -3
- package/src/main/docEdit.cjs +4 -2
- package/src/main/health.cjs +267 -51
- package/src/main/heapSnapshot.cjs +2 -2
- package/src/main/historyAggregator.cjs +1 -1
- package/src/main/index.cjs +61 -10
- package/src/main/ipcSchemas.cjs +6 -17
- package/src/main/lib/__tests__/auditLog.test.cjs +38 -0
- package/src/main/lib/__tests__/buildIdentity.test.cjs +121 -0
- package/src/main/lib/__tests__/cwdClassify.test.cjs +111 -0
- package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +95 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +1 -1
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +63 -0
- package/src/main/lib/__tests__/gateFixtures.json +20 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +8 -1
- package/src/main/lib/__tests__/instanceLock.test.cjs +93 -7
- package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +78 -0
- package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +11 -0
- package/src/main/lib/__tests__/localAdminHttp.test.cjs +1 -1
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +6 -1
- package/src/main/lib/__tests__/procIdentity.test.cjs +119 -0
- package/src/main/lib/__tests__/procName.test.cjs +92 -0
- package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +67 -0
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +6 -7
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +37 -204
- package/src/main/lib/__tests__/schedulerPaths.test.cjs +226 -0
- package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +94 -0
- package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +56 -0
- package/src/main/lib/__tests__/sessionSlots.test.cjs +45 -0
- package/src/main/lib/__tests__/telemetryBacklog.test.cjs +1 -1
- package/src/main/lib/__tests__/upgradeDrain.test.cjs +130 -0
- package/src/main/lib/__tests__/usageCircuit.test.cjs +61 -0
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +63 -0
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +73 -0
- package/src/main/lib/activeIndexRebuild.cjs +1 -3
- package/src/main/lib/activeSessions.cjs +20 -88
- package/src/main/lib/adoptedRunSupervisor.cjs +136 -0
- package/src/main/lib/agentModelResolve.cjs +33 -1
- package/src/main/lib/agentPersonaSchema.cjs +2 -2
- package/src/main/lib/auditLog.cjs +30 -5
- package/src/main/lib/buildIdentity.cjs +113 -0
- package/src/main/lib/classifyPromptTicket.cjs +3 -2
- package/src/main/lib/claudeBin.cjs +37 -2
- package/src/main/lib/cleanEnv.cjs +27 -1
- package/src/main/lib/credentials.cjs +4 -2
- package/src/main/lib/cwdClassify.cjs +185 -0
- package/src/main/lib/definitionOfDone.cjs +296 -52
- package/src/main/lib/dispatchLoop.cjs +40 -0
- package/src/main/lib/effectiveModelInfo.cjs +9 -10
- package/src/main/lib/ephemeralCwd.cjs +7 -28
- package/src/main/lib/gitWorktree.cjs +95 -8
- package/src/main/lib/guardShims.cjs +3 -3
- package/src/main/lib/historyRollup.cjs +6 -7
- package/src/main/lib/instanceLock.cjs +32 -5
- package/src/main/lib/jobSupervisorRecord.cjs +147 -0
- package/src/main/lib/jobWorktreeBootLive.cjs +9 -5
- package/src/main/lib/localAdminHttp.cjs +9 -27
- package/src/main/lib/mcpToolCatalog.cjs +29 -77
- package/src/main/lib/opsOwnership.cjs +27 -19
- package/src/main/lib/prdAuthoringSeed.cjs +36 -0
- package/src/main/lib/prdLocations.cjs +48 -1
- package/src/main/lib/procIdentity.cjs +126 -0
- package/src/main/lib/procName.cjs +98 -0
- package/src/main/lib/projectHomeAdminRoutes.cjs +56 -327
- package/src/main/lib/queueHistory.cjs +8 -7
- package/src/main/lib/queueStore.cjs +57 -37
- package/src/main/lib/quietMachineLease.cjs +19 -2
- package/src/main/lib/reservationExpiry.cjs +30 -0
- package/src/main/lib/runClaudeP.cjs +4 -2
- package/src/main/lib/runLogRetention.cjs +3 -2
- package/src/main/lib/scheduleJobSchema.cjs +2 -2
- package/src/main/lib/scheduleJobTransitions.cjs +29 -2
- package/src/main/lib/schedulerBatch.cjs +27 -2
- package/src/main/lib/schedulerPaths.cjs +175 -0
- package/src/main/lib/schedulerRuntimeState.cjs +59 -0
- package/src/main/lib/sessionSlots.cjs +47 -9
- package/src/main/lib/smProcNames.cjs +51 -0
- package/src/main/lib/upgradeDrain.cjs +188 -0
- package/src/main/lib/usageCircuit.cjs +53 -6
- package/src/main/lib/watchdogHelpers.cjs +70 -37
- package/src/main/lib/withTimeout.cjs +33 -0
- package/src/main/mcpStatus.cjs +4 -2
- package/src/main/pluginInstall.cjs +6 -2
- package/src/main/projectPages.cjs +41 -145
- package/src/main/pty.cjs +8 -1
- package/src/main/queueOps.cjs +10 -10
- package/src/main/runVerify.cjs +69 -3
- package/src/main/scheduler.cjs +1598 -381
- package/src/main/seedAgentPersonas.cjs +1 -1
- package/src/main/seedDevPlugin.cjs +1 -1
- package/src/main/seedSchedulerMcp.cjs +7 -6
- package/src/main/seedStatus.cjs +1 -1
- package/src/main/supervisor.cjs +5 -3
- package/src/main/usage.cjs +126 -62
- package/src/preload/api.d.ts +18 -64
- package/src/preload/index.cjs +2 -4
- package/src/seed/agents/project-home-builder.md +31 -48
- package/screenshots/.gitkeep +0 -0
- package/screenshots/README-screenshots.md +0 -13
- package/src/main/lib/projectPageSummarySchema.cjs +0 -181
- package/src/main/teams.cjs +0 -95
- package/src/main/templates/project-pages-catalog.json +0 -741
- package/src/main/templates/project-pages-default-home.html +0 -123
- package/src/main/templates/project-pages-pipeline.md +0 -417
- package/src/seed/prompts/code-review/ac-coverage-check.md +0 -8
- package/src/seed/prompts/code-review/correctness-only.md +0 -8
- package/src/seed/prompts/code-review/full-spectrum-high.md +0 -8
- package/src/seed/prompts/code-review/hallucination-check.md +0 -8
- package/src/seed/prompts/code-review/public-api-compat.md +0 -8
- package/src/seed/prompts/code-review/readability-naming.md +0 -8
- package/src/seed/prompts/debugging/bug-as-failing-test.md +0 -8
- package/src/seed/prompts/debugging/git-bisect-regression.md +0 -8
- package/src/seed/prompts/debugging/instrument-intermittent-bug.md +0 -8
- package/src/seed/prompts/debugging/localize-pipeline-failure.md +0 -8
- package/src/seed/prompts/debugging/reproduce-then-diagnose.md +0 -8
- package/src/seed/prompts/documentation/adr-from-change.md +0 -8
- package/src/seed/prompts/documentation/module-readme.md +0 -8
- package/src/seed/prompts/documentation/onboarding-plan.md +0 -8
- package/src/seed/prompts/documentation/refresh-claude-md.md +0 -8
- package/src/seed/prompts/documentation/tsdoc-public-exports.md +0 -8
- package/src/seed/prompts/git-pr/conventional-commit.md +0 -8
- package/src/seed/prompts/git-pr/draft-pr-title-body.md +0 -8
- package/src/seed/prompts/git-pr/pre-commit-safety-sweep.md +0 -8
- package/src/seed/prompts/git-pr/release-notes-block.md +0 -8
- package/src/seed/prompts/git-pr/split-large-pr.md +0 -8
- package/src/seed/prompts/performance/bundle-startup-audit.md +0 -8
- package/src/seed/prompts/performance/complexity-audit.md +0 -8
- package/src/seed/prompts/performance/cpu-profile-hot-path.md +0 -8
- package/src/seed/prompts/performance/db-query-plan-review.md +0 -8
- package/src/seed/prompts/performance/memory-leak-hunt.md +0 -8
- package/src/seed/prompts/qa/api-contract-tests.md +0 -8
- package/src/seed/prompts/qa/e2e-critical-path.md +0 -8
- package/src/seed/prompts/qa/failing-test-for-bug.md +0 -8
- package/src/seed/prompts/qa/find-missing-test-coverage.md +0 -8
- package/src/seed/prompts/qa/stabilize-flaky-test.md +0 -8
- package/src/seed/prompts/qa/tdd-red-first.md +0 -8
- package/src/seed/prompts/qa/visual-regression-review.md +0 -8
- package/src/seed/prompts/qa/wcag-axe-scan.md +0 -8
- package/src/seed/prompts/refactoring/dead-code-sweep.md +0 -8
- package/src/seed/prompts/refactoring/extract-duplicated-pattern.md +0 -8
- package/src/seed/prompts/refactoring/modernize-legacy-file.md +0 -8
- package/src/seed/prompts/refactoring/reduce-cyclomatic-complexity.md +0 -8
- package/src/seed/prompts/refactoring/tighten-module-boundaries.md +0 -8
- package/src/seed/prompts/security/authz-audit.md +0 -8
- package/src/seed/prompts/security/crypto-correctness.md +0 -8
- package/src/seed/prompts/security/cwe-top-25-hunt.md +0 -8
- package/src/seed/prompts/security/dependency-audit.md +0 -8
- package/src/seed/prompts/security/ipc-boundary-hardening.md +0 -8
- package/src/seed/prompts/security/owasp-top-10-staged-diff.md +0 -8
- package/src/seed/prompts/security/secret-credential-scan.md +0 -8
- package/web/README.md +0 -41
- package/web/project-pages/logic/dist/logic.cjs +0 -4709
- package/web/project-pages/render.cjs +0 -70
- package/web/project-pages/renderer/dist/renderer.cjs +0 -18900
- package/web/project-pages/validate-summary.cjs +0 -62
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usageSingleFlight.test.cjs — usage.cjs's fetchUsage() is the single owner
|
|
3
|
+
* of caching, single-flight de-duplication, and the shared usageCircuit for
|
|
4
|
+
* the /api/oauth/usage meter. Before this, the renderer's billing:fetch IPC
|
|
5
|
+
* handler owned the 30s OK-cache alone and the scheduler's pollLoop called
|
|
6
|
+
* fetchUsage() directly with no cache/dedup — two independent request
|
|
7
|
+
* streams against a rate-limiting endpoint, and a success on one path never
|
|
8
|
+
* reset the other's failure streak. This suite proves: (1) concurrent
|
|
9
|
+
* fetchUsage() callers coalesce into exactly one network fetch, (2) a
|
|
10
|
+
* success resets the shared circuit's streak regardless of which "caller"
|
|
11
|
+
* triggered the preceding failures, and (3) a 429's Retry-After suppresses
|
|
12
|
+
* the next request until it elapses.
|
|
13
|
+
*
|
|
14
|
+
* Never hits the live billing endpoint — global.fetch is stubbed throughout,
|
|
15
|
+
* and HOME is pointed at a scratch dir so no real credentials/cache file on
|
|
16
|
+
* this machine is ever read.
|
|
17
|
+
*
|
|
18
|
+
* usage.cjs (and config.cjs/credentials.cjs, which it requires) are loaded
|
|
19
|
+
* via Node's own require() — this is a .cjs test, not transformed ESM — so
|
|
20
|
+
* vi.mock()/vi.resetModules() do NOT intercept them the way they would for
|
|
21
|
+
* an ESM import graph; both also bake os.homedir() into module-level
|
|
22
|
+
* constants at first require (config.cjs's allowedRoots/WRITE_PREFIXES,
|
|
23
|
+
* usage.cjs's CACHE_PATH, credentials.cjs's CREDS_PATH). So this suite
|
|
24
|
+
* follows historyRollup.test.cjs's pattern instead: swap $HOME to a fresh
|
|
25
|
+
* tmp dir with a valid, far-from-expiry fake credentials file, purge
|
|
26
|
+
* Node's require.cache for every affected module, and re-require fresh
|
|
27
|
+
* each test.
|
|
28
|
+
*
|
|
29
|
+
* Run: timeout 120 npx vitest run src/main/__tests__/usageSingleFlight.test.cjs
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
'use strict';
|
|
33
|
+
|
|
34
|
+
import { test, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
35
|
+
import fs from 'node:fs';
|
|
36
|
+
import os from 'node:os';
|
|
37
|
+
import path from 'node:path';
|
|
38
|
+
|
|
39
|
+
function jsonResponse(status, body, headers = {}) {
|
|
40
|
+
return {
|
|
41
|
+
status,
|
|
42
|
+
ok: status >= 200 && status < 300,
|
|
43
|
+
text: async () => JSON.stringify(body),
|
|
44
|
+
json: async () => body,
|
|
45
|
+
headers: { get: (k) => headers[k.toLowerCase()] ?? null },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const usagePayload = { five_hour: { utilization: 10, resets_at: null }, seven_day: { utilization: 10, resets_at: null }, seven_day_sonnet: null, seven_day_opus: null, extra_usage: null };
|
|
50
|
+
|
|
51
|
+
const MODULES_TO_RELOAD = [
|
|
52
|
+
'../usage.cjs',
|
|
53
|
+
'../config.cjs',
|
|
54
|
+
'../lib/credentials.cjs',
|
|
55
|
+
'../lib/usageCircuit.cjs',
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
function purgeRequireCache() {
|
|
59
|
+
for (const m of MODULES_TO_RELOAD) {
|
|
60
|
+
try { delete require.cache[require.resolve(m)]; } catch { /* not loaded yet */ }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let realHome;
|
|
65
|
+
let tmpHome;
|
|
66
|
+
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
realHome = process.env.HOME;
|
|
69
|
+
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'usage-single-flight-test-'));
|
|
70
|
+
process.env.HOME = tmpHome;
|
|
71
|
+
fs.mkdirSync(path.join(tmpHome, '.claude'), { recursive: true });
|
|
72
|
+
fs.writeFileSync(
|
|
73
|
+
path.join(tmpHome, '.claude', '.credentials.json'),
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
claudeAiOauth: {
|
|
76
|
+
accessToken: 'test-access-token',
|
|
77
|
+
refreshToken: 'test-refresh-token',
|
|
78
|
+
expiresAt: Date.now() + 1_000 * 60 * 60 * 24, // 24h out — never "expiring soon"
|
|
79
|
+
subscriptionType: 'max',
|
|
80
|
+
rateLimitTier: 'default_claude_max_20x',
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
purgeRequireCache();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
afterEach(() => {
|
|
88
|
+
process.env.HOME = realHome;
|
|
89
|
+
vi.unstubAllGlobals();
|
|
90
|
+
vi.restoreAllMocks();
|
|
91
|
+
purgeRequireCache();
|
|
92
|
+
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('two concurrent fetchUsage() calls produce exactly one HTTP fetch', async () => {
|
|
96
|
+
const { fetchUsage } = require('../usage.cjs');
|
|
97
|
+
let fetchCalls = 0;
|
|
98
|
+
vi.stubGlobal('fetch', vi.fn(async () => {
|
|
99
|
+
fetchCalls++;
|
|
100
|
+
// Slow enough that both callers are guaranteed to be in-flight together.
|
|
101
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
102
|
+
return jsonResponse(200, usagePayload);
|
|
103
|
+
}));
|
|
104
|
+
|
|
105
|
+
const [a, b] = await Promise.all([fetchUsage(), fetchUsage()]);
|
|
106
|
+
|
|
107
|
+
expect(fetchCalls).toBe(1);
|
|
108
|
+
expect(a.kind).toBe('ok');
|
|
109
|
+
expect(b.kind).toBe('ok');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('an ok result resets the shared circuit streak built up by prior failures', async () => {
|
|
113
|
+
const usage = require('../usage.cjs');
|
|
114
|
+
const circuit = usage.__usageCircuitForTest;
|
|
115
|
+
|
|
116
|
+
let call = 0;
|
|
117
|
+
vi.stubGlobal('fetch', vi.fn(async () => {
|
|
118
|
+
call++;
|
|
119
|
+
if (call <= 3) return jsonResponse(500, { error: 'boom' });
|
|
120
|
+
return jsonResponse(200, usagePayload);
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
// Three consecutive transient failures — simulating the scheduler's poller
|
|
124
|
+
// failing repeatedly — trip the circuit open.
|
|
125
|
+
await usage.fetchUsage();
|
|
126
|
+
await usage.fetchUsage();
|
|
127
|
+
await usage.fetchUsage();
|
|
128
|
+
expect(circuit.state()).toBe('open');
|
|
129
|
+
|
|
130
|
+
// A later success — as if it came from the renderer's independent
|
|
131
|
+
// billing:fetch call, but reached through the SAME shared fetchUsage() —
|
|
132
|
+
// must reset the streak the scheduler's calls built up, since both
|
|
133
|
+
// callers share one circuit instance.
|
|
134
|
+
const ok = await usage.fetchUsage();
|
|
135
|
+
expect(ok.kind).toBe('ok');
|
|
136
|
+
expect(circuit.state()).toBe('closed');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('a 429 with Retry-After suppresses the next request until it elapses', async () => {
|
|
140
|
+
const usage = require('../usage.cjs');
|
|
141
|
+
|
|
142
|
+
let fetchCalls = 0;
|
|
143
|
+
vi.stubGlobal('fetch', vi.fn(async () => {
|
|
144
|
+
fetchCalls++;
|
|
145
|
+
return jsonResponse(429, { error: { type: 'rate_limit_error' } }, { 'retry-after': '60' });
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
const first = await usage.fetchUsage();
|
|
149
|
+
expect(first.kind).toBe('meter_rate_limited');
|
|
150
|
+
expect(first.retryAfterMs).toBe(60_000);
|
|
151
|
+
|
|
152
|
+
const second = await usage.fetchUsage();
|
|
153
|
+
expect(second.kind).toBe('meter_rate_limited');
|
|
154
|
+
expect(second.suppressed).toBe(true);
|
|
155
|
+
// No second network call — the suppression window hasn't elapsed.
|
|
156
|
+
expect(fetchCalls).toBe(1);
|
|
157
|
+
});
|
|
@@ -46,7 +46,7 @@ test('WORK_TYPES matches the tag ids declared in tagLibrary.ts TAG_LIBRARY, in o
|
|
|
46
46
|
expect(tagMatches).toEqual(WORK_TYPES);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
test('api.d.ts tag unions
|
|
49
|
+
test('api.d.ts tag unions both contain exactly the same 6 values', () => {
|
|
50
50
|
const src = fs.readFileSync(API_D_TS_PATH, 'utf8');
|
|
51
51
|
const unionMatches = [...src.matchAll(/tag\?:\s*((?:'[^']+'\s*\|?\s*)+);/g)].map((m) =>
|
|
52
52
|
m[1]
|
package/src/main/bilkoHost.cjs
CHANGED
|
@@ -46,6 +46,10 @@ const {
|
|
|
46
46
|
const WRITER = 'bilko-host';
|
|
47
47
|
const PROJECT_PAGE_LENSES = new Set(['home', 'marketing', 'feature', 'architecture']);
|
|
48
48
|
|
|
49
|
+
function homePagePath(cwd) {
|
|
50
|
+
return opsPath(cwd, 'project-pages', 'home.html');
|
|
51
|
+
}
|
|
52
|
+
|
|
49
53
|
function bilkoHostDir(cwd) {
|
|
50
54
|
return opsPath(cwd, 'bilko-host');
|
|
51
55
|
}
|
|
@@ -103,9 +107,10 @@ async function writeDocuments(cwd, documents) {
|
|
|
103
107
|
async function get({ cwd }) {
|
|
104
108
|
const realCwd = config.validatePath(cwd);
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
// The single Project Home page (project-pages/home.html) seeds the root
|
|
111
|
+
// document. `hasMarketingPage` is the renderer's legacy field name for
|
|
112
|
+
// "a root-document source page exists".
|
|
113
|
+
const marketingResult = await config.readText(homePagePath(realCwd));
|
|
109
114
|
const pkgResult = await config.readJson(path.join(realCwd, 'package.json'));
|
|
110
115
|
const pkg = pkgResult.exists && !pkgResult.parseError ? pkgResult.data : null;
|
|
111
116
|
|
|
@@ -142,15 +147,15 @@ async function get({ cwd }) {
|
|
|
142
147
|
};
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
/** Seeds documents.json with a single root document (the
|
|
150
|
+
/** Seeds documents.json with a single root document (the Project Home page, home.html) if it doesn't exist yet. */
|
|
146
151
|
async function ensureSeededDocuments(cwd) {
|
|
147
152
|
const existing = await readDocuments(cwd);
|
|
148
153
|
if (existing) return existing;
|
|
149
154
|
const seeded = [{
|
|
150
155
|
id: crypto.randomUUID(),
|
|
151
156
|
subpath: '',
|
|
152
|
-
title: 'Project (
|
|
153
|
-
source: { kind: 'project-page-lens', lens: '
|
|
157
|
+
title: 'Project (Home)',
|
|
158
|
+
source: { kind: 'project-page-lens', lens: 'home' },
|
|
154
159
|
addedAt: new Date().toISOString(),
|
|
155
160
|
}];
|
|
156
161
|
await writeDocuments(cwd, seeded);
|
|
@@ -215,8 +220,12 @@ async function removeDocument({ cwd, id }) {
|
|
|
215
220
|
|
|
216
221
|
async function resolveDocumentHtml(cwd, doc) {
|
|
217
222
|
if (doc.source.kind === 'project-page-lens') {
|
|
223
|
+
// Only `home` is generated now (one home.html); the other lens names
|
|
224
|
+
// are legacy and resolve to their old output/<lens>.html if one exists.
|
|
218
225
|
const result = await config.readText(
|
|
219
|
-
|
|
226
|
+
doc.source.lens === 'home'
|
|
227
|
+
? homePagePath(cwd)
|
|
228
|
+
: opsPath(cwd, 'project-pages', 'output', `${doc.source.lens}.html`),
|
|
220
229
|
);
|
|
221
230
|
if (!result.exists) {
|
|
222
231
|
throw new Error(`document "${doc.title}" points at the ${doc.source.lens} Project Page, but it hasn't been generated yet`);
|
package/src/main/chatRunner.cjs
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
const { spawn } = require('node:child_process');
|
|
46
46
|
const { ipcMain } = require('electron');
|
|
47
|
-
const { resolveClaudeBin } = require('./lib/claudeBin.cjs');
|
|
47
|
+
const { resolveClaudeBin, claudeSpawnTarget } = require('./lib/claudeBin.cjs');
|
|
48
48
|
const { cleanChildEnv, pathWithUserBins } = require('./lib/cleanEnv.cjs');
|
|
49
49
|
const { recordExchange } = require('./exchanges.cjs');
|
|
50
50
|
const { classifyToolUse } = require('./lib/toolUseClassify.cjs');
|
|
@@ -571,7 +571,9 @@ function executeRun({ tabId, sessionId, prompt, cwd, resume, silent, onSilentRes
|
|
|
571
571
|
// real-time NDJSON streaming; stderr piped for error-message capture.
|
|
572
572
|
let child;
|
|
573
573
|
try {
|
|
574
|
-
|
|
574
|
+
const target = claudeSpawnTarget('chat', sessionId, claudeBin);
|
|
575
|
+
child = spawn(target.command, args, {
|
|
576
|
+
...(target.argv0 ? { argv0: target.argv0 } : {}),
|
|
575
577
|
cwd: execCwd,
|
|
576
578
|
env: childEnv,
|
|
577
579
|
stdio: ['ignore', 'pipe', 'pipe'],
|
package/src/main/config.cjs
CHANGED
|
@@ -148,9 +148,8 @@ function validateWrite(realAbs) {
|
|
|
148
148
|
// (PRD 825; scheduler.cjs remote.writePrd)
|
|
149
149
|
// project-brief projectBrief.cjs's brief.json (PRD 837)
|
|
150
150
|
// bilko-host bilkoHost.cjs's bundle prep
|
|
151
|
-
// project-pages projectHomeAdminRoutes.cjs's
|
|
152
|
-
// (
|
|
153
|
-
// project-home-admin-routes)
|
|
151
|
+
// project-pages projectHomeAdminRoutes.cjs's project_home_write
|
|
152
|
+
// path (home.html)
|
|
154
153
|
// Paths come from opsOwnership.opsPath (PRD 1082) — the one ops-root
|
|
155
154
|
// resolver — which THROWS for an ephemeral root (a linked worktree that
|
|
156
155
|
// pty.cjs registered as an allowed root for its spawn cwd, or
|
package/src/main/docEdit.cjs
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
const { ipcMain } = require('electron');
|
|
18
18
|
const { spawn } = require('node:child_process');
|
|
19
19
|
const crypto = require('node:crypto');
|
|
20
|
-
const { resolveClaudeBin } = require('./lib/claudeBin.cjs');
|
|
20
|
+
const { resolveClaudeBin, claudeSpawnTarget } = require('./lib/claudeBin.cjs');
|
|
21
|
+
const { withProcRole } = require('./lib/cleanEnv.cjs');
|
|
21
22
|
const { extractJson } = require('./lib/extractJson.cjs');
|
|
22
23
|
const { assertInsideHome } = require('./lib/insideHome.cjs');
|
|
23
24
|
const { expandHome } = require('./lib/expandHome.cjs');
|
|
@@ -99,7 +100,8 @@ function runClaude(prompt, { model = 'sonnet', timeoutMs = 90_000, systemPrompt
|
|
|
99
100
|
// stdin MUST be closed ('ignore') — `claude -p` otherwise blocks waiting
|
|
100
101
|
// for piped stdin and returns empty. SM_KG_INTERNAL=1 tells the
|
|
101
102
|
// prompt-logging hook to skip this invocation.
|
|
102
|
-
const
|
|
103
|
+
const target = claudeSpawnTarget('aux', 'docedit', bin);
|
|
104
|
+
const child = spawn(target.command, args, { env: withProcRole({ ...process.env, SM_KG_INTERNAL: '1' }, 'aux'), stdio: ['ignore', 'pipe', 'pipe'], ...(target.argv0 ? { argv0: target.argv0 } : {}) });
|
|
103
105
|
let out = '';
|
|
104
106
|
let err = '';
|
|
105
107
|
// Cap accumulated stdout — the model output shouldn't grow `out` without
|