@moretea-labs/forge 1.5.0 → 1.6.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.
Files changed (138) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/DESIGN.md +7 -2
  3. package/README.md +7 -7
  4. package/README.zh-CN.md +5 -3
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/assets/hooks/pre-edit-guard.sh +8 -39
  7. package/assets/hooks/prompt-guard.sh +2 -2
  8. package/assets/plugin-registry.v1.json +54 -3
  9. package/assets/reference-configs/hook-operations.md +1 -1
  10. package/assets/reference-configs/sprint-contracts.md +2 -2
  11. package/assets/skill-version.json +2 -2
  12. package/assets/templates/helpers/ensure-task-workflow.sh +2 -2
  13. package/assets/templates/helpers/sprint-backlog.sh +6 -6
  14. package/docs/architecture/current/automation-and-schedule-engine.md +9 -3
  15. package/docs/architecture/current/codegraph-context-provider.md +15 -3
  16. package/docs/architecture/current/dispatch-and-agent-strategy.md +32 -13
  17. package/docs/architecture/current/entity-model.md +20 -0
  18. package/docs/architecture/current/external-plugin-governance.md +3 -3
  19. package/docs/architecture/current/system-overview.md +26 -1
  20. package/docs/architecture/current/thin-harness-v1.md +10 -0
  21. package/docs/forge-chatgpt-mcp-setup.md +27 -3
  22. package/docs/operations/chatgpt-personal-assistant-runtime.md +12 -2
  23. package/docs/operations/controller-browser-plugin.md +12 -16
  24. package/docs/operations/features.md +1 -1
  25. package/docs/operations/homebrew.md +2 -2
  26. package/docs/public-usage-guide.md +1 -1
  27. package/docs/public-usage-guide.zh-CN.md +1 -1
  28. package/docs/tutorials/01-install-and-start.md +6 -4
  29. package/docs/tutorials/01-install-and-start.zh-CN.md +3 -1
  30. package/docs/tutorials/02-connect-chatgpt.md +8 -2
  31. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +8 -2
  32. package/docs/wiki/Installation.md +1 -1
  33. package/docs/wiki/Quick-Start.md +1 -1
  34. package/package.json +1 -1
  35. package/scripts/check-public-docs.sh +14 -1
  36. package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
  37. package/scripts/sprint-backlog.sh +1 -1
  38. package/src/cli/commands/chatgpt.ts +31 -2
  39. package/src/cli/commands/init-hook.ts +3 -1
  40. package/src/cli/commands/mcp.ts +2 -0
  41. package/src/cli/commands/plugin.ts +36 -9
  42. package/src/cli/commands/runtime.ts +1 -0
  43. package/src/cli/commands/setup-profile.ts +49 -18
  44. package/src/cli/controller/context-pack.ts +158 -6
  45. package/src/cli/hook/prompt-guard-decision.ts +17 -18
  46. package/src/cli/hook/prompt-intents.ts +1 -1
  47. package/src/cli/local-bridge/console-assets.ts +17 -0
  48. package/src/cli/local-bridge/console-automations.ts +205 -23
  49. package/src/cli/local-bridge/console-view-models.ts +2 -0
  50. package/src/cli/local-bridge/facade-api.ts +2 -0
  51. package/src/cli/local-bridge/frontend/src/App.tsx +1 -1
  52. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +143 -3
  53. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +1 -1
  54. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +181 -3
  55. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
  56. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
  57. package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -6
  58. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
  59. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -1
  60. package/src/cli/local-bridge/frontend/src/styles.css +27 -11
  61. package/src/cli/local-bridge/frontend/src/types.ts +6 -2
  62. package/src/cli/local-bridge/server.ts +31 -20
  63. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  64. package/src/cli/local-bridge/ui-dist/app.js +5003 -4815
  65. package/src/cli/mcp/auth.ts +2 -0
  66. package/src/cli/mcp/paths.ts +8 -2
  67. package/src/cli/mcp/repository-tools.ts +124 -9
  68. package/src/cli/mcp/server.ts +164 -19
  69. package/src/cli/mcp/setup.ts +9 -1
  70. package/src/cli/mcp/transports/http.ts +52 -2
  71. package/src/cli/mcp/transports/session-registry.ts +24 -0
  72. package/src/cli/repositories/command-classifier.ts +113 -0
  73. package/src/cli/repositories/safe-patch.ts +6 -4
  74. package/src/cli/repositories/structured-git.ts +49 -7
  75. package/src/cli/repository/inspector.ts +16 -3
  76. package/src/runtime/assistant/intent.ts +3 -3
  77. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +157 -2
  78. package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
  79. package/src/runtime/control-plane/execution/validation.ts +15 -2
  80. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +32 -0
  81. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +6 -7
  82. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +2 -1
  83. package/src/runtime/control-plane/facade/capability-registry.ts +1 -1
  84. package/src/runtime/control-plane/facade/controller-session-store.ts +12 -13
  85. package/src/runtime/control-plane/facade/goal-workloop-access.ts +7 -2
  86. package/src/runtime/control-plane/facade/goal-workloop.ts +231 -8
  87. package/src/runtime/control-plane/facade/plan-contract-store.ts +32 -12
  88. package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
  89. package/src/runtime/control-plane/facade/types.ts +33 -6
  90. package/src/runtime/control-plane/facade/work-contract-store.ts +31 -2
  91. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +375 -23
  92. package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
  93. package/src/runtime/diagnostics/mcp-timing.ts +6 -0
  94. package/src/runtime/execution/process-runtime/check-facade.ts +1 -10
  95. package/src/runtime/execution/process-runtime/check-result.ts +10 -2
  96. package/src/runtime/execution/process-runtime/command-facade.ts +1 -0
  97. package/src/runtime/execution/process-runtime/gc.ts +64 -10
  98. package/src/runtime/execution/process-runtime/persisted-check.ts +10 -2
  99. package/src/runtime/execution/process-runtime/resource-claims.ts +87 -2
  100. package/src/runtime/execution/process-runtime/runtime.ts +16 -1
  101. package/src/runtime/execution/process-runtime/store.ts +6 -0
  102. package/src/runtime/gateway/mcp/execution-tools.ts +27 -12
  103. package/src/runtime/gateway/mcp/router.ts +1 -1
  104. package/src/runtime/gateway/mcp/runtime-tools.ts +482 -178
  105. package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
  106. package/src/runtime/plugins/browser-adapter.ts +19 -72
  107. package/src/runtime/plugins/browser-handoff-host.ts +6 -31
  108. package/src/runtime/plugins/browser-handoff.ts +0 -3
  109. package/src/runtime/plugins/browser-macos-bridge.ts +8 -0
  110. package/src/runtime/plugins/desktop-operator-registration.ts +8 -11
  111. package/src/runtime/plugins/external-registration.ts +84 -5
  112. package/src/runtime/plugins/first-party-registry.ts +2 -2
  113. package/src/runtime/plugins/gmail-adapter.ts +28 -2
  114. package/src/runtime/plugins/local-system-adapter.ts +2 -2
  115. package/src/runtime/plugins/plugin-management-adapter.ts +140 -0
  116. package/src/runtime/plugins/store.ts +107 -5
  117. package/src/runtime/plugins/types.ts +4 -0
  118. package/src/runtime/recovery/actions.ts +0 -10
  119. package/src/runtime/recovery/classifier.ts +0 -9
  120. package/src/runtime/recovery/maintenance-executor.ts +43 -11
  121. package/src/runtime/recovery/probe.ts +0 -1
  122. package/src/runtime/recovery/types.ts +0 -1
  123. package/src/runtime/root/package-connector-service.ts +136 -0
  124. package/src/runtime/root/package-runtime-service.ts +25 -12
  125. package/src/runtime/root/release-materialize.ts +161 -18
  126. package/src/runtime/root/service.ts +6 -4
  127. package/src/runtime/safe-tooling/index.ts +0 -1
  128. package/src/runtime/safe-tooling/types.ts +0 -30
  129. package/src/runtime/standalone-recovery/core.ts +2 -2
  130. package/src/runtime/workflow/schedules/browser-probe.ts +180 -0
  131. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
  132. package/src/runtime/workflow/schedules/engine.ts +357 -64
  133. package/src/runtime/workflow/schedules/types.ts +5 -0
  134. package/src/runtime/workflow/schedules/work-continuation.ts +100 -27
  135. package/bin/forge-desktop-helper.mjs +0 -204
  136. package/docs/operations/controller-desktop-plugin.md +0 -112
  137. package/src/runtime/plugins/desktop-adapter.ts +0 -374
  138. package/src/runtime/safe-tooling/browser-safe.ts +0 -133
@@ -13,6 +13,26 @@ Forge separates four kinds of truth:
13
13
 
14
14
  Entities from different categories must not be collapsed merely because they are currently stored in adjacent files or exposed by one tool.
15
15
 
16
+ The current Controller model also separates semantic ownership from execution depth and placement. Requirement/Plan/Work describe intent and finite delivery lineage; Direct/Process/Agent describe execution mechanisms; Workspace/Worktree/provider resources describe placement. None of those dimensions substitutes for another.
17
+
18
+ ### 1.1 Current intent hierarchy
19
+
20
+ ```text
21
+ Requirement? long-lived user outcome
22
+ -> Plan? optional decomposition/replanning contract
23
+ -> Work finite recoverable objective
24
+ -> Edit Session / Process / Run / Verification evidence
25
+
26
+ Schedule long-lived trigger/policy
27
+ -> Occurrence one bounded terminal firing
28
+ ```
29
+
30
+ A Requirement may have more than one active Plan slice. Current Plan rows own the forward `requirementId` relation; `Requirement.activePlanId` is migration compatibility only and MUST NOT become a second lifecycle authority. A failed/cancelled Work moves its Plan to `replanning`; a reusable slice returns to `ready` rather than pretending to be in verification.
31
+
32
+ A Durable repository Work has one execution `WorkHandle` with the same Work identity. The handle records the selected checkout/worktree, execution-session binding, permission snapshot and finalization stages; it is execution state, not another user objective. New `rh_work start` creation materializes this handle and claims the initiating authenticated Controller in the same facade flow. `managedWorktree=false` means the Work does not own the current checkout/branch as disposable resources, so terminal cleanup releases lifecycle/process ownership without deleting them.
33
+
34
+ Conversation/session bindings are transport and presentation preferences. They may help resume a Controller, but Work/Schedule identity survives a changed or missing conversation.
35
+
16
36
  ## 2. Identity Hierarchy
17
37
 
18
38
  ```text
@@ -71,7 +71,7 @@ Current source uses Forge authorities for active configuration:
71
71
  - GitHub: `.forge/plugins/github.json` plus Repository Registry GitHub identity;
72
72
  - Gmail/Calendar/Tasks: `.forge/plugins/...`, `FORGE_*_ACCESS_TOKEN`;
73
73
  - iOS: `.forge/plugins/ios.json`, `FORGE_IOS_DEVICE_RUNNER_URL` plus local Xcode/CoreDevice/agent-device facts;
74
- - Desktop: Controller Home `system/desktop/config.json`;
74
+ - Desktop Operator: trusted external registration under Controller Home plus the stable signed macOS app identity;
75
75
  - Local System: Controller Home `system/local-system`.
76
76
 
77
77
  App Store Connect intentionally retains `.repo-harness/plugins/app-store-connect.json` as a named `legacy-read-fallback`. This is an acceptable migration pattern and must not become a new write authority.
@@ -326,7 +326,7 @@ Runtime/recovery/worktree directories are governed separately and are never trea
326
326
  7. Route a non-destructive status/observe action end-to-end.
327
327
  8. Add write action policy tests for press/type/screenshot/batch without bypassing normal Forge confirmation rules.
328
328
  9. Run real macOS E2E when the registered Desktop Operator build/service is available.
329
- 10. Only then decide whether the bundled Desktop helper remains fallback or is retired.
329
+ 10. Retire the bundled Desktop helper after the external Desktop Operator is healthy; do not retain a second desktop authority.
330
330
 
331
331
  ### Phase 1 acceptance
332
332
 
@@ -368,7 +368,7 @@ Preserve its independent Git/product boundary. Integrate only through stable con
368
368
  Audit and close every built-in plugin:
369
369
 
370
370
  - Browser: Chrome/Vivaldi attach, ownership/reuse, DOM/native capability matrix, failure paths, real E2E.
371
- - Local System/Desktop: unregistered target operations, application control, external Desktop provider, destructive-path safeguards.
371
+ - Local System/Desktop Operator: unregistered target operations, background-safe application control, external Desktop provider, destructive-path safeguards.
372
372
  - iOS: simulator, agent-device, CoreDevice, physical runner configuration/E2E.
373
373
  - App Store Connect: auth/read/preview/write policy and remote-write guarded E2E.
374
374
  - GitHub: canonical Forge remote identity after repository rename; issue/project read/write acceptance.
@@ -1,10 +1,35 @@
1
1
  # Controller Runtime System Overview
2
2
 
3
3
  > Status: **Runtime Authority**
4
+ >
5
+ > Control convergence: ChatGPT/human Controller owns semantic understanding and commits Direct/Process/Durable Work/Plan only after sufficient context; Forge does not classify every request at ingress. `RouteDecision` owns execution mechanics after that commitment, while unrelated Work/Plan state never upgrades or blocks ordinary Direct execution. Semantic ownership, execution depth, and resource placement stay independent. CodeGraph/lexical/Forge relations are bounded impact evidence, not another decision authority.
4
6
 
5
7
  ## 1. System Definition
6
8
 
7
- Forge Controller Runtime is an Agent Engineering Control Plane for one or more local Git repositories. ChatGPT, Local UI, CLI and optional GitHub integrations submit decisions and commands. The runtime persists accepted work, schedules it under repository-owned conflict rules, executes it outside the Gateway process and records evidence for recovery, acceptance and release.
9
+ Forge Controller Runtime is an Agent Engineering Control Plane for one or more local Git repositories. ChatGPT is the primary semantic Controller: it may inspect first, then choose whether a request needs only a Direct action, a Process, finite durable Work, a Plan, or a Workflow. Local UI, CLI and integrations can submit the same explicit decisions and commands. Forge supplies bounded context, hard policy/resource constraints, persistence, execution and machine evidence; it does not replace the Controller with prompt classifiers or Plan/Work ceremony.
10
+
11
+ ### 1.1 End-to-end authority map
12
+
13
+ ```text
14
+ User request
15
+ -> ChatGPT / human Controller
16
+ -> Explore when needed: rh_context + raw reads + CodeGraph/Runtime/history evidence
17
+ -> semantic commitment: answer | Direct | Process | finite Work | Plan | Workflow
18
+ -> Forge execution boundary
19
+ -> hard policy / authorization / claims / leases / fencing
20
+ -> placement and executor mechanics; no semantic reinterpretation
21
+ -> execution
22
+ -> Direct mutation: SafePatch -> EditSession -> MutationGate
23
+ -> command/check: Unified Process Runtime
24
+ -> durable responsibility: finite Work using the same execution primitives
25
+ -> recurrence: Workflow/Schedule -> bounded Occurrence -> Controller decision
26
+ -> machine evidence
27
+ -> diff / Process receipt / check / delivery / cleanup facts
28
+ -> ChatGPT / user acceptance
29
+ -> accept, continue, replan, or close the semantic goal
30
+ ```
31
+
32
+ Authority rule: Context providers return evidence, RoutePolicy selects mechanics from a Controller commitment, Plan/Requirement/Work persist explicitly chosen durable semantics, and Process/EditSession/Evidence record execution facts. None of those layers may infer that a missing Plan/Work makes ordinary implementation unauthorized, or that a successful/failed cleanup receipt by itself proves the user's goal accepted/rejected.
8
33
 
9
34
  ## 2. Canonical Runtime Topology
10
35
 
@@ -174,6 +174,16 @@ bounded child process (process group) / yielded search
174
174
  - Timeout/cancel: SIGTERM process group → grace → SIGKILL via `terminateProcessTree`.
175
175
  - stdout/stderr collectors cap while streaming.
176
176
 
177
+ ## MCP tool-surface freshness
178
+
179
+ The Canonical Runtime `tools/list` schema fingerprint is the tool-surface identity. Release identity alone does not invalidate a session, while any exposed schema change does.
180
+
181
+ HTTP MCP sessions capture the exact Canonical Runtime fingerprint and tool names at initialize time. The Gateway also observes the existing atomic `runtime/status.json` publication; when its published tool-surface fingerprint changes, it sends the standard MCP `notifications/tools/list_changed` notification to connected sessions whose captured fingerprint is stale. This is event-driven over the existing Runtime status publication—there is no schema poller, refresh daemon, or extra control-plane entity.
182
+
183
+ The notification is an optimization hint, not authority. It never rewrites a session's captured fingerprint. Until the client re-runs discovery/reinitializes, the existing per-request fingerprint fence still rejects stale-schema execution. A lost notification therefore cannot make an obsolete tool call valid; it only risks falling back to the deterministic reinitialize path.
184
+
185
+ This removes the normal stale-tool extra round trip for clients that honor standard MCP list-changed notifications while retaining the same fail-closed schema fence for clients that do not.
186
+
177
187
  ## Process output confidentiality
178
188
 
179
189
  Process Runtime applies one shared bounded redaction policy before stdout/stderr
@@ -27,16 +27,40 @@ The Package Runtime does not require a Forge Git checkout, Bun compilation, Code
27
27
 
28
28
  ## Local boundaries
29
29
 
30
- Forge MCP remains loopback-only, normally at:
30
+ Forge keeps two MCP boundaries on loopback by default:
31
31
 
32
32
  ```text
33
- http://127.0.0.1:8765/mcp
33
+ ChatGPT OAuth Gateway: http://127.0.0.1:8767/mcp
34
+ Canonical Runtime: http://127.0.0.1:8765/mcp
34
35
  ```
35
36
 
37
+ The OAuth Gateway is the endpoint for Secure Tunnel or HTTPS connectors. It proxies authenticated controller traffic to the bearer-only Canonical Runtime; remote clients should never target the internal Runtime directly. `forge mcp setup chatgpt --user-level` records the actual OAuth endpoint, so custom ports remain supported.
38
+
36
39
  Fresh user-level setup keeps the repository-centric Utility Console disabled until a repository/workbench target is configured. When enabled later it uses a separate loopback port (normally 8766). Never expose it to the internet.
37
40
 
38
41
  Service-level MCP configuration lives below `Controller Home/mcp/`. OAuth credentials and bearer fallback tokens are local secrets and must not be pasted into chat or committed. Repository-specific `.forge/mcp.policy.json` can narrow access when a repository is later adopted.
39
42
 
43
+ ## App identity vs. transport
44
+
45
+ The ChatGPT App/connector is the application identity and owns the visible Forge tool schema. **Secure MCP Tunnel is the transport.** Switching an existing Forge App from a public HTTPS/Cloudflare route to Tunnel changes how commands reach Forge; it does not create a second Forge tool schema.
46
+
47
+ Default path:
48
+
49
+ ```text
50
+ ChatGPT App -> OpenAI Secure MCP Tunnel -> tunnel-client
51
+ -> Forge loopback OAuth Gateway -> Canonical Runtime
52
+ ```
53
+
54
+ A fresh chat is useful for isolated A/B testing, but Forge does not require a new conversation merely because transport changed when the same App is already connected and its tool schema is unchanged. If published tool definitions change, use ChatGPT's current app refresh/re-publish workflow.
55
+
56
+ Upgrade existing Forge installs with:
57
+
58
+ ```bash
59
+ npm install -g @moretea-labs/forge@latest
60
+ forge --version
61
+ forge setup next
62
+ ```
63
+
40
64
  ## Remote controller connection
41
65
 
42
66
  The setup profile owns the connection choice. Supported paths are:
@@ -47,7 +71,7 @@ The setup profile owns the connection choice. Supported paths are:
47
71
  4. **Existing HTTPS** — user-managed reverse proxy/tunnel ending in `/mcp`.
48
72
  5. **None** — local setup only; remote connectivity can be configured later.
49
73
 
50
- For OpenAI Secure MCP Tunnel, setup uses the official supervised runtime surface and considers it ready only when `tunnel-client runtimes status forge --json` reports the runtime running, healthy, and ready.
74
+ For OpenAI Secure MCP Tunnel, setup uses the official managed runtime surface and considers a matching local alias ready only when `tunnel-client` reports the configured `tunnel_id` running, healthy, and ready. Alias names are not tunnel identity.
51
75
 
52
76
  For public HTTPS paths, the configured connector URL is:
53
77
 
@@ -54,7 +54,15 @@ A routine stores the user's natural-language goal rather than a traditional GUI
54
54
  }
55
55
  ```
56
56
 
57
- The first version stores the routine and can run it on demand. Automatic time-based scheduling should attach this store to the existing schedule engine in a later iteration.
57
+ Routine execution and long-lived goal continuation use the existing Schedule Engine rather than a second assistant daemon. Semantic/model-backed routine logic remains external-controller-owned; the Kernel does not execute an unbounded model loop on a timer.
58
+
59
+ For an accepted non-terminal Work, ChatGPT can create a bounded `rh_work.schedule_create` policy in one of three modes:
60
+
61
+ - `continuation` — wake the bound ChatGPT/Codex/Claude/Grok Controller at the configured trigger;
62
+ - `browser_watch` — silently refresh/read an allowed browser target, fingerprint a deterministic text projection, and wake the bound Controller only when the observation changes;
63
+ - `browser_keepalive` — silently refresh an authenticated browser target and wake only when configured login markers indicate that user authentication is required.
64
+
65
+ The first `browser_watch` observation is a silent baseline by default. Unchanged observations do not create a ChatGPT conversation turn. When the bound Work becomes terminal, Forge disables the Schedule before performing another external probe, so temporary watchers naturally disappear with the Goal they serve.
58
66
 
59
67
  ## Policy defaults
60
68
 
@@ -76,8 +84,10 @@ Requires human approval:
76
84
 
77
85
  ## Assistant Inbox
78
86
 
79
- Assistant Inbox is the user-facing result surface for routine outputs and intent execution records. ChatGPT can read it and then present the result conversationally, for example: "今天助理整理了什么?"
87
+ Assistant Inbox is the user-facing result surface for meaningful routine outputs, approval/authentication needs, and intent execution records. A successful scheduled probe with no external change should remain silent rather than generating a daily "completed" notification. ChatGPT can read meaningful items and then present the result conversationally, for example: "今天助理整理了什么?"
80
88
 
81
89
  ## Current limitation
82
90
 
83
91
  The runtime does not embed a full NLP model. ChatGPT Actions should provide structure when precision matters. The local runtime includes conservative intent inference only for routine creation, reminders, and immediate mail-summary collection.
92
+
93
+ `browser_watch` is a fallback observation source for services without a usable API or webhook; it depends on a live authenticated browser session and caller-supplied selectors/terms when the page contains unrelated or volatile content. Browser refresh can reduce inactivity-related logout but cannot override a provider's absolute session lifetime, security checks, or MFA policy. Provider-native APIs/events should replace browser probes when they are available and more reliable.
@@ -48,7 +48,7 @@ Session metadata is reusable across actions via `session_id`. Any action that re
48
48
  - Artifacts stay under `.forge/browser/**` (not arbitrary local paths).
49
49
  - CDP attach is bounded to configured loopback endpoints only; the plugin does not scan arbitrary ports or remote hosts. Native discovery checks only the configured Chrome/Vivaldi candidates and does not launch them.
50
50
  - CDP browsers are disconnected after the action; Apple Events keeps plugin-owned session tabs open until `close_session`/`close_page` while preserving user-owned tabs; managed contexts are closed after the action. Standard native DOM reads/interactions do not foreground the owned tab and return DOM evidence instead of attempting a screenshot.
51
- - Health `userFacingStatus` reports `ready`, `domain restricted`, `session active`, or setup states.
51
+ - Health `userFacingStatus` reports `ready`, `session active`, or setup states.
52
52
 
53
53
  ## Configuration
54
54
 
@@ -67,12 +67,11 @@ Example:
67
67
  "nativeBrowserCandidates": ["vivaldi", "chrome"],
68
68
  "cdpAttachFallback": "managed_persistent",
69
69
  "browserChannel": "chromium",
70
- "defaultTimeoutMs": 30000,
71
- "allowedDomains": ["example.com", "docs.example.com"]
70
+ "defaultTimeoutMs": 30000
72
71
  }
73
72
  ```
74
73
 
75
- `allowedDomains` is the safety boundary. If it is empty, the plugin can target any HTTP(S) host. If it is set, the plugin accepts only exact hosts or subdomains of those entries.
74
+ Browser URLs are open by default across hosts. The URL boundary is scheme-based: top-level navigation accepts absolute `http://` and `https://` URLs and rejects `file://`, `data:`, browser-internal pages, and custom schemes. Interaction risk and authorization are enforced by the typed action policy rather than a domain grant.
76
75
 
77
76
  Additional browser/profile fields:
78
77
 
@@ -131,8 +130,7 @@ Example custom Chrome automation-profile binding:
131
130
  "browserChannel": "chrome",
132
131
  "cdpEndpoint": "http://127.0.0.1:9222",
133
132
  "cdpAttachFallback": "fail_closed",
134
- "defaultTimeoutMs": 30000,
135
- "allowedDomains": ["appstoreconnect.apple.com"]
133
+ "defaultTimeoutMs": 30000
136
134
  }
137
135
  ```
138
136
 
@@ -152,12 +150,11 @@ Use native attachment when the target session is already logged in:
152
150
  "browserMode": "attach_preferred",
153
151
  "nativeAttachMode": "auto",
154
152
  "nativeBrowserCandidates": ["vivaldi", "chrome"],
155
- "cdpAttachFallback": "managed_persistent",
156
- "allowedDomains": ["chatgpt.com", "example.com"]
153
+ "cdpAttachFallback": "managed_persistent"
157
154
  }
158
155
  ```
159
156
 
160
- The attach order is CDP, then Apple Events, then managed fallback. macOS may require Automation permission for the controller/Node process to control Vivaldi or Google Chrome. The browser must also permit JavaScript from Apple Events for DOM extraction and interaction. If either permission is unavailable or the browser has no window, the attempt is recorded and fallback policy applies. The provider uses the active browser only for discovery, then operates on a plugin-owned tab identified by stable window/tab metadata. It does not read cookies or storage and re-checks the target URL against `allowedDomains` before and after actions.
157
+ The attach order is CDP, then Apple Events, then managed fallback. macOS may require Automation permission for the controller/Node process to control Vivaldi or Google Chrome. The browser must also permit JavaScript from Apple Events for DOM extraction and interaction. If either permission is unavailable or the browser has no window, the attempt is recorded and fallback policy applies. The provider uses the active browser only for discovery, then operates on a plugin-owned tab identified by stable window/tab metadata. It does not read cookies or storage. Top-level Browser actions accept any absolute HTTP(S) URL; non-HTTP(S) schemes fail before launch.
161
158
 
162
159
  Native limitations are explicit: console/network event capture is unavailable and native file-input/download semantics are not equivalent to Playwright. A screenshot of a plugin-owned background tab fails closed with `PLUGIN_BROWSER_FOREGROUND_REQUIRED`; Forge does not silently activate the tab just to capture evidence. Use explicit foreground/human handoff, CDP, or a managed context for workflows that require screenshots or capabilities not available through background DOM automation.
163
160
 
@@ -219,15 +216,14 @@ Risk levels:
219
216
  - `click`, `type`, `press` use `risk=remote_write`
220
217
  - `wait_for_selector` uses `risk=workspace_write`
221
218
 
222
- ## Allowed-domain enforcement
223
-
224
- The plugin enforces `allowedDomains` in three places:
219
+ ## URL scheme boundary
225
220
 
226
- 1. It validates the explicit `url` before opening a page.
227
- 2. It validates any saved `session_id` target before interaction.
228
- 3. It re-checks the resulting page URL after the action and rejects the result if navigation leaves the allowed set.
221
+ Browser no longer maintains per-domain grants or a host allowlist. Any absolute HTTP(S) URL may be opened, redirected to, or reached by an interaction. This avoids configuration churn for normal browsing while preserving the actual trust boundaries:
229
222
 
230
- The plugin does not intentionally provide any action that can bypass this boundary.
223
+ 1. top-level Browser targets must use `http:` or `https:`;
224
+ 2. local files, browser-internal URLs, `data:` URLs, and custom schemes are rejected as Browser targets;
225
+ 3. action risk and confirmation still govern remote writes and interactive operations;
226
+ 4. silent native automation stays on plugin-owned background tabs unless an explicit human handoff requires foreground presentation.
231
227
 
232
228
  ## Dependency requirement
233
229
 
@@ -24,7 +24,7 @@ These features are part of the default local setup:
24
24
  | Codex / Claude | Delegated implementation for work too large for Direct Edit | Install and authenticate the corresponding CLI; explicitly enable the dev runner. |
25
25
  | GitHub | Issue/Project synchronization, PR workflows, cloud-agent sessions | Authenticated `gh` and repository permission. |
26
26
  | Tailscale / Cloudflare | Stable HTTPS endpoint for ChatGPT MCP | Tunnel client and appropriate account/domain configuration. |
27
- | Browser | Playwright navigation, screenshots, and bounded browser evidence | Browser binaries and allowed domains. |
27
+ | Browser | Playwright navigation, screenshots, and bounded browser evidence | Browser binaries and HTTP(S) URL scheme validation. |
28
28
  | CodeGraph | Additional code relationships and impact navigation | CodeGraph CLI; native Windows automatic setup is not yet enabled. |
29
29
  | Google Workspace | Gmail and Calendar assistant actions | Explicit OAuth setup and plugin permission. |
30
30
  | Schedules and findings | Supervised recurring checks and candidate findings | Canonical Forge Runtime running; live actions remain policy-gated. |
@@ -6,8 +6,8 @@ Homebrew is planned as a convenience layer after the first stable npm/GitHub rel
6
6
 
7
7
  Do not publish a formula until all of the following are true:
8
8
 
9
- - `@moretea-labs/forge@1.5.0` exists on npm;
10
- - Git tag and GitHub Release `v1.5.0` exist and point to the tested commit;
9
+ - `@moretea-labs/forge@1.6.0` exists on npm;
10
+ - Git tag and GitHub Release `v1.6.0` exist and point to the tested commit;
11
11
  - the npm tarball has an immutable checksum;
12
12
  - macOS installation and `forge --version` / `forge doctor` tests pass;
13
13
  - upgrade and uninstall behavior is documented.
@@ -18,7 +18,7 @@ forge setup next
18
18
 
19
19
  ## 2. Follow setup until the selected path is usable
20
20
 
21
- For a hosted controller, setup guides the user-level Package Runtime and a remote connection. Prefer OpenAI Secure MCP Tunnel when eligible; Cloudflare Tunnel, Tailscale Funnel, an existing HTTPS `/mcp` endpoint, or deferred remote access are alternatives.
21
+ For ChatGPT, `--tunnel auto` prefers OpenAI Secure MCP Tunnel and does not silently switch to a public ingress provider just because one is installed. The packaged setup keeps the bearer-only Canonical Runtime private and manages a separate loopback OAuth Gateway for the ChatGPT App. Cloudflare Tunnel, Tailscale Funnel, an existing HTTPS `/mcp` endpoint, or deferred remote access are explicit alternatives. Existing users update with `npm install -g @moretea-labs/forge@latest`, then `forge setup next`.
22
22
 
23
23
  The normal package Runtime is `forge runtime service install-package`. Source immutable Runtime and Standalone Recovery are advanced maintainer paths.
24
24
 
@@ -18,7 +18,7 @@ forge setup next
18
18
 
19
19
  ## 2. 按 Next 完成所选路径
20
20
 
21
- 远程主控会继续配置 Package Runtime 和远程连接。有权限时优先 OpenAI Secure MCP Tunnel;也可以选择 Cloudflare Tunnel、Tailscale Funnel、已有 HTTPS `/mcp`,或暂缓远程连接。
21
+ 对 ChatGPT,`--tunnel auto` 会优先 OpenAI Secure MCP Tunnel,不会因为机器上恰好安装了 cloudflared/Tailscale 就静默改用公网入口。Package setup 会保持 bearer-only Canonical Runtime 私有,并管理一个独立的 loopback OAuth Gateway 供 ChatGPT App 使用。Cloudflare Tunnel、Tailscale Funnel、已有 HTTPS `/mcp` 或暂缓远程连接都是显式 fallback。已安装用户运行 `npm install -g @moretea-labs/forge@latest` 后再执行 `forge setup next`。
22
22
 
23
23
  普通 package Runtime 是 `forge runtime service install-package`。源码 immutable Runtime 与 Standalone Recovery 属于高级维护路径。
24
24
 
@@ -20,7 +20,7 @@ See [Platform Support](../operations/platform-support.md) for the exact matrix.
20
20
 
21
21
  ## 2. Install Forge
22
22
 
23
- Release candidates use npm `next`:
23
+ Stable releases use npm `latest`:
24
24
 
25
25
  ```bash
26
26
  npm install -g @moretea-labs/forge
@@ -34,11 +34,11 @@ For Forge source development only:
34
34
  ```bash
35
35
  git clone https://github.com/moretea-labs/forge.git
36
36
  cd forge
37
- npm ci --ignore-scripts --no-audit --no-fund
37
+ bun install --frozen-lockfile
38
38
  npm install -g . --omit=optional --no-audit --no-fund
39
39
  ```
40
40
 
41
- The published package exposes `forge`, `forge-hook`, and `forge-runtime`. Normal package users do **not** need a Forge source checkout, Bun compilation, CodeGraph, or Standalone Recovery to start the user-level Runtime.
41
+ The published package exposes `forge`, `forge-hook`, and `forge-runtime`. Normal package users do **not** need a Forge source checkout, Bun compilation, CodeGraph, or Standalone Recovery to start the user-level Runtime. To upgrade, run `npm install -g @moretea-labs/forge@latest`, verify `forge --version`, then run `forge setup next` so newer setup contracts can be reconciled without reinstalling from source.
42
42
 
43
43
  ## 3. Start guided setup
44
44
 
@@ -78,7 +78,7 @@ The setup session is stored below the user-level Forge directory, so you can clo
78
78
 
79
79
  1. controller registration;
80
80
  2. the packaged user-level Runtime;
81
- 3. secure public HTTPS for a remote controller;
81
+ 3. remote connectivity — OpenAI Secure MCP Tunnel first for ChatGPT, with explicit HTTPS fallbacks;
82
82
  4. account/browser authentication that only you can complete;
83
83
  5. a connection verification.
84
84
 
@@ -90,6 +90,8 @@ The normal Runtime action is:
90
90
  forge runtime service install-package
91
91
  ```
92
92
 
93
+ For ChatGPT setups this installs two local service boundaries together: the bearer-only Canonical Runtime and a separate loopback OAuth Gateway used by Secure Tunnel or HTTPS connectors. Users should follow the OAuth endpoint printed by setup instead of tunneling directly to the internal Runtime port.
94
+
93
95
  The older `forge runtime service install --repo ...` path builds an immutable Git/source Runtime and is an **advanced maintainer path**, not normal onboarding. Standalone Recovery is likewise optional advanced infrastructure.
94
96
 
95
97
  ## 5. Repositories are optional at first
@@ -34,7 +34,7 @@ forge --version
34
34
  ```bash
35
35
  git clone https://github.com/moretea-labs/forge.git
36
36
  cd forge
37
- npm ci --ignore-scripts --no-audit --no-fund
37
+ bun install --frozen-lockfile
38
38
  npm install -g . --omit=optional --no-audit --no-fund
39
39
  ```
40
40
 
@@ -90,6 +90,8 @@ setup 进度保存在用户级 Forge 目录,可以退出终端后继续。根
90
90
  forge runtime service install-package
91
91
  ```
92
92
 
93
+ 对 ChatGPT,package 安装会同时维护两个本地服务边界:内部 bearer-only Canonical Runtime,以及供 Secure Tunnel/HTTPS connector 使用的 loopback OAuth Gateway。不要把 tunnel 直接指向内部 Runtime 端口,以 setup 输出的本地 OAuth endpoint 为准。
94
+
93
95
  旧的 `forge runtime service install --repo ...` 会构建 Git/source immutable Runtime,属于**高级维护路径**;Standalone Recovery 同样不是普通用户初始化的前置条件。
94
96
 
95
97
  ## 5. 首次 setup 不要求仓库
@@ -42,7 +42,7 @@ Run `forge setup next`. Forge supports these connection providers:
42
42
 
43
43
  ### A. OpenAI Secure MCP Tunnel — preferred when available
44
44
 
45
- Secure MCP Tunnel lets an OpenAI-hosted product reach the local MCP server through an outbound tunnel, without creating public inbound access. See OpenAI's [Secure MCP Tunnel guide](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels) and the official [`openai/tunnel-client`](https://github.com/openai/tunnel-client).
45
+ Secure MCP Tunnel lets an OpenAI-hosted product reach the local MCP server through an outbound tunnel, without creating public inbound access. `--tunnel auto` treats this as the first-choice ChatGPT transport and does not silently choose Cloudflare/Tailscale merely because those CLIs are installed. See OpenAI's [Secure MCP Tunnel guide](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels) and the official [`openai/tunnel-client`](https://github.com/openai/tunnel-client).
46
46
 
47
47
  You need a tunnel ID and tunnel-use permission from OpenAI Platform. Record only the non-secret tunnel ID in Forge:
48
48
 
@@ -67,13 +67,19 @@ tunnel-client runtimes connect \
67
67
  --alias forge \
68
68
  --tunnel-id tunnel_0123456789abcdef0123456789abcdef \
69
69
  --runtime-api-key env:CONTROL_PLANE_API_KEY \
70
- --mcp-server-url http://127.0.0.1:8765/mcp
70
+ --mcp-server-url http://127.0.0.1:8767/mcp
71
71
 
72
72
  tunnel-client runtimes status forge --json
73
73
  ```
74
74
 
75
75
  Forge reports this provider ready only when `tunnel-client` reports the managed runtime as running, healthy, and ready.
76
76
 
77
+ #### What address changes?
78
+
79
+ With Secure Tunnel there is no public Forge `/mcp` address to paste. The ChatGPT App selects the `tunnel_id`; `tunnel-client` forwards commands to Forge's **loopback OAuth Gateway** (default `127.0.0.1:8767/mcp`), which proxies to the internal bearer-only Runtime (default `127.0.0.1:8765/mcp`). If you customize ports, use the OAuth endpoint printed by `forge mcp setup chatgpt --user-level`.
80
+
81
+ The App/connector identity and Forge tool schema are separate from the transport. Switching from Cloudflare/HTTPS to Secure Tunnel changes the network path, not the 19-tool Forge schema. A fresh chat is useful for isolated A/B testing, but it is not required merely because transport changed when the same App is already connected.
82
+
77
83
  ### B. Cloudflare Tunnel
78
84
 
79
85
  Choose this when you need a stable public HTTPS endpoint and control the Cloudflare account/domain:
@@ -40,7 +40,7 @@ http://127.0.0.1:8765/mcp
40
40
 
41
41
  ### A. OpenAI Secure MCP Tunnel——有权限时优先
42
42
 
43
- Secure MCP Tunnel 通过出站连接把本机/private MCP 接到 OpenAI 托管产品,不要求给 Forge 开公网入站。详见 OpenAI 的 [Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels) 与官方 [`openai/tunnel-client`](https://github.com/openai/tunnel-client)。
43
+ Secure MCP Tunnel 通过出站连接把本机/private MCP 接到 OpenAI 托管产品,不要求给 Forge 开公网入站。 `--tunnel auto` 会把它作为 ChatGPT 的第一优先传输,不会仅仅因为机器上装了 cloudflared/Tailscale 就静默改用公网方案。详见 OpenAI 的 [Secure MCP Tunnel](https://developers.openai.com/api/docs/guides/secure-mcp-tunnels) 与官方 [`openai/tunnel-client`](https://github.com/openai/tunnel-client)。
44
44
 
45
45
  需要先在 OpenAI Platform 获得 tunnel ID 和使用权限。Forge 只记录**非秘密**的 tunnel ID:
46
46
 
@@ -65,13 +65,19 @@ tunnel-client runtimes connect \
65
65
  --alias forge \
66
66
  --tunnel-id tunnel_0123456789abcdef0123456789abcdef \
67
67
  --runtime-api-key env:CONTROL_PLANE_API_KEY \
68
- --mcp-server-url http://127.0.0.1:8765/mcp
68
+ --mcp-server-url http://127.0.0.1:8767/mcp
69
69
 
70
70
  tunnel-client runtimes status forge --json
71
71
  ```
72
72
 
73
73
  只有 tunnel-client 返回 `process_running + healthy + ready` 后,Forge 才把这个连接判为 ready。
74
74
 
75
+ #### 地址到底变成什么?
76
+
77
+ 使用 Secure Tunnel 后,不再需要给 Forge 准备一个公网 `/mcp` 地址。ChatGPT App 选择 `tunnel_id`;本机 `tunnel-client` 把命令转发到 Forge 的 **loopback OAuth Gateway**(默认 `127.0.0.1:8767/mcp`),再由 Gateway 代理到内部 bearer-only Runtime(默认 `127.0.0.1:8765/mcp`)。如果改过端口,以 `forge mcp setup chatgpt --user-level` 输出的 OAuth endpoint 为准。
78
+
79
+ App/connector 身份及 Forge 工具 schema 与网络传输层是两件事。Cloudflare/HTTPS 切到 Secure Tunnel 改变的是网络路径,不会生成另一套 19-tool Forge schema。同一个 App 已连接且 schema 没变化时,单纯切换网络不要求新开会话;新会话主要用于隔离 A/B 或排查客户端缓存。
80
+
75
81
  ### B. Cloudflare Tunnel
76
82
 
77
83
  需要稳定公网 HTTPS、并且你管理 Cloudflare 账号/域名时使用:
@@ -7,7 +7,7 @@
7
7
  This is the verified path while `@moretea-labs/forge` remains unpublished:
8
8
 
9
9
  ```bash
10
- npm ci --ignore-scripts --no-audit --no-fund
10
+ bun install --frozen-lockfile
11
11
  npm install -g . --omit=optional --no-audit --no-fund
12
12
  ```
13
13
 
@@ -7,7 +7,7 @@ Until the npm RC is publicly available, use the verified source path:
7
7
  ```bash
8
8
  git clone https://github.com/moretea-labs/forge.git
9
9
  cd forge
10
- npm ci --ignore-scripts --no-audit --no-fund
10
+ bun install --frozen-lockfile
11
11
  npm install -g . --omit=optional --no-audit --no-fund
12
12
  ```
13
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moretea-labs/forge",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Local-first action assistant for software work with resumable execution, bounded tools, and reviewable evidence",
5
5
  "license": "MIT",
6
6
  "author": "Moretea Labs contributors",
@@ -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
 
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bun
2
+ import { mkdirSync, writeFileSync } from 'fs';
3
+ import { dirname, join, resolve } from 'path';
4
+ import { resolveRepoPreferredControllerHome } from '../src/cli/repositories/controller-home';
5
+ import { listRepositories } from '../src/cli/repositories/registry';
6
+ import { migrateChatgptAutomationSchedule } from '../src/runtime/workflow/schedules/chatgpt-automation-migration';
7
+ import { listSchedules, saveSchedule } from '../src/runtime/workflow/schedules/store';
8
+ import type { RepositorySchedule } from '../src/runtime/workflow/schedules/types';
9
+
10
+ interface Args { controllerHome?: string; apply: boolean; json: boolean; }
11
+
12
+ function parseArgs(argv: string[]): Args {
13
+ const args: Args = { apply: false, json: false };
14
+ for (let index = 0; index < argv.length; index += 1) {
15
+ const value = argv[index];
16
+ if (value === '--apply') args.apply = true;
17
+ else if (value === '--json') args.json = true;
18
+ else if (value === '--controller-home') args.controllerHome = resolve(argv[++index] ?? '');
19
+ else throw new Error(`unknown argument: ${value}`);
20
+ }
21
+ return args;
22
+ }
23
+
24
+ function main(): void {
25
+ const args = parseArgs(process.argv.slice(2));
26
+ const controllerHome = resolveRepoPreferredControllerHome(process.cwd(), args.controllerHome);
27
+ const repositories = listRepositories(controllerHome, { includeRemoved: true });
28
+ const candidates: Array<{ repositoryName: string; original: RepositorySchedule; migrated: RepositorySchedule }> = [];
29
+ for (const repository of repositories) {
30
+ for (const schedule of listSchedules(controllerHome, repository.repoId)) {
31
+ const result = migrateChatgptAutomationSchedule(schedule);
32
+ if (result.changed) candidates.push({ repositoryName: repository.displayName, original: schedule, migrated: result.schedule });
33
+ }
34
+ }
35
+
36
+ let backupPath: string | undefined;
37
+ if (args.apply && candidates.length > 0) {
38
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
39
+ backupPath = join(controllerHome, 'backups', `chatgpt-automation-schedules-${stamp}.json`);
40
+ mkdirSync(dirname(backupPath), { recursive: true });
41
+ writeFileSync(backupPath, `${JSON.stringify({ schemaVersion: 1, createdAt: new Date().toISOString(), schedules: candidates.map((item) => item.original) }, null, 2)}\n`);
42
+ for (const candidate of candidates) saveSchedule(controllerHome, candidate.migrated);
43
+ }
44
+
45
+ const output = {
46
+ schemaVersion: 1,
47
+ controllerHome,
48
+ repositoryCount: repositories.length,
49
+ migratedCount: candidates.length,
50
+ writesApplied: args.apply,
51
+ backupPath,
52
+ schedules: candidates.map((item) => ({ repoId: item.original.repoId, repositoryName: item.repositoryName, scheduleId: item.original.scheduleId, name: item.original.name })),
53
+ };
54
+ if (args.json) console.log(JSON.stringify(output, null, 2));
55
+ else {
56
+ console.log(`[chatgpt-automation-migration] ${candidates.length} schedule(s) eligible across ${repositories.length} repository record(s).`);
57
+ console.log(args.apply ? `[chatgpt-automation-migration] Applied. Backup: ${backupPath ?? 'not needed'}` : '[chatgpt-automation-migration] Preview only; pass --apply after the new Runtime baseline is active.');
58
+ }
59
+ }
60
+
61
+ try { main(); } catch (error) {
62
+ console.error(error instanceof Error ? error.message : String(error));
63
+ process.exitCode = 1;
64
+ }
@@ -21,7 +21,7 @@ Usage:
21
21
 
22
22
  Program-level sprint backlog helper. PRDs live in plans/prds/ as the upper
23
23
  planning layer; sprints live in plans/sprints/ as ordered execution backlogs.
24
- Each backlog row is expanded with $think before the existing plan -> contract
24
+ Each backlog row is expanded with /plan before the existing plan -> contract
25
25
  -> worktree flow. tasks/todos.md stays the deferred-goal ledger.
26
26
 
27
27
  start-task reserves the next (or named) pending backlog row and can capture a