create-walle 0.10.1 → 0.10.2
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 +4 -0
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +6 -4
- package/package.json +1 -1
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +55 -17
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +1 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +2 -2
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +4 -2
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +902 -239
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +6 -4
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Lead-cost routing WP-6 (design §6.5, D-19): the 1-in-EXPLORE_GRADE_EVERY spot-check grader
|
|
4
|
+
// for exploration hand-offs. A pinned grader model — the brain setting
|
|
5
|
+
// `helper_rules.grader_model`, seeded to the user's stated grader — reads the card (the brief the
|
|
6
|
+
// helper was given, the report it wrote, the tools it touched) against the rubric committed
|
|
7
|
+
// beside this file, and answers with one JSON object.
|
|
8
|
+
//
|
|
9
|
+
// Two properties are load-bearing (D-0/D-19):
|
|
10
|
+
//
|
|
11
|
+
// 1. NO FALLBACK. An unset pin or a failed call is a stored `{unavailable:true, error}` sample
|
|
12
|
+
// that the rules exclude from the sufficient rate. A cheaper judge is never substituted,
|
|
13
|
+
// because a cheaper judge's verdicts would silently move the cell's thresholds.
|
|
14
|
+
// 2. NEVER THROWS. The caller (lib/helper-rules/lead-call-hook.js) runs on the lead's tool-call
|
|
15
|
+
// path and only ever fire-and-forgets this; every failure has to come back as a value.
|
|
16
|
+
//
|
|
17
|
+
// The reply is parsed field by field with a regex, never JSON.parse'd whole: a grader that wraps
|
|
18
|
+
// its answer in prose (or in a fenced block) still yields its verdict, while a reply that never
|
|
19
|
+
// states `sufficient` and `coverage` is `grade_unparsed` rather than a fabricated label.
|
|
20
|
+
//
|
|
21
|
+
// Round 2 WP-3 (§5 D-8, §6.6): three hardenings, none of which relaxes the pin.
|
|
22
|
+
// * the card's report TEXT is read HERE from `report_path` / `last_message_path` (the hook has
|
|
23
|
+
// no fs access, and the no-id wait never carried a report), so the grader sees the real report;
|
|
24
|
+
// * a reply wrapped in one Markdown fence is unwrapped before the field regexes run;
|
|
25
|
+
// * an unparsed first reply earns ONE re-ask of the same pinned model with the parse error
|
|
26
|
+
// appended, and a second failure stores the raw reply so the failure is visible on the panel.
|
|
27
|
+
// A cheaper judge is still never substituted (D-19).
|
|
28
|
+
|
|
29
|
+
const fs = require('node:fs');
|
|
30
|
+
const path = require('node:path');
|
|
31
|
+
|
|
32
|
+
const EXPLORE_GRADE_EVERY = 5; // D-12: one in five completed hand-offs per cell
|
|
33
|
+
const GRADE_TASK = 'explore-handoff-grade';
|
|
34
|
+
const GRADE_MAX_TOKENS = 400;
|
|
35
|
+
const GRADE_TIMEOUT_MS = 120000;
|
|
36
|
+
const CARD_MAX_CHARS = 12000;
|
|
37
|
+
const BRIEF_MAX_CHARS = 4000; // the brief's share of the card; the report keeps the rest
|
|
38
|
+
const REPORT_MAX_CHARS = CARD_MAX_CHARS - BRIEF_MAX_CHARS; // the report's share of the card
|
|
39
|
+
const RAW_MAX_CHARS = 2048; // D-8: how much of an unparsed reply the stored sample keeps
|
|
40
|
+
const DEFAULT_GRADER_MODEL_KV = 'helper_rules.grader_model';
|
|
41
|
+
|
|
42
|
+
// The pilot's T2 rubric, verbatim, committed next to this module (design §6.5).
|
|
43
|
+
const RUBRIC = fs.readFileSync(path.join(__dirname, 'explore-rubric.md'), 'utf8');
|
|
44
|
+
|
|
45
|
+
const FIELD_PATTERNS = Object.freeze({
|
|
46
|
+
sufficient: /"sufficient"\s*:\s*(true|false)/,
|
|
47
|
+
coverage: /"coverage"\s*:\s*"(all|most|little)"/,
|
|
48
|
+
inaccuracies: /"inaccuracies"\s*:\s*(\d+)/,
|
|
49
|
+
why: /"why"\s*:\s*"([^"]{0,300})"/,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// A verdict without these two is not a verdict (D-19): the parse error names the missing ones.
|
|
53
|
+
const REQUIRED_FIELDS = Object.freeze(['sufficient', 'coverage']);
|
|
54
|
+
|
|
55
|
+
// One opening Markdown fence — ``` optionally followed by a language word (`json`) — plus its
|
|
56
|
+
// line break; and the matching closing fence at the end of the text. The language word is a word,
|
|
57
|
+
// never free text, so a single-line ```json {...}``` reply is left to the field regexes untouched.
|
|
58
|
+
const OPEN_FENCE = /^\s*```[ \t]*[A-Za-z0-9_+-]*[ \t]*(?:\r?\n|$)/;
|
|
59
|
+
const CLOSE_FENCE = /\r?\n[ \t]*```[ \t]*\s*$/;
|
|
60
|
+
|
|
61
|
+
function _str(value) {
|
|
62
|
+
return typeof value === 'string' ? value : '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function _errorCode(err) {
|
|
66
|
+
return String((err && (err.code || err.message)) || 'grade_failed');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The card as one text block: the brief, the report, then one `tool path` line per tool. Clipped
|
|
71
|
+
* to CARD_MAX_CHARS by keeping the head — the brief and the head of the report are what the
|
|
72
|
+
* grader's coverage question is about, and a report is ≤600 words by contract (D-10).
|
|
73
|
+
*/
|
|
74
|
+
// Lead review (WP-6 C-1): the hook (lib/helper-rules/lead-call-hook.js) has no fs access, so it
|
|
75
|
+
// parks the delegation's rendered_brief_path; the brief TEXT is read here, bounded, and a missing or
|
|
76
|
+
// unreadable file is an empty brief -- the grader then judges the report against nothing and says so.
|
|
77
|
+
function _briefText(source) {
|
|
78
|
+
const direct = _str(source.brief);
|
|
79
|
+
if (direct) return direct;
|
|
80
|
+
const briefPath = _str(source.brief_path);
|
|
81
|
+
if (!briefPath) return '';
|
|
82
|
+
try {
|
|
83
|
+
return fs.readFileSync(briefPath, 'utf8').slice(0, BRIEF_MAX_CHARS);
|
|
84
|
+
} catch {
|
|
85
|
+
// expected: the rendered brief was purged or never written -- the card carries no brief
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* D-8: the report the grader judges. The hook has no fs access and the no-id wait never carried a
|
|
92
|
+
* report, so the grader reads the card's paths itself: `report` (back-compat, an inline string),
|
|
93
|
+
* else the file at `report_path`, else the worker's `last_message_path`. Missing, unreadable or
|
|
94
|
+
* empty falls through to the next source; nothing readable is ''. Bounded to the report's share of
|
|
95
|
+
* the card so a long report can never crowd out the brief.
|
|
96
|
+
*/
|
|
97
|
+
function _fileText(filePath) {
|
|
98
|
+
if (!filePath) return '';
|
|
99
|
+
try {
|
|
100
|
+
return fs.readFileSync(filePath, 'utf8').slice(0, REPORT_MAX_CHARS);
|
|
101
|
+
} catch {
|
|
102
|
+
// expected: the report (or last message) was purged or never written -- the card carries no report
|
|
103
|
+
return '';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function _reportText(source) {
|
|
108
|
+
const direct = _str(source.report);
|
|
109
|
+
if (direct) return direct.slice(0, REPORT_MAX_CHARS);
|
|
110
|
+
const fromReportPath = _fileText(_str(source.report_path));
|
|
111
|
+
if (fromReportPath) return fromReportPath;
|
|
112
|
+
return _fileText(_str(source.last_message_path));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function _cardText(card) {
|
|
116
|
+
const source = card && typeof card === 'object' ? card : {};
|
|
117
|
+
const toolLog = Array.isArray(source.toolLog) ? source.toolLog : [];
|
|
118
|
+
const toolLines = toolLog
|
|
119
|
+
.map((entry) => `${_str(entry && entry.tool)} ${_str(entry && entry.path)}`.trim())
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.join('\n');
|
|
122
|
+
// Each half keeps its own head, so a long brief can never push the report off the card.
|
|
123
|
+
const text = [
|
|
124
|
+
'## Brief',
|
|
125
|
+
_briefText(source).slice(0, BRIEF_MAX_CHARS),
|
|
126
|
+
'',
|
|
127
|
+
'## Report',
|
|
128
|
+
_reportText(source),
|
|
129
|
+
'',
|
|
130
|
+
'## Tools used',
|
|
131
|
+
toolLines,
|
|
132
|
+
].join('\n');
|
|
133
|
+
return text.slice(0, CARD_MAX_CHARS);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function _replyText(reply) {
|
|
137
|
+
if (typeof reply === 'string') return reply;
|
|
138
|
+
return _str(reply && reply.content);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* D-8: a grader that wraps its JSON in one Markdown fence still yields its verdict. Only a fence
|
|
143
|
+
* the reply STARTS with is stripped, and only its matching close — prose around the block is left
|
|
144
|
+
* to the field regexes exactly as before.
|
|
145
|
+
*/
|
|
146
|
+
function _stripFence(text) {
|
|
147
|
+
const open = OPEN_FENCE.exec(text);
|
|
148
|
+
if (!open) return text;
|
|
149
|
+
return text.slice(open[0].length).replace(CLOSE_FENCE, '');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Parse one reply. `sufficient` and `coverage` are required; an unstated count/why reads as 0/' '. */
|
|
153
|
+
function _parseReply(reply) {
|
|
154
|
+
const text = _stripFence(_replyText(reply));
|
|
155
|
+
const matched = {};
|
|
156
|
+
for (const name of REQUIRED_FIELDS) matched[name] = FIELD_PATTERNS[name].exec(text);
|
|
157
|
+
const missing = REQUIRED_FIELDS.filter((name) => !matched[name]);
|
|
158
|
+
if (missing.length) return { ok: false, error: 'grade_unparsed', missing };
|
|
159
|
+
const inaccuracies = FIELD_PATTERNS.inaccuracies.exec(text);
|
|
160
|
+
const why = FIELD_PATTERNS.why.exec(text);
|
|
161
|
+
return {
|
|
162
|
+
ok: true,
|
|
163
|
+
sufficient: matched.sufficient[1] === 'true',
|
|
164
|
+
coverage: matched.coverage[1],
|
|
165
|
+
// A field the grader did not state: 0 wrong claims, no reason given.
|
|
166
|
+
inaccuracies: inaccuracies ? Number.parseInt(inaccuracies[1], 10) : 0,
|
|
167
|
+
why: why ? why[1].trim() : '',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Grade one exploration hand-off. Never throws; returns { ok:false, error } on any failure, and
|
|
173
|
+
* re-asks the same pinned model once when the first reply does not parse (D-8).
|
|
174
|
+
* @param {{ brief?:string, brief_path?:string, report?:string, report_path?:string, last_message_path?:string, toolLog:[{tool:string, path:string}] }} card clipped to CARD_MAX_CHARS (brief text, or read from brief_path; report text, or read from report_path/last_message_path)
|
|
175
|
+
* @param {{ completeForRole: Function, graderModel: string, brain?: object }} deps
|
|
176
|
+
* @returns {Promise<{ ok:true, sufficient:boolean, coverage:'all'|'most'|'little', inaccuracies:number, why:string } | { ok:false, error:string, raw?:string }>}
|
|
177
|
+
*/
|
|
178
|
+
async function gradeHandoff(card, deps = {}) {
|
|
179
|
+
const graderModel = _str(deps && deps.graderModel).trim();
|
|
180
|
+
// An unset pin is not a reason to grade with something else (D-0): the sample is unavailable.
|
|
181
|
+
if (!graderModel) return { ok: false, error: 'grader_model_unset' };
|
|
182
|
+
const ask = {
|
|
183
|
+
brain: deps.brain,
|
|
184
|
+
task: GRADE_TASK,
|
|
185
|
+
model: graderModel,
|
|
186
|
+
system: RUBRIC,
|
|
187
|
+
maxTokens: GRADE_MAX_TOKENS,
|
|
188
|
+
timeoutMs: GRADE_TIMEOUT_MS,
|
|
189
|
+
temperature: 0,
|
|
190
|
+
};
|
|
191
|
+
const userMessage = { role: 'user', content: _cardText(card) };
|
|
192
|
+
let reply;
|
|
193
|
+
try {
|
|
194
|
+
reply = await deps.completeForRole({ ...ask, messages: [userMessage] });
|
|
195
|
+
} catch (err) {
|
|
196
|
+
// REPORT: the caller stores this as an unavailable sample -- it is a value, never a throw.
|
|
197
|
+
// A call that never answered has no reply to re-ask about, so this is not retried.
|
|
198
|
+
return { ok: false, error: _errorCode(err) };
|
|
199
|
+
}
|
|
200
|
+
const first = _parseReply(reply);
|
|
201
|
+
if (first.ok) return first;
|
|
202
|
+
const firstRaw = _replyText(reply);
|
|
203
|
+
let raw = firstRaw;
|
|
204
|
+
try {
|
|
205
|
+
// D-8: ONE bounded retry, the SAME pinned model and parameters, with the raw reply and the
|
|
206
|
+
// parse error on the wire (the MLflow "single retry with a tightened prompt" form).
|
|
207
|
+
const retried = await deps.completeForRole({
|
|
208
|
+
...ask,
|
|
209
|
+
messages: [
|
|
210
|
+
userMessage,
|
|
211
|
+
{ role: 'assistant', content: firstRaw },
|
|
212
|
+
{ role: 'user', content: `Reply with the JSON object only. Parse error: missing ${first.missing.join(', ')}` },
|
|
213
|
+
],
|
|
214
|
+
});
|
|
215
|
+
const parsed = _parseReply(retried);
|
|
216
|
+
if (parsed.ok) return parsed;
|
|
217
|
+
raw = _replyText(retried);
|
|
218
|
+
} catch {
|
|
219
|
+
// REPORT: the retry itself failed -- the sample is still stored as an unparsed grade, carrying
|
|
220
|
+
// the first raw reply, so the failure is visible rather than a silent hole in the rate.
|
|
221
|
+
raw = firstRaw;
|
|
222
|
+
}
|
|
223
|
+
return { ok: false, error: 'grade_unparsed', raw: raw.slice(0, RAW_MAX_CHARS) };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** D-12: every EXPLORE_GRADE_EVERY-th completed hand-off of a cell (its `helper_outcomes.seq`). */
|
|
227
|
+
function shouldGrade(seq) {
|
|
228
|
+
return Number.isInteger(seq) && seq > 0 && seq % EXPLORE_GRADE_EVERY === 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The persisted `helper_outcomes.grade_json` value: the four verdict fields, or `unavailable`.
|
|
233
|
+
* D-8: an unparsed sample keeps the raw reply (≤ RAW_MAX_CHARS) so the panel can show WHY it
|
|
234
|
+
* failed instead of an empty cell.
|
|
235
|
+
*/
|
|
236
|
+
function gradeToJson(result) {
|
|
237
|
+
if (!result || result.ok !== true) {
|
|
238
|
+
const json = { unavailable: true, error: _str(result && result.error) || 'grade_failed' };
|
|
239
|
+
const raw = _str(result && result.raw);
|
|
240
|
+
if (raw) json.raw = raw.slice(0, RAW_MAX_CHARS);
|
|
241
|
+
return json;
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
sufficient: result.sufficient === true,
|
|
245
|
+
coverage: result.coverage,
|
|
246
|
+
inaccuracies: Number.isInteger(result.inaccuracies) ? result.inaccuracies : 0,
|
|
247
|
+
why: _str(result.why),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** The pinned grader model from kv_store; missing (or unreadable) is '' -> `grader_model_unset`. */
|
|
252
|
+
function readGraderModel(db) {
|
|
253
|
+
if (!db || typeof db.prepare !== 'function') return '';
|
|
254
|
+
try {
|
|
255
|
+
const row = db.prepare('SELECT value FROM kv_store WHERE key = ?').get(DEFAULT_GRADER_MODEL_KV);
|
|
256
|
+
return _str(row && row.value).trim();
|
|
257
|
+
} catch {
|
|
258
|
+
// expected: kv_store is absent on a bare handle -- an unreadable pin reads as unset
|
|
259
|
+
return '';
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
module.exports = {
|
|
264
|
+
BRIEF_MAX_CHARS,
|
|
265
|
+
CARD_MAX_CHARS,
|
|
266
|
+
DEFAULT_GRADER_MODEL_KV,
|
|
267
|
+
EXPLORE_GRADE_EVERY,
|
|
268
|
+
GRADE_MAX_TOKENS,
|
|
269
|
+
GRADE_TASK,
|
|
270
|
+
GRADE_TIMEOUT_MS,
|
|
271
|
+
RAW_MAX_CHARS,
|
|
272
|
+
RUBRIC,
|
|
273
|
+
gradeHandoff,
|
|
274
|
+
gradeToJson,
|
|
275
|
+
readGraderModel,
|
|
276
|
+
shouldGrade,
|
|
277
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Lead-cost routing WP-5a (design §6.7): the PURE labelling functions behind the two rule
|
|
4
|
+
// cells. Nothing here reads a clock, a database or a transcript — every input is an
|
|
5
|
+
// argument, so the whole file is unit-testable on fixtures and has no side effects.
|
|
6
|
+
//
|
|
7
|
+
// Round 2 (WP-1, D-1/D-2/D-4): the labeller no longer counts citations out of a result body.
|
|
8
|
+
// The observed inputs arrive as a `facts` object (§6.2) produced by `factsFromPayload`, and
|
|
9
|
+
// `labelFromFacts(kind, facts)` derives the decision from those facts alone. `LABEL_VERSION`
|
|
10
|
+
// is the version of that rule; every row the hook writes carries it.
|
|
11
|
+
//
|
|
12
|
+
// Round 1 (D-12): `lead_usd` and `reread_rate` are deliberately NOT computed — the usage
|
|
13
|
+
// ledger carries no per-call tool names, so both stay null and the evaluator simply skips
|
|
14
|
+
// the two rules that read them.
|
|
15
|
+
|
|
16
|
+
// D-3 (lead-cost-routing-round2-2026-10-24.html §5 D-3, §6.1): the citation regex moved to
|
|
17
|
+
// shared/report-citations.js so CTM (the counter, delegate-worker.js's getWorkerStatus) and
|
|
18
|
+
// this file (the labeller) cannot drift. `countReportRows` below stays the export name every
|
|
19
|
+
// caller already uses; round 2 (D-3) makes CTM the only counter, so this is now the shared
|
|
20
|
+
// implementation CTM calls rather than something the hook runs on a result body.
|
|
21
|
+
const { countReportCitations } = require('../../../shared/report-citations');
|
|
22
|
+
|
|
23
|
+
// D-1: the version of the label rule below. Bump it whenever the rule changes.
|
|
24
|
+
const LABEL_VERSION = 2;
|
|
25
|
+
|
|
26
|
+
// The tools that mean "the lead acted on that worker". walle_worker_wait / status are
|
|
27
|
+
// excluded even when they name the session: another poll on the same set is exactly the
|
|
28
|
+
// empty wake the rule exists to catch.
|
|
29
|
+
const WAIT_TOOLS = new Set(['walle_worker_wait', 'walle_worker_status']);
|
|
30
|
+
// S-9 (round 2): kept as the exported list of acting tools. Since round 2 an ACT tool counts
|
|
31
|
+
// only when its args name THAT worker, exactly like every other non-wait tool — `ACT_TOOLS`
|
|
32
|
+
// no longer short-circuits the judgement (see `_isUsefulNextCall`).
|
|
33
|
+
const ACT_TOOLS = new Set(['walle_stop_worker', 'walle_resume_worker']);
|
|
34
|
+
|
|
35
|
+
// D-4: the terminal statuses a payload may report and the report sources that can carry a
|
|
36
|
+
// report. Anything else reads as unknown (null) so a malformed body can never be a hand-off.
|
|
37
|
+
const TERMINAL_STATUSES = new Set(['report_ready', 'exited', 'failed']);
|
|
38
|
+
const REPORT_SOURCES = new Set(['report', 'last_message', 'final_result']);
|
|
39
|
+
|
|
40
|
+
function _toolOf(nextCall) {
|
|
41
|
+
return nextCall && typeof nextCall.tool === 'string' ? nextCall.tool : '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _argsOf(nextCall) {
|
|
45
|
+
const args = nextCall && nextCall.args;
|
|
46
|
+
return args && typeof args === 'object' ? args : {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** S-9: the lead's call acts on THIS worker only when its args name that worker. */
|
|
50
|
+
function _namesWorker(nextCall, workerId) {
|
|
51
|
+
return Boolean(workerId) && _argsOf(nextCall).ctm_session_id === workerId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** True when the lead's next Wall-E call actually advanced the worker rather than polling it. */
|
|
55
|
+
function _isUsefulNextCall(nextCall, workerId) {
|
|
56
|
+
const tool = _toolOf(nextCall);
|
|
57
|
+
if (!tool) return false;
|
|
58
|
+
if (WAIT_TOOLS.has(tool)) return false;
|
|
59
|
+
// S-9 (round 2): the round-1 `ACT_TOOLS.has(tool)` short-circuit is gone -- a stop/resume
|
|
60
|
+
// counts only when its args name THAT worker, the same test every other non-wait tool uses.
|
|
61
|
+
return _namesWorker(nextCall, workerId);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The label for a WAKE_LEAD tick: did the wake buy the lead anything?
|
|
66
|
+
* @returns {'useful'|'empty'}
|
|
67
|
+
*/
|
|
68
|
+
function labelWatcherWake({ nextCall, workerId } = {}) {
|
|
69
|
+
return _isUsefulNextCall(nextCall, workerId) ? 'useful' : 'empty';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The label for a tick the watcher kept silent, judged by the same rule with the silent
|
|
74
|
+
* prefix. A KEEP_WAITING tick draws no lead call of its own, so it is silent_empty unless
|
|
75
|
+
* the lead's next call for that set was a finish/resume — the silence was right, and that
|
|
76
|
+
* is the only way the evaluator's silent window can ever turn a cell back on.
|
|
77
|
+
* @returns {'silent_useful'|'silent_empty'}
|
|
78
|
+
*/
|
|
79
|
+
function labelSilentTick({ nextCall, workerId } = {}) {
|
|
80
|
+
return _isUsefulNextCall(nextCall, workerId) ? 'silent_useful' : 'silent_empty';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The positive control for silence: a worker that only ended after the watcher last chose
|
|
85
|
+
* to keep waiting was a wake the watcher missed.
|
|
86
|
+
* @returns {'late'|null}
|
|
87
|
+
*/
|
|
88
|
+
function labelLateEnd({ lastDecision, terminalStatus } = {}) {
|
|
89
|
+
return lastDecision === 'KEEP_WAITING' && terminalStatus === 'failed' ? 'late' : null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Distinct `file:line` tokens cited by a report — the report's evidence count. */
|
|
93
|
+
const countReportRows = countReportCitations;
|
|
94
|
+
|
|
95
|
+
function _toMs(value) {
|
|
96
|
+
if (value == null) return null;
|
|
97
|
+
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null;
|
|
98
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : null;
|
|
99
|
+
const text = String(value).trim();
|
|
100
|
+
if (!text) return null;
|
|
101
|
+
// SQLite's datetime('now') is 'YYYY-MM-DD HH:MM:SS' in UTC — Date.parse reads that as local.
|
|
102
|
+
const iso = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}$/.test(text) ? `${text.replace(' ', 'T')}Z` : text;
|
|
103
|
+
const ms = Date.parse(iso);
|
|
104
|
+
return Number.isFinite(ms) ? ms : null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function _strOrNull(value) {
|
|
108
|
+
return typeof value === 'string' && value ? value : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function _boolOrNull(value) {
|
|
112
|
+
return typeof value === 'boolean' ? value : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** D-4: a citation count is a non-negative integer, or null when absent/unusable. */
|
|
116
|
+
function _countOrNull(value) {
|
|
117
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? Math.trunc(value) : null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* D-2: the one payload accessor. The recommended no-id wait nests the woken worker under
|
|
122
|
+
* `worker`; every other wait/status body carries its fields at the top level.
|
|
123
|
+
* @returns {object|null}
|
|
124
|
+
*/
|
|
125
|
+
function workerPayloadOf(res) {
|
|
126
|
+
if (!res || typeof res !== 'object') return null;
|
|
127
|
+
if (res.worker && typeof res.worker === 'object') return res.worker;
|
|
128
|
+
return res;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* D-1/D-4: the observed facts of one explore hand-off (all keys present; null when unknown).
|
|
133
|
+
* @param {object|null} payload the wait/status body, already unwrapped by workerPayloadOf
|
|
134
|
+
* @param {{opened_at?:number|string|Date|null, terminal_at?:number|string|Date|null,
|
|
135
|
+
* wait_variant?:string|null, woke_on?:string|null}} meta
|
|
136
|
+
*/
|
|
137
|
+
function factsFromPayload(payload, { opened_at, terminal_at, wait_variant, woke_on } = {}) {
|
|
138
|
+
const p = payload && typeof payload === 'object' ? payload : null;
|
|
139
|
+
const status = p ? _strOrNull(p.status) : null;
|
|
140
|
+
const source = p ? _strOrNull(p.report_source) : null;
|
|
141
|
+
const spend = p && p.spend && typeof p.spend === 'object' ? p.spend.usd : null;
|
|
142
|
+
return {
|
|
143
|
+
terminal_status: TERMINAL_STATUSES.has(status) ? status : null,
|
|
144
|
+
report_source: REPORT_SOURCES.has(source) ? source : null,
|
|
145
|
+
report_present: p ? _boolOrNull(p.report_present) : null,
|
|
146
|
+
report_citation_rows: p ? _countOrNull(p.report_citation_rows) : null,
|
|
147
|
+
report_chars: p ? _countOrNull(p.report_chars) : null,
|
|
148
|
+
report_path: p ? _strOrNull(p.report_path) : null,
|
|
149
|
+
last_message_path: p ? _strOrNull(p.last_message_path) : null,
|
|
150
|
+
worker_spend_usd: typeof spend === 'number' && Number.isFinite(spend) ? spend : null,
|
|
151
|
+
harness: p ? _strOrNull(p.harness) : null,
|
|
152
|
+
wait_variant: _strOrNull(wait_variant),
|
|
153
|
+
woke_on: _strOrNull(woke_on),
|
|
154
|
+
opened_at: _toMs(opened_at),
|
|
155
|
+
terminal_at: _toMs(terminal_at),
|
|
156
|
+
abandoned_at: null,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function _secondsBetween(openedAt, terminalAt) {
|
|
161
|
+
return Number.isFinite(openedAt) && Number.isFinite(terminalAt) ? (terminalAt - openedAt) / 1000 : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** D-4: the explore decision, exactly as written in the design. */
|
|
165
|
+
function _labelExplore(facts) {
|
|
166
|
+
const t = facts.terminal_status;
|
|
167
|
+
const s = facts.report_source;
|
|
168
|
+
const c = facts.report_citation_rows;
|
|
169
|
+
let decision;
|
|
170
|
+
if (facts.abandoned_at != null) decision = 'abandoned';
|
|
171
|
+
else if (t == null || c == null) decision = 'unmeasured';
|
|
172
|
+
else if (t === 'failed') decision = 'fallback';
|
|
173
|
+
else if ((t === 'report_ready' || t === 'exited') && REPORT_SOURCES.has(s) && c >= 1) decision = 'handoff';
|
|
174
|
+
else decision = 'fallback';
|
|
175
|
+
return {
|
|
176
|
+
decision,
|
|
177
|
+
label: null,
|
|
178
|
+
report_rows: decision === 'unmeasured' ? null : c,
|
|
179
|
+
helper_usd: facts.worker_spend_usd,
|
|
180
|
+
seconds_to_report: _secondsBetween(facts.opened_at, facts.terminal_at),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The same ACT_TOOLS rule as `_isUsefulNextCall`, applied to pre-computed next-call facts. */
|
|
185
|
+
function _usefulFromFacts(nextCall, workerId) {
|
|
186
|
+
const tool = nextCall && typeof nextCall.tool === 'string' ? nextCall.tool : '';
|
|
187
|
+
if (!tool) return false;
|
|
188
|
+
if (WAIT_TOOLS.has(tool)) return false;
|
|
189
|
+
return Boolean(workerId) && nextCall.names_worker === true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** §6.4: a wait-watch row's label — late beats dropped beats the useful/empty judgement. */
|
|
193
|
+
function _labelWaitWatch(facts) {
|
|
194
|
+
const f = facts && typeof facts === 'object' ? facts : {};
|
|
195
|
+
const silent = f.silent === true;
|
|
196
|
+
let label;
|
|
197
|
+
if (f.late === true) label = 'late';
|
|
198
|
+
else if (f.dropped === true) label = silent ? 'silent_empty' : 'empty';
|
|
199
|
+
else if (_usefulFromFacts(f.next_call, f.worker_id)) label = silent ? 'silent_useful' : 'useful';
|
|
200
|
+
else label = silent ? 'silent_empty' : 'empty';
|
|
201
|
+
return {
|
|
202
|
+
decision: typeof f.decision === 'string' ? f.decision : null,
|
|
203
|
+
label,
|
|
204
|
+
report_rows: null,
|
|
205
|
+
helper_usd: null,
|
|
206
|
+
seconds_to_report: null,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* D-1/D-4: derive the row's label from its stored facts. Pure and total — a malformed facts
|
|
212
|
+
* object reads as `unmeasured`, never a throw on the lead's tool-call path.
|
|
213
|
+
* @param {'explore'|'wait-watch'} kind
|
|
214
|
+
* @param {object} facts
|
|
215
|
+
* @returns {{decision:string|null, label:string|null, report_rows:number|null,
|
|
216
|
+
* helper_usd:number|null, seconds_to_report:number|null}}
|
|
217
|
+
*/
|
|
218
|
+
/** The one answer for "this row cannot be measured": D-7 excludes it from `closed`. */
|
|
219
|
+
const UNMEASURED = Object.freeze({
|
|
220
|
+
decision: 'unmeasured', label: null, report_rows: null, helper_usd: null, seconds_to_report: null,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
function labelFromFacts(kind, facts) {
|
|
224
|
+
try {
|
|
225
|
+
if (kind === 'explore') return _labelExplore(facts);
|
|
226
|
+
if (kind === 'wait-watch') return _labelWaitWatch(facts);
|
|
227
|
+
} catch {
|
|
228
|
+
// HANDLE: a facts object the rule cannot read is unmeasured, never a failed tool call.
|
|
229
|
+
return UNMEASURED;
|
|
230
|
+
}
|
|
231
|
+
// HANDLE: an unknown kind has no rule -- unmeasured is the honest reading, never a throw.
|
|
232
|
+
return UNMEASURED;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
module.exports = {
|
|
236
|
+
ACT_TOOLS,
|
|
237
|
+
LABEL_VERSION,
|
|
238
|
+
TERMINAL_STATUSES,
|
|
239
|
+
WAIT_TOOLS,
|
|
240
|
+
countReportRows,
|
|
241
|
+
factsFromPayload,
|
|
242
|
+
labelFromFacts,
|
|
243
|
+
labelLateEnd,
|
|
244
|
+
labelSilentTick,
|
|
245
|
+
labelWatcherWake,
|
|
246
|
+
workerPayloadOf,
|
|
247
|
+
};
|