@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.
- package/CHANGELOG.md +28 -1
- package/DESIGN.md +7 -2
- package/README.md +7 -7
- package/README.zh-CN.md +5 -3
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/assets/hooks/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +2 -2
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +2 -2
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/ensure-task-workflow.sh +2 -2
- package/assets/templates/helpers/sprint-backlog.sh +6 -6
- package/docs/architecture/current/automation-and-schedule-engine.md +9 -3
- package/docs/architecture/current/codegraph-context-provider.md +15 -3
- package/docs/architecture/current/dispatch-and-agent-strategy.md +32 -13
- package/docs/architecture/current/entity-model.md +20 -0
- package/docs/architecture/current/external-plugin-governance.md +3 -3
- package/docs/architecture/current/system-overview.md +26 -1
- package/docs/architecture/current/thin-harness-v1.md +10 -0
- package/docs/forge-chatgpt-mcp-setup.md +27 -3
- package/docs/operations/chatgpt-personal-assistant-runtime.md +12 -2
- package/docs/operations/controller-browser-plugin.md +12 -16
- package/docs/operations/features.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/public-usage-guide.md +1 -1
- package/docs/public-usage-guide.zh-CN.md +1 -1
- package/docs/tutorials/01-install-and-start.md +6 -4
- package/docs/tutorials/01-install-and-start.zh-CN.md +3 -1
- package/docs/tutorials/02-connect-chatgpt.md +8 -2
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +8 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Quick-Start.md +1 -1
- package/package.json +1 -1
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/sprint-backlog.sh +1 -1
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -1
- package/src/cli/commands/mcp.ts +2 -0
- package/src/cli/commands/plugin.ts +36 -9
- package/src/cli/commands/runtime.ts +1 -0
- package/src/cli/commands/setup-profile.ts +49 -18
- package/src/cli/controller/context-pack.ts +158 -6
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/local-bridge/console-assets.ts +17 -0
- package/src/cli/local-bridge/console-automations.ts +205 -23
- package/src/cli/local-bridge/console-view-models.ts +2 -0
- package/src/cli/local-bridge/facade-api.ts +2 -0
- package/src/cli/local-bridge/frontend/src/App.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +143 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +181 -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 -6
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -1
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +6 -2
- package/src/cli/local-bridge/server.ts +31 -20
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5003 -4815
- package/src/cli/mcp/auth.ts +2 -0
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +124 -9
- package/src/cli/mcp/server.ts +164 -19
- package/src/cli/mcp/setup.ts +9 -1
- package/src/cli/mcp/transports/http.ts +52 -2
- package/src/cli/mcp/transports/session-registry.ts +24 -0
- package/src/cli/repositories/command-classifier.ts +113 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/structured-git.ts +49 -7
- package/src/cli/repository/inspector.ts +16 -3
- package/src/runtime/assistant/intent.ts +3 -3
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +157 -2
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +32 -0
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +6 -7
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +2 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +1 -1
- package/src/runtime/control-plane/facade/controller-session-store.ts +12 -13
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +7 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +231 -8
- package/src/runtime/control-plane/facade/plan-contract-store.ts +32 -12
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- package/src/runtime/control-plane/facade/types.ts +33 -6
- package/src/runtime/control-plane/facade/work-contract-store.ts +31 -2
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +375 -23
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- package/src/runtime/diagnostics/mcp-timing.ts +6 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -10
- package/src/runtime/execution/process-runtime/check-result.ts +10 -2
- package/src/runtime/execution/process-runtime/command-facade.ts +1 -0
- package/src/runtime/execution/process-runtime/gc.ts +64 -10
- package/src/runtime/execution/process-runtime/persisted-check.ts +10 -2
- package/src/runtime/execution/process-runtime/resource-claims.ts +87 -2
- package/src/runtime/execution/process-runtime/runtime.ts +16 -1
- package/src/runtime/execution/process-runtime/store.ts +6 -0
- package/src/runtime/gateway/mcp/execution-tools.ts +27 -12
- package/src/runtime/gateway/mcp/router.ts +1 -1
- package/src/runtime/gateway/mcp/runtime-tools.ts +482 -178
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/browser-adapter.ts +19 -72
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +0 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +8 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +8 -11
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/first-party-registry.ts +2 -2
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- package/src/runtime/plugins/local-system-adapter.ts +2 -2
- package/src/runtime/plugins/plugin-management-adapter.ts +140 -0
- package/src/runtime/plugins/store.ts +107 -5
- package/src/runtime/plugins/types.ts +4 -0
- package/src/runtime/recovery/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +43 -11
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/package-connector-service.ts +136 -0
- package/src/runtime/root/package-runtime-service.ts +25 -12
- package/src/runtime/root/release-materialize.ts +161 -18
- package/src/runtime/root/service.ts +6 -4
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/types.ts +0 -30
- package/src/runtime/standalone-recovery/core.ts +2 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +180 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +357 -64
- package/src/runtime/workflow/schedules/types.ts +5 -0
- package/src/runtime/workflow/schedules/work-continuation.ts +100 -27
- package/bin/forge-desktop-helper.mjs +0 -204
- package/docs/operations/controller-desktop-plugin.md +0 -112
- package/src/runtime/plugins/desktop-adapter.ts +0 -374
- 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
|
|
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.
|
|
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
|
|
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
|
|
30
|
+
Forge keeps two MCP boundaries on loopback by default:
|
|
31
31
|
|
|
32
32
|
```text
|
|
33
|
-
http://127.0.0.1:
|
|
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
|
|
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
|
-
|
|
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
|
|
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`, `
|
|
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
|
-
|
|
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
|
|
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
|
-
##
|
|
223
|
-
|
|
224
|
-
The plugin enforces `allowedDomains` in three places:
|
|
219
|
+
## URL scheme boundary
|
|
225
220
|
|
|
226
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
10
|
-
- Git tag and GitHub Release `v1.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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 账号/域名时使用:
|
package/docs/wiki/Quick-Start.md
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
|
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
|