@moretea-labs/forge 1.5.1 → 1.7.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/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +170 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +106 -3
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +898 -430
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation.ts +275 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
- package/docs/architecture/current/entity-model.md +0 -592
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -144
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -311
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- package/src/runtime/workflow/portfolio/types.ts +0 -29
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Forge Work efficiency benchmark.
|
|
5
|
+
*
|
|
6
|
+
* Measures end-to-end controller ceremony for a tiny, real repository change
|
|
7
|
+
* against isolated temporary repository/controller state. It compares the
|
|
8
|
+
* streamlined path (verify -> finalize) with the legacy-style ceremony
|
|
9
|
+
* (verify -> continue -> finalize) without mutating the Forge checkout.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'fs';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { spawnSync } from 'child_process';
|
|
15
|
+
import { createMcpToolContext } from '../src/cli/mcp/server';
|
|
16
|
+
import type { MultiRepositoryMcpToolContext } from '../src/cli/mcp/multi-repository';
|
|
17
|
+
import { ensureControllerHome } from '../src/cli/repositories/controller-home';
|
|
18
|
+
import { registerRepository } from '../src/cli/repositories/registry';
|
|
19
|
+
import { callRuntimeTool } from '../src/runtime/gateway/mcp/runtime-tools';
|
|
20
|
+
import { getWorkContract } from '../src/runtime/control-plane/facade/work-contract-store';
|
|
21
|
+
import { waitForProcess } from '../src/runtime/execution/process-runtime';
|
|
22
|
+
import { acquireRuntimeOwnership } from '../src/runtime/root/ownership';
|
|
23
|
+
import { forgeRuntimeServicePaths } from '../src/runtime/root/service';
|
|
24
|
+
import { writeRuntimeStatusSnapshot } from '../src/runtime/root/status';
|
|
25
|
+
import { ensureActiveRuntimeRelease } from '../src/runtime/root/release-store';
|
|
26
|
+
import { bindRuntimeWriteClaim, clearRuntimeWriteClaimForTests } from '../src/runtime/root/write-fence';
|
|
27
|
+
|
|
28
|
+
interface TimedCall {
|
|
29
|
+
elapsedMs: number;
|
|
30
|
+
value: Record<string, any>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface FlowSample {
|
|
34
|
+
mode: 'streamlined' | 'legacy_ceremony';
|
|
35
|
+
sample: number;
|
|
36
|
+
ok: boolean;
|
|
37
|
+
controllerCalls: number;
|
|
38
|
+
processWaits: number;
|
|
39
|
+
startMs: number;
|
|
40
|
+
verifySubmitMs: number;
|
|
41
|
+
verifyWaitMs: number;
|
|
42
|
+
verifyReattachMs: number;
|
|
43
|
+
continueMs: number;
|
|
44
|
+
finalizeMs: number;
|
|
45
|
+
totalMs: number;
|
|
46
|
+
verificationNextStep?: string;
|
|
47
|
+
finalStatus?: string;
|
|
48
|
+
cleanupComplete: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function argNumber(name: string, fallback: number): number {
|
|
52
|
+
const index = process.argv.indexOf(name);
|
|
53
|
+
if (index < 0) return fallback;
|
|
54
|
+
const parsed = Number(process.argv[index + 1]);
|
|
55
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function git(root: string, args: string[]): string {
|
|
59
|
+
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8' });
|
|
60
|
+
if (result.status !== 0) throw new Error(String(result.stderr || `git ${args.join(' ')} failed`));
|
|
61
|
+
return String(result.stdout ?? '').trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runtimeManifest(controllerHome: string): string {
|
|
65
|
+
const path = join(controllerHome, 'benchmark-runtime.manifest.json');
|
|
66
|
+
writeFileSync(path, JSON.stringify({
|
|
67
|
+
schemaVersion: 1,
|
|
68
|
+
releaseId: 'release-work-efficiency-benchmark',
|
|
69
|
+
artifactIdentity: 'artifact-work-efficiency-benchmark',
|
|
70
|
+
entrypoint: 'forge-runtime',
|
|
71
|
+
arguments: [],
|
|
72
|
+
configurationSchemaVersion: 1,
|
|
73
|
+
controllerHome,
|
|
74
|
+
databaseSchemaCompatibility: { minimum: 1, maximum: 1 },
|
|
75
|
+
workerProtocolVersion: 1,
|
|
76
|
+
createdAt: new Date().toISOString(),
|
|
77
|
+
}));
|
|
78
|
+
return path;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function createFixture(label: string) {
|
|
82
|
+
const root = mkdtempSync(join(tmpdir(), `forge-work-efficiency-${label}-`));
|
|
83
|
+
const controllerHome = join(root, 'controller');
|
|
84
|
+
const repoRoot = join(root, 'repo');
|
|
85
|
+
ensureControllerHome(controllerHome);
|
|
86
|
+
mkdirSync(repoRoot, { recursive: true });
|
|
87
|
+
git(repoRoot, ['init', '-b', 'main']);
|
|
88
|
+
git(repoRoot, ['config', 'user.name', 'Work Efficiency Benchmark']);
|
|
89
|
+
git(repoRoot, ['config', 'user.email', 'benchmark@example.test']);
|
|
90
|
+
writeFileSync(join(repoRoot, 'README.md'), 'fixture\n');
|
|
91
|
+
writeFileSync(join(repoRoot, 'package.json'), JSON.stringify({
|
|
92
|
+
name: `work-efficiency-${label}`,
|
|
93
|
+
private: true,
|
|
94
|
+
scripts: { 'check:bench': 'node -e "process.exit(0)"' },
|
|
95
|
+
}, null, 2));
|
|
96
|
+
git(repoRoot, ['add', '.']);
|
|
97
|
+
git(repoRoot, ['commit', '-m', 'fixture']);
|
|
98
|
+
|
|
99
|
+
const repository = registerRepository({ path: repoRoot, controllerHome, displayName: `work-efficiency-${label}` });
|
|
100
|
+
const owner = acquireRuntimeOwnership(controllerHome, `runtime-work-efficiency-${label}`);
|
|
101
|
+
const authority = ensureActiveRuntimeRelease(controllerHome, runtimeManifest(controllerHome));
|
|
102
|
+
bindRuntimeWriteClaim({ controllerHome, owner: owner.record, authority });
|
|
103
|
+
|
|
104
|
+
const runtimeService = forgeRuntimeServicePaths(controllerHome);
|
|
105
|
+
mkdirSync(runtimeService.serviceRoot, { recursive: true });
|
|
106
|
+
mkdirSync(join(controllerHome, 'mcp'), { recursive: true });
|
|
107
|
+
const runtimeTokenPath = join(controllerHome, 'mcp', 'runtime-token');
|
|
108
|
+
writeFileSync(runtimeTokenPath, `fixture-token-${label}\n`, { mode: 0o600 });
|
|
109
|
+
writeFileSync(runtimeService.configPath, JSON.stringify({
|
|
110
|
+
schemaVersion: 1,
|
|
111
|
+
controllerHome,
|
|
112
|
+
repositoryRoot: repoRoot,
|
|
113
|
+
host: '127.0.0.1',
|
|
114
|
+
port: 9876,
|
|
115
|
+
authTokenFile: runtimeTokenPath,
|
|
116
|
+
}));
|
|
117
|
+
const observedAt = new Date().toISOString();
|
|
118
|
+
writeRuntimeStatusSnapshot(controllerHome, {
|
|
119
|
+
schemaVersion: 1,
|
|
120
|
+
runtimeInstanceId: owner.record.runtimeInstanceId,
|
|
121
|
+
pid: owner.record.pid,
|
|
122
|
+
releaseId: authority.active.releaseId,
|
|
123
|
+
artifactIdentity: authority.active.artifactIdentity,
|
|
124
|
+
endpoint: 'http://127.0.0.1:9876/mcp',
|
|
125
|
+
readiness: {
|
|
126
|
+
ready: true,
|
|
127
|
+
reasonCodes: [],
|
|
128
|
+
diagnostics: {
|
|
129
|
+
database: { outcome: 'pass' },
|
|
130
|
+
scheduler: { outcome: 'pass' },
|
|
131
|
+
releaseCoherence: { outcome: 'pass' },
|
|
132
|
+
mcpEndToEnd: { outcome: 'pass' },
|
|
133
|
+
},
|
|
134
|
+
observedAt,
|
|
135
|
+
},
|
|
136
|
+
startedAt: observedAt,
|
|
137
|
+
updatedAt: observedAt,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const ctx = createMcpToolContext({
|
|
141
|
+
controllerHome,
|
|
142
|
+
profile: 'controller',
|
|
143
|
+
repo: repoRoot,
|
|
144
|
+
sessionId: `mcp-work-efficiency-${label}`,
|
|
145
|
+
principalId: `principal-work-efficiency-${label}`,
|
|
146
|
+
controllerInstanceId: owner.record.runtimeInstanceId,
|
|
147
|
+
}) as MultiRepositoryMcpToolContext;
|
|
148
|
+
return { root, controllerHome, repoRoot, repository, ctx };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function timedCall(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>): Promise<TimedCall> {
|
|
152
|
+
const startedAt = performance.now();
|
|
153
|
+
const result = await callRuntimeTool(ctx, 'rh_work', args);
|
|
154
|
+
const elapsedMs = Math.round((performance.now() - startedAt) * 100) / 100;
|
|
155
|
+
if (!result) throw new Error('rh_work returned no benchmark result');
|
|
156
|
+
const value = (result.structuredContent ?? JSON.parse(result.content?.[0]?.text ?? '{}')) as Record<string, any>;
|
|
157
|
+
return { elapsedMs, value };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function runFlow(mode: FlowSample['mode'], sample: number): Promise<FlowSample> {
|
|
161
|
+
const label = `${mode}-${sample}-${Date.now()}`;
|
|
162
|
+
const fx = createFixture(label);
|
|
163
|
+
const wallStartedAt = performance.now();
|
|
164
|
+
let controllerCalls = 0;
|
|
165
|
+
let processWaits = 0;
|
|
166
|
+
try {
|
|
167
|
+
const started = await timedCall(fx.ctx, {
|
|
168
|
+
repo_id: fx.repository.repoId,
|
|
169
|
+
operation: 'start',
|
|
170
|
+
objective: `Benchmark ${mode} work lifecycle`,
|
|
171
|
+
scope_clear: true,
|
|
172
|
+
expected_files: 1,
|
|
173
|
+
expected_changed_lines: 1,
|
|
174
|
+
requires_recovery: true,
|
|
175
|
+
allowed_paths: ['README.md'],
|
|
176
|
+
check_ids: ['package:check:bench'],
|
|
177
|
+
constraints: { workspaceMode: 'isolated' },
|
|
178
|
+
request_id: `work-efficiency-start-${label}`,
|
|
179
|
+
});
|
|
180
|
+
controllerCalls += 1;
|
|
181
|
+
const workId = String(started.value.data?.work?.workId ?? '');
|
|
182
|
+
if (!workId) throw new Error('benchmark Work was not created');
|
|
183
|
+
const store = { controllerHome: fx.controllerHome, repoId: fx.repository.repoId };
|
|
184
|
+
const contract = getWorkContract(store, workId);
|
|
185
|
+
if (!contract?.worktreeRef) throw new Error('benchmark Work has no managed worktree');
|
|
186
|
+
writeFileSync(join(contract.worktreeRef, 'README.md'), `fixture\n${mode}\n`);
|
|
187
|
+
|
|
188
|
+
const verifyArgs = {
|
|
189
|
+
repo_id: fx.repository.repoId,
|
|
190
|
+
operation: 'verify',
|
|
191
|
+
work_id: workId,
|
|
192
|
+
check_id: 'package:check:bench',
|
|
193
|
+
request_id: `work-efficiency-verify-${label}`,
|
|
194
|
+
};
|
|
195
|
+
const verifySubmit = await timedCall(fx.ctx, verifyArgs);
|
|
196
|
+
controllerCalls += 1;
|
|
197
|
+
const processId = String(verifySubmit.value.data?.verification?.processId ?? '');
|
|
198
|
+
if (!processId) throw new Error('benchmark verification did not return a Process id');
|
|
199
|
+
const waitStartedAt = performance.now();
|
|
200
|
+
await waitForProcess(fx.controllerHome, fx.repository.repoId, processId, { timeoutMs: 10_000 });
|
|
201
|
+
const verifyWaitMs = Math.round((performance.now() - waitStartedAt) * 100) / 100;
|
|
202
|
+
processWaits += 1;
|
|
203
|
+
|
|
204
|
+
const verifyReattach = await timedCall(fx.ctx, verifyArgs);
|
|
205
|
+
controllerCalls += 1;
|
|
206
|
+
const verificationOutcome = String(verifyReattach.value.data?.verification?.outcome ?? '');
|
|
207
|
+
const verificationNextStep = typeof verifyReattach.value.data?.nextStep === 'string'
|
|
208
|
+
? verifyReattach.value.data.nextStep
|
|
209
|
+
: undefined;
|
|
210
|
+
if (verificationOutcome !== 'valid_pass') throw new Error(`benchmark verification outcome: ${verificationOutcome}`);
|
|
211
|
+
|
|
212
|
+
let continueMs = 0;
|
|
213
|
+
if (mode === 'legacy_ceremony') {
|
|
214
|
+
const continued = await timedCall(fx.ctx, {
|
|
215
|
+
repo_id: fx.repository.repoId,
|
|
216
|
+
operation: 'continue',
|
|
217
|
+
work_id: workId,
|
|
218
|
+
});
|
|
219
|
+
controllerCalls += 1;
|
|
220
|
+
continueMs = continued.elapsedMs;
|
|
221
|
+
if (continued.value.data?.nextStep !== 'finalize') throw new Error('legacy ceremony did not reach finalize');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const finalized = await timedCall(fx.ctx, {
|
|
225
|
+
repo_id: fx.repository.repoId,
|
|
226
|
+
operation: 'finalize',
|
|
227
|
+
work_id: workId,
|
|
228
|
+
});
|
|
229
|
+
controllerCalls += 1;
|
|
230
|
+
const finalStatus = String(finalized.value.data?.finalStatus ?? '');
|
|
231
|
+
const cleanupComplete = !existsSync(contract.worktreeRef);
|
|
232
|
+
const totalMs = Math.round((performance.now() - wallStartedAt) * 100) / 100;
|
|
233
|
+
return {
|
|
234
|
+
mode,
|
|
235
|
+
sample,
|
|
236
|
+
ok: finalStatus === 'completed' && cleanupComplete,
|
|
237
|
+
controllerCalls,
|
|
238
|
+
processWaits,
|
|
239
|
+
startMs: started.elapsedMs,
|
|
240
|
+
verifySubmitMs: verifySubmit.elapsedMs,
|
|
241
|
+
verifyWaitMs,
|
|
242
|
+
verifyReattachMs: verifyReattach.elapsedMs,
|
|
243
|
+
continueMs,
|
|
244
|
+
finalizeMs: finalized.elapsedMs,
|
|
245
|
+
totalMs,
|
|
246
|
+
verificationNextStep,
|
|
247
|
+
finalStatus,
|
|
248
|
+
cleanupComplete,
|
|
249
|
+
};
|
|
250
|
+
} finally {
|
|
251
|
+
clearRuntimeWriteClaimForTests();
|
|
252
|
+
rmSync(fx.root, { recursive: true, force: true });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function percentile(values: number[], p: number): number {
|
|
257
|
+
if (values.length === 0) return 0;
|
|
258
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
259
|
+
const index = Math.min(sorted.length - 1, Math.ceil(sorted.length * p) - 1);
|
|
260
|
+
return Math.round((sorted[Math.max(0, index)] ?? 0) * 100) / 100;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function summarize(samples: FlowSample[]) {
|
|
264
|
+
return {
|
|
265
|
+
count: samples.length,
|
|
266
|
+
allOk: samples.every((sample) => sample.ok),
|
|
267
|
+
controllerCalls: samples[0]?.controllerCalls ?? 0,
|
|
268
|
+
processWaits: samples[0]?.processWaits ?? 0,
|
|
269
|
+
totalMs: {
|
|
270
|
+
p50: percentile(samples.map((sample) => sample.totalMs), 0.5),
|
|
271
|
+
p95: percentile(samples.map((sample) => sample.totalMs), 0.95),
|
|
272
|
+
},
|
|
273
|
+
startMs: { p50: percentile(samples.map((sample) => sample.startMs), 0.5), p95: percentile(samples.map((sample) => sample.startMs), 0.95) },
|
|
274
|
+
verifyWallMs: {
|
|
275
|
+
p50: percentile(samples.map((sample) => sample.verifySubmitMs + sample.verifyWaitMs + sample.verifyReattachMs), 0.5),
|
|
276
|
+
p95: percentile(samples.map((sample) => sample.verifySubmitMs + sample.verifyWaitMs + sample.verifyReattachMs), 0.95),
|
|
277
|
+
},
|
|
278
|
+
continueMs: { p50: percentile(samples.map((sample) => sample.continueMs), 0.5), p95: percentile(samples.map((sample) => sample.continueMs), 0.95) },
|
|
279
|
+
finalizeMs: { p50: percentile(samples.map((sample) => sample.finalizeMs), 0.5), p95: percentile(samples.map((sample) => sample.finalizeMs), 0.95) },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function main(): Promise<void> {
|
|
284
|
+
const sampleCount = Math.min(argNumber('--samples', 3), 10);
|
|
285
|
+
const sourceHeadBefore = git(process.cwd(), ['rev-parse', 'HEAD']);
|
|
286
|
+
const streamlined: FlowSample[] = [];
|
|
287
|
+
const legacy: FlowSample[] = [];
|
|
288
|
+
|
|
289
|
+
for (let sample = 1; sample <= sampleCount; sample += 1) {
|
|
290
|
+
if (sample % 2 === 1) {
|
|
291
|
+
streamlined.push(await runFlow('streamlined', sample));
|
|
292
|
+
legacy.push(await runFlow('legacy_ceremony', sample));
|
|
293
|
+
} else {
|
|
294
|
+
legacy.push(await runFlow('legacy_ceremony', sample));
|
|
295
|
+
streamlined.push(await runFlow('streamlined', sample));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const sourceHeadAfter = git(process.cwd(), ['rev-parse', 'HEAD']);
|
|
300
|
+
const streamlinedSummary = summarize(streamlined);
|
|
301
|
+
const legacySummary = summarize(legacy);
|
|
302
|
+
const result = {
|
|
303
|
+
schemaVersion: 1,
|
|
304
|
+
benchmark: 'work-efficiency',
|
|
305
|
+
revision: sourceHeadAfter,
|
|
306
|
+
generatedAt: new Date().toISOString(),
|
|
307
|
+
sampleCount,
|
|
308
|
+
methodology: 'Real rh_work start + managed Check Process + authoritative reattach + finalize on isolated temporary repositories. Legacy comparison adds only the mechanical continue call.',
|
|
309
|
+
streamlined: streamlinedSummary,
|
|
310
|
+
legacyCeremony: legacySummary,
|
|
311
|
+
productivity: {
|
|
312
|
+
controllerCallsSavedPerWork: legacySummary.controllerCalls - streamlinedSummary.controllerCalls,
|
|
313
|
+
controlRoundTripReductionRatio: legacySummary.controllerCalls > 0
|
|
314
|
+
? Math.round(((legacySummary.controllerCalls - streamlinedSummary.controllerCalls) / legacySummary.controllerCalls) * 10_000) / 10_000
|
|
315
|
+
: 0,
|
|
316
|
+
measuredContinueCeremonyMsP50: legacySummary.continueMs.p50,
|
|
317
|
+
totalWallClockDeltaMsP50: Math.round((legacySummary.totalMs.p50 - streamlinedSummary.totalMs.p50) * 100) / 100,
|
|
318
|
+
},
|
|
319
|
+
acceptance: {
|
|
320
|
+
sourceCheckoutHeadStable: sourceHeadBefore === sourceHeadAfter,
|
|
321
|
+
streamlinedAllOk: streamlinedSummary.allOk,
|
|
322
|
+
legacyAllOk: legacySummary.allOk,
|
|
323
|
+
streamlinedDirectsFinalPassToFinalize: streamlined.every((sample) => sample.verificationNextStep === 'finalize'),
|
|
324
|
+
oneControllerCallSaved: legacySummary.controllerCalls - streamlinedSummary.controllerCalls === 1,
|
|
325
|
+
cleanupComplete: [...streamlined, ...legacy].every((sample) => sample.cleanupComplete),
|
|
326
|
+
},
|
|
327
|
+
samples: { streamlined, legacyCeremony: legacy },
|
|
328
|
+
};
|
|
329
|
+
const allAccepted = Object.values(result.acceptance).every(Boolean);
|
|
330
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
331
|
+
if (!allAccepted) process.exitCode = 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
await main();
|
package/scripts/capture-plan.sh
CHANGED
|
@@ -266,7 +266,7 @@ Use the captured planning output below as the execution source of truth.
|
|
|
266
266
|
### Trade-offs
|
|
267
267
|
| Option | Pros | Cons | Decision |
|
|
268
268
|
|--------|------|------|----------|
|
|
269
|
-
| Captured plan | Preserves the approved
|
|
269
|
+
| Captured plan | Preserves the approved Codex Plan or Waza think decision | Requires the captured text to be concrete enough to execute | Use |
|
|
270
270
|
|
|
271
271
|
## Detailed Design
|
|
272
272
|
### File Changes
|
|
@@ -302,8 +302,8 @@ See captured planning output.
|
|
|
302
302
|
|
|
303
303
|
- **State/progress path**: \`${plan_file}\` task breakdown, \`tasks/todos.md\` deferred-goal ledger, \`tasks/contracts/${artifact_stem}.contract.md\`, \`tasks/reviews/${artifact_stem}.review.md\`, and \`tasks/notes/${artifact_stem}.notes.md\`
|
|
304
304
|
- **Verification evidence**: \`.ai/harness/checks/latest.json\`, \`.ai/harness/runs/\`, and the commands named in the captured planning output
|
|
305
|
-
- **
|
|
306
|
-
- **Stop condition**: all task breakdown items are complete
|
|
305
|
+
- **Impact review**: after direct checks, reassess user intent, affected domains, downstream consumers, state transitions, and residual risks
|
|
306
|
+
- **Stop condition**: all task breakdown items are complete and sprint verification reports direct checks plus declared scope passing
|
|
307
307
|
- **Rollback surface**: before execution remove \`${plan_file}\`; after execution revert branch \`codex/${slug}\` or the generated task artifacts
|
|
308
308
|
|
|
309
309
|
## Captured Planning Output
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
if command -v
|
|
4
|
+
if command -v node >/dev/null 2>&1; then
|
|
5
|
+
RUNTIME_BIN="$(command -v node)"
|
|
6
|
+
elif command -v bun >/dev/null 2>&1; then
|
|
5
7
|
RUNTIME_BIN="$(command -v bun)"
|
|
6
8
|
elif [[ -x "${HOME}/.bun/bin/bun" ]]; then
|
|
7
9
|
RUNTIME_BIN="${HOME}/.bun/bin/bun"
|
|
8
|
-
elif command -v node >/dev/null 2>&1; then
|
|
9
|
-
RUNTIME_BIN="$(command -v node)"
|
|
10
10
|
else
|
|
11
|
-
echo "check-agent-tooling.sh requires
|
|
11
|
+
echo "check-agent-tooling.sh requires node or bun" >&2
|
|
12
12
|
exit 1
|
|
13
13
|
fi
|
|
14
14
|
|
|
15
|
-
export FORGE_TOOLING_PATH_SNAPSHOT="${PATH:-}"
|
|
16
15
|
exec "$RUNTIME_BIN" - "$@" <<'NODE_EOF'
|
|
17
16
|
const fs = require("fs");
|
|
18
17
|
const crypto = require("crypto");
|
|
@@ -77,7 +76,6 @@ const WAZA_RAW_BASE_URL = "https://raw.githubusercontent.com/tw93/Waza/main";
|
|
|
77
76
|
const WAZA_MANAGED_SKILLS = ["think", "hunt", "check", "health"];
|
|
78
77
|
const WAZA_SHARED_RULES = ["anti-patterns.md", "chinese.md", "durable-context.md", "english.md"];
|
|
79
78
|
const CODEX_AUTOMATION_SKILLS = ["health", "check", "mermaid"];
|
|
80
|
-
const SKILLS_CLI_TIMEOUT_MS = 5000;
|
|
81
79
|
const CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
|
|
82
80
|
const CODEGRAPH_GLOBAL_INSTALL_COMMAND = `bun add -g ${CODEGRAPH_PACKAGE} && forge tools configure codegraph --target codex --location global`;
|
|
83
81
|
const GBRAIN_INSTALL_COMMAND = "bun install -g github:garrytan/gbrain";
|
|
@@ -140,21 +138,7 @@ function fileIsExecutable(filePath) {
|
|
|
140
138
|
|
|
141
139
|
function detectTimeoutBin() {
|
|
142
140
|
if (timeoutBin !== undefined) return timeoutBin;
|
|
143
|
-
|
|
144
|
-
if (!candidate) {
|
|
145
|
-
timeoutBin = "";
|
|
146
|
-
return timeoutBin;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const capability = spawnSync(candidate, ["--version"], {
|
|
150
|
-
encoding: "utf8",
|
|
151
|
-
timeout: 500,
|
|
152
|
-
env: process.env,
|
|
153
|
-
});
|
|
154
|
-
const output = `${capability.stdout || ""}\n${capability.stderr || ""}`;
|
|
155
|
-
timeoutBin = capability.status === 0 && /GNU coreutils|coreutils/i.test(output)
|
|
156
|
-
? candidate
|
|
157
|
-
: "";
|
|
141
|
+
timeoutBin = resolvePathCommand("timeout") || "";
|
|
158
142
|
return timeoutBin;
|
|
159
143
|
}
|
|
160
144
|
|
|
@@ -705,7 +689,7 @@ function detectWaza() {
|
|
|
705
689
|
const skillLock = readJson(skillLockPath);
|
|
706
690
|
const skillsBin = resolvePathCommand("skills");
|
|
707
691
|
const skillsResult = skillsBin
|
|
708
|
-
? run(skillsBin, ["ls", "-g", "--json"], { timeoutMs:
|
|
692
|
+
? run(skillsBin, ["ls", "-g", "--json"], { timeoutMs: 1500 })
|
|
709
693
|
: { ok: false, status: null, stdout: "", stderr: "", error: "skills CLI is not installed", timed_out: false };
|
|
710
694
|
const skillItems = skillsResult.ok ? parseJson(skillsResult.stdout) || [] : [];
|
|
711
695
|
const wazaEntries = Object.entries(skillLock?.skills || {}).filter(([, meta]) => meta?.source === WAZA_SOURCE_REPO);
|
|
@@ -1178,7 +1162,7 @@ function parseCodeGraphProjectStatus(output) {
|
|
|
1178
1162
|
}
|
|
1179
1163
|
|
|
1180
1164
|
function resolvePathCommand(command) {
|
|
1181
|
-
const pathValue = process.env.
|
|
1165
|
+
const pathValue = process.env.PATH || "";
|
|
1182
1166
|
for (const dir of pathValue.split(path.delimiter)) {
|
|
1183
1167
|
if (!dir) continue;
|
|
1184
1168
|
const candidate = path.join(dir, command);
|
|
@@ -1203,18 +1187,7 @@ function codeGraphPlatformPackageName() {
|
|
|
1203
1187
|
|
|
1204
1188
|
function codeGraphPlatformBundleBin() {
|
|
1205
1189
|
if (process.platform === "win32") return null;
|
|
1206
|
-
|
|
1207
|
-
if (fileIsExecutable(direct)) return direct;
|
|
1208
|
-
// Git worktrees commonly reuse the canonical checkout's dependencies. Resolve
|
|
1209
|
-
// the platform package through Node/Bun module lookup instead of declaring the
|
|
1210
|
-
// bundled Runtime missing just because this worktree has no local node_modules.
|
|
1211
|
-
try {
|
|
1212
|
-
const packageJson = require.resolve(`${codeGraphPlatformPackageName()}/package.json`, { paths: [REPO_ROOT] });
|
|
1213
|
-
const resolved = path.join(path.dirname(packageJson), "bin", "codegraph");
|
|
1214
|
-
return fileIsExecutable(resolved) ? resolved : direct;
|
|
1215
|
-
} catch {
|
|
1216
|
-
return direct;
|
|
1217
|
-
}
|
|
1190
|
+
return path.join(REPO_ROOT, "node_modules", codeGraphPlatformPackageName(), "bin", "codegraph");
|
|
1218
1191
|
}
|
|
1219
1192
|
|
|
1220
1193
|
function resolveCodeGraphBinary() {
|
|
@@ -19,85 +19,6 @@ target_branch=""
|
|
|
19
19
|
changed_files_file=""
|
|
20
20
|
format="text"
|
|
21
21
|
|
|
22
|
-
required_current_docs=(
|
|
23
|
-
"docs/architecture/current/README.md"
|
|
24
|
-
"docs/architecture/current/governance.md"
|
|
25
|
-
"docs/architecture/current/system-overview.md"
|
|
26
|
-
"docs/architecture/current/architecture-invariants.md"
|
|
27
|
-
"docs/architecture/current/entity-model.md"
|
|
28
|
-
"docs/architecture/current/job-and-run-lifecycle.md"
|
|
29
|
-
"docs/architecture/current/dispatch-and-agent-strategy.md"
|
|
30
|
-
"docs/architecture/current/scheduler-and-resource-claims.md"
|
|
31
|
-
"docs/architecture/current/multi-repository-execution.md"
|
|
32
|
-
"docs/architecture/current/automation-and-schedule-engine.md"
|
|
33
|
-
"docs/architecture/current/failure-recovery.md"
|
|
34
|
-
"docs/architecture/current/verification-and-release-gates.md"
|
|
35
|
-
"docs/architecture/current/implementation-status.md"
|
|
36
|
-
"docs/architecture/current/migration-roadmap.md"
|
|
37
|
-
"docs/architecture/current/runtime-directory-map.md"
|
|
38
|
-
"docs/architecture/current/operations-runbook.md"
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
historical_runtime_docs=(
|
|
42
|
-
"docs/architecture/history.md"
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
runtime_architecture_gate_enabled() {
|
|
46
|
-
[[ -d "docs/architecture/current" ]] && return 0
|
|
47
|
-
local file
|
|
48
|
-
for file in "${historical_runtime_docs[@]}"; do
|
|
49
|
-
[[ -f "$file" ]] && return 0
|
|
50
|
-
done
|
|
51
|
-
[[ -f "docs/architecture/index.md" ]] && grep -Fq -- "Controller Runtime" "docs/architecture/index.md"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
architecture_baseline_fail() {
|
|
55
|
-
echo "[ArchitectureSync] current Controller Runtime architecture baseline failed: $1" >&2
|
|
56
|
-
return 1
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
require_architecture_file() {
|
|
60
|
-
local file="$1"
|
|
61
|
-
[[ -f "$file" ]] || architecture_baseline_fail "missing required file $file"
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
require_architecture_text() {
|
|
65
|
-
local file="$1"
|
|
66
|
-
local text="$2"
|
|
67
|
-
if ! require_architecture_file "$file"; then
|
|
68
|
-
return 1
|
|
69
|
-
fi
|
|
70
|
-
grep -Fq -- "$text" "$file" || architecture_baseline_fail "$file must contain: $text"
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
check_runtime_architecture_baseline() {
|
|
74
|
-
local file
|
|
75
|
-
local failed=0
|
|
76
|
-
require_architecture_text "docs/architecture/index.md" "Runtime Authority" || failed=1
|
|
77
|
-
require_architecture_text "docs/architecture/index.md" "docs/architecture/current/" || failed=1
|
|
78
|
-
require_architecture_text "docs/architecture/current/README.md" "Runtime Authority" || failed=1
|
|
79
|
-
require_architecture_text "docs/architecture/current/governance.md" "Runtime Authority" || failed=1
|
|
80
|
-
|
|
81
|
-
for file in "${required_current_docs[@]}"; do
|
|
82
|
-
require_architecture_file "$file" || failed=1
|
|
83
|
-
done
|
|
84
|
-
|
|
85
|
-
for file in "${historical_runtime_docs[@]}"; do
|
|
86
|
-
require_architecture_text "$file" "Historical Design" || failed=1
|
|
87
|
-
require_architecture_text "$file" "Not Runtime Authority" || failed=1
|
|
88
|
-
require_architecture_text "$file" "docs/architecture/current/README.md" || failed=1
|
|
89
|
-
done
|
|
90
|
-
|
|
91
|
-
require_architecture_text "docs/architecture/current/architecture-invariants.md" "Invariant 2 — Persist Before Execute" || failed=1
|
|
92
|
-
require_architecture_text "docs/architecture/current/architecture-invariants.md" "Invariant 4 — Task Is Intent; Run Is Attempt" || failed=1
|
|
93
|
-
require_architecture_text "docs/architecture/current/architecture-invariants.md" "Invariant 16 — Evidence Binds to Exact Revision" || failed=1
|
|
94
|
-
require_architecture_text "docs/architecture/current/architecture-invariants.md" "Invariant 21 — Scheduled Work Is Bounded" || failed=1
|
|
95
|
-
require_architecture_text "docs/architecture/current/implementation-status.md" "## Completion Statement" || failed=1
|
|
96
|
-
require_architecture_text "docs/architecture/current/migration-roadmap.md" "## P0" || failed=1
|
|
97
|
-
require_architecture_text "docs/architecture/current/migration-roadmap.md" "## P5" || failed=1
|
|
98
|
-
return "$failed"
|
|
99
|
-
}
|
|
100
|
-
|
|
101
22
|
while [[ $# -gt 0 ]]; do
|
|
102
23
|
case "$1" in
|
|
103
24
|
--mode)
|
|
@@ -277,13 +198,6 @@ case "$mode" in
|
|
|
277
198
|
;;
|
|
278
199
|
esac
|
|
279
200
|
|
|
280
|
-
# Structural authority checks are invariant and must run even when freshness gating is disabled.
|
|
281
|
-
if runtime_architecture_gate_enabled; then
|
|
282
|
-
if ! check_runtime_architecture_baseline; then
|
|
283
|
-
exit 1
|
|
284
|
-
fi
|
|
285
|
-
fi
|
|
286
|
-
|
|
287
201
|
if [[ ! -x "scripts/architecture-queue.sh" ]]; then
|
|
288
202
|
if [[ "$mode" == "strict" ]]; then
|
|
289
203
|
echo "[ArchitectureSync] strict gate failed: missing scripts/architecture-queue.sh" >&2
|
|
@@ -298,6 +212,23 @@ if ! bash scripts/architecture-queue.sh reindex --check >/dev/null; then
|
|
|
298
212
|
exit 1
|
|
299
213
|
fi
|
|
300
214
|
|
|
215
|
+
if [[ -f "docs/architecture/current/README.md" ]]; then
|
|
216
|
+
if [[ ! -f "docs/architecture/CURRENT.md" ]]; then
|
|
217
|
+
echo "[ArchitectureSync] architecture baseline failed: missing required file docs/architecture/CURRENT.md" >&2
|
|
218
|
+
exit 1
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
if ! grep -Fq "Runtime Authority" "docs/architecture/CURRENT.md"; then
|
|
222
|
+
echo "[ArchitectureSync] architecture baseline failed: docs/architecture/CURRENT.md must contain: Runtime Authority" >&2
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
if ! grep -Fq "Not Runtime Authority" "docs/architecture/current/README.md"; then
|
|
227
|
+
echo "[ArchitectureSync] architecture baseline failed: docs/architecture/current/README.md must contain: Not Runtime Authority" >&2
|
|
228
|
+
exit 1
|
|
229
|
+
fi
|
|
230
|
+
fi
|
|
231
|
+
|
|
301
232
|
if [[ "$mode" == "off" ]]; then
|
|
302
233
|
case "$format" in
|
|
303
234
|
json) printf '{"mode":"off","changed_capabilities":0,"blocking":0}\n' ;;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
1
2
|
import { FORGE_TOOL_SURFACE, FORGE_VERSION, forgeToolSurfaceFingerprint } from '../src/cli/controller/runtime-config';
|
|
2
3
|
import { runtimePolicy } from '../src/cli/mcp/multi-repository';
|
|
3
4
|
import { buildMcpToolDefinitions } from '../src/cli/mcp/tools';
|
|
@@ -48,6 +49,16 @@ const missingCatalog = catalogNames.filter((name) => !fullNames.includes(name));
|
|
|
48
49
|
const sourceCollisions = Object.entries(sourceGroups).flatMap(([group, names], groupIndex, entries) =>
|
|
49
50
|
names.filter((name) => entries.slice(0, groupIndex).some(([, earlier]) => earlier.includes(name)))
|
|
50
51
|
.map((name) => `${group}:${name}`));
|
|
52
|
+
const currentToolNames = new Set([
|
|
53
|
+
...sourceGroups.runtime,
|
|
54
|
+
...sourceGroups.execution,
|
|
55
|
+
...sourceGroups.process,
|
|
56
|
+
...sourceGroups.access,
|
|
57
|
+
...sourceGroups.repository,
|
|
58
|
+
]);
|
|
59
|
+
const legacyHandlerSource = readFileSync(new URL('../src/cli/mcp/legacy-tool-service.ts', import.meta.url), 'utf8');
|
|
60
|
+
const legacyHandlerNames = [...legacyHandlerSource.matchAll(/case\s+["']([^"']+)["']\s*:/g)].map((match) => match[1]);
|
|
61
|
+
const legacyHandlerCollisions = [...new Set(legacyHandlerNames.filter((name) => currentToolNames.has(name)))].sort();
|
|
51
62
|
|
|
52
63
|
const failures: string[] = [];
|
|
53
64
|
if (defaultNames.length > MAX_DEFAULT_TOOL_COUNT) {
|
|
@@ -56,6 +67,8 @@ if (defaultNames.length > MAX_DEFAULT_TOOL_COUNT) {
|
|
|
56
67
|
if (duplicateDefault.length) failures.push(`default duplicate names: ${[...new Set(duplicateDefault)].join(', ')}`);
|
|
57
68
|
if (missingDefault.length) failures.push(`default tools missing from registered definitions: ${missingDefault.join(', ')}`);
|
|
58
69
|
if (missingCatalog.length) failures.push(`compatibility catalog tools missing from registered definitions: ${missingCatalog.join(', ')}`);
|
|
70
|
+
if (sourceCollisions.length) failures.push(`tool schema authority collisions: ${sourceCollisions.join(', ')}`);
|
|
71
|
+
if (legacyHandlerCollisions.length) failures.push(`legacy execution authority collisions: ${legacyHandlerCollisions.join(', ')}`);
|
|
59
72
|
if (coreNames.join('\n') !== defaultNames.join('\n')) {
|
|
60
73
|
failures.push('core surface must alias the bounded default ChatGPT surface');
|
|
61
74
|
}
|
|
@@ -89,5 +102,6 @@ console.log(JSON.stringify({
|
|
|
89
102
|
fullCompatibilityFingerprint: fullFingerprint,
|
|
90
103
|
sourceToolCounts: Object.fromEntries(Object.entries(sourceGroups).map(([name, tools]) => [name, tools.length])),
|
|
91
104
|
sourceCollisions: [...new Set(sourceCollisions)].sort(),
|
|
105
|
+
legacyHandlerCollisions,
|
|
92
106
|
accessModeChangesSchema: false,
|
|
93
107
|
}, null, 2));
|
|
@@ -72,9 +72,22 @@ grep -q "$README_CHANNEL_EN" README.md || { echo "[public-docs] English README m
|
|
|
72
72
|
grep -q "$README_CHANNEL_ZH" README.zh-CN.md || { echo "[public-docs] Chinese README must state the npm channel for $PACKAGE_VERSION" >&2; exit 1; }
|
|
73
73
|
grep -q 'See \[README.md\](README.md)' README.en.md || { echo "[public-docs] README.en.md must point to the maintained English README" >&2; exit 1; }
|
|
74
74
|
|
|
75
|
+
source_install_docs=(
|
|
76
|
+
README.md README.zh-CN.md
|
|
77
|
+
docs/tutorials/01-install-and-start.md docs/tutorials/01-install-and-start.zh-CN.md
|
|
78
|
+
docs/wiki/Quick-Start.md docs/wiki/Installation.md
|
|
79
|
+
)
|
|
80
|
+
for path in "${source_install_docs[@]}"; do
|
|
81
|
+
grep -q 'bun install --frozen-lockfile' "$path" || { echo "[public-docs] source checkout must use the CI-authoritative Bun frozen lock: $path" >&2; exit 1; }
|
|
82
|
+
grep -q 'npm install -g \.' "$path" || { echo "[public-docs] missing source package install: $path" >&2; exit 1; }
|
|
83
|
+
done
|
|
84
|
+
if git grep -n 'npm ci --ignore-scripts --no-audit --no-fund' -- "${source_install_docs[@]}" >/dev/null; then
|
|
85
|
+
echo "[public-docs] generic npm ci must not be advertised for Forge source checkouts" >&2
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
|
|
75
89
|
for path in docs/tutorials/01-install-and-start.md docs/tutorials/01-install-and-start.zh-CN.md; do
|
|
76
90
|
grep -q 'Node.js 20.10' "$path" || { echo "[public-docs] missing Node baseline: $path" >&2; exit 1; }
|
|
77
|
-
grep -q 'npm install -g \.' "$path" || { echo "[public-docs] missing source install: $path" >&2; exit 1; }
|
|
78
91
|
grep -q "$INSTALL_SPEC" "$path" || { echo "[public-docs] missing package command for $PACKAGE_VERSION: $path" >&2; exit 1; }
|
|
79
92
|
done
|
|
80
93
|
|