@aion0/forge 0.6.1 → 0.8.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/.forge/mcp.json +8 -0
- package/.forge/worktrees/pipeline-0a33c50d/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-0a33c50d/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-2ba01c10/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-2ba01c10/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-3156a8b3/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-3156a8b3/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-316c6574/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-316c6574/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-44a94121/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-44a94121/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-d1757a50/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-d1757a50/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-d59c2fe2/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-d59c2fe2/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-d6a6ef23/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-d6a6ef23/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-e7f78b7a/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-e7f78b7a/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-e97c13c7/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-e97c13c7/lib/help-docs/07-projects.md +1 -1
- package/.forge/worktrees/pipeline-ecd7cb0f/lib/help-docs/01-settings.md +5 -5
- package/.forge/worktrees/pipeline-ecd7cb0f/lib/help-docs/07-projects.md +1 -1
- package/CLAUDE.md +2 -2
- package/RELEASE_NOTES.md +101 -5
- package/app/api/auth/check/route.ts +18 -0
- package/app/api/browser-bridge/route.ts +70 -0
- package/app/api/chat/sessions/[id]/events/route.ts +17 -0
- package/app/api/chat/sessions/[id]/fork/route.ts +15 -0
- package/app/api/chat/sessions/[id]/messages/route.ts +21 -0
- package/app/api/chat/sessions/[id]/route.ts +23 -0
- package/app/api/chat/sessions/route.ts +12 -0
- package/app/api/chat/temper-ping/route.ts +18 -0
- package/app/api/chat-proxy/[...path]/route.ts +83 -0
- package/app/api/connector-tool/route.ts +38 -0
- package/app/api/connectors/[id]/settings/route.ts +112 -0
- package/app/api/connectors/route.ts +108 -0
- package/app/api/health/tools/route.ts +14 -0
- package/app/api/issue-scanner-gitlab/route.ts +95 -0
- package/app/api/jobs/[id]/reset_dedup/route.ts +15 -0
- package/app/api/jobs/[id]/route.ts +31 -0
- package/app/api/jobs/[id]/run/route.ts +44 -0
- package/app/api/jobs/[id]/runs/[runId]/route.ts +15 -0
- package/app/api/jobs/[id]/runs/route.ts +15 -0
- package/app/api/jobs/preview/route.ts +193 -0
- package/app/api/jobs/route.ts +36 -0
- package/app/api/notify/test/route.ts +39 -7
- package/app/api/pipelines/[id]/route.ts +10 -1
- package/app/api/pipelines/route.ts +16 -2
- package/app/api/plugins/route.ts +40 -8
- package/app/api/project-sessions/route.ts +50 -10
- package/app/api/settings/route.ts +13 -0
- package/app/chat/page.tsx +531 -0
- package/bin/forge-server.mjs +3 -1
- package/cli/chat.ts +283 -0
- package/cli/jobs.ts +176 -0
- package/cli/mw.ts +28 -1
- package/cli/worktree.ts +245 -0
- package/components/ConnectorsPanel.tsx +275 -0
- package/components/Dashboard.tsx +90 -37
- package/components/JobsView.tsx +361 -0
- package/components/LogViewer.tsx +12 -2
- package/components/PipelineView.tsx +275 -56
- package/components/PluginsPanel.tsx +3 -1
- package/components/SettingsModal.tsx +229 -40
- package/components/SkillsPanel.tsx +12 -4
- package/components/TerminalLauncher.tsx +3 -1
- package/components/WebTerminal.tsx +32 -9
- package/components/WorkspaceView.tsx +18 -10
- package/docs/Connector-DeclarativeExtract-Handoff.md +471 -0
- package/docs/Connector-DeclarativeExtract-Spec.md +364 -0
- package/docs/Implementation-Plan-Browser-Agent.md +487 -0
- package/docs/Jobs-Design.md +240 -0
- package/docs/LOCAL-DEPLOY.md +3 -3
- package/docs/RFC-Browser-Connectors.md +509 -0
- package/lib/agents/index.ts +44 -6
- package/lib/agents/types.ts +1 -1
- package/lib/browser-bridge-standalone.ts +317 -0
- package/lib/builtin-plugins/github-api.yaml +93 -0
- package/lib/builtin-plugins/gitlab.yaml +860 -0
- package/lib/builtin-plugins/mantis.probe.js +176 -0
- package/lib/builtin-plugins/mantis.yaml +964 -0
- package/lib/builtin-plugins/pmdb.yaml +178 -0
- package/lib/builtin-plugins/teams.yaml +913 -0
- package/lib/chat/__test__/smoke.ts +30 -0
- package/lib/chat/agent-loop.ts +523 -0
- package/lib/chat/bridge-client.ts +59 -0
- package/lib/chat/llm/anthropic.ts +99 -0
- package/lib/chat/llm/index.ts +20 -0
- package/lib/chat/llm/openai.ts +215 -0
- package/lib/chat/llm/types.ts +42 -0
- package/lib/chat/local-memory.ts +300 -0
- package/lib/chat/memory-store.ts +87 -0
- package/lib/chat/memory-tools.ts +157 -0
- package/lib/chat/protocols/http.ts +118 -0
- package/lib/chat/protocols/shell.ts +101 -0
- package/lib/chat/proxy.ts +51 -0
- package/lib/chat/session-store.ts +272 -0
- package/lib/chat/telegram-bridge.ts +276 -0
- package/lib/chat/temper.ts +281 -0
- package/lib/chat/tool-dispatcher.ts +190 -0
- package/lib/chat/types.ts +50 -0
- package/lib/chat-standalone.ts +286 -0
- package/lib/crypto.ts +1 -1
- package/lib/health.ts +131 -0
- package/lib/help-docs/00-overview.md +2 -1
- package/lib/help-docs/01-settings.md +46 -25
- package/lib/help-docs/07-projects.md +1 -1
- package/lib/help-docs/10-troubleshooting.md +10 -2
- package/lib/help-docs/16-gitlab-autofix.md +114 -0
- package/lib/help-docs/17-connectors.md +322 -0
- package/lib/help-docs/18-chrome-mcp.md +134 -0
- package/lib/help-docs/19-jobs.md +140 -0
- package/lib/help-docs/20-mantis-bug-fix.md +115 -0
- package/lib/help-docs/CLAUDE.md +10 -0
- package/lib/init.ts +137 -50
- package/lib/iso-time.ts +30 -0
- package/lib/issue-scanner-gitlab.ts +281 -0
- package/lib/jobs/dispatcher.ts +217 -0
- package/lib/jobs/scheduler.ts +334 -0
- package/lib/jobs/store.ts +319 -0
- package/lib/jobs/types.ts +117 -0
- package/lib/pipeline-scheduler.ts +1 -6
- package/lib/pipeline.ts +790 -10
- package/lib/plugins/registry.ts +133 -8
- package/lib/plugins/templates.ts +83 -0
- package/lib/plugins/types.ts +140 -1
- package/lib/session-watcher.ts +36 -10
- package/lib/settings.ts +65 -33
- package/lib/skills.ts +3 -1
- package/lib/task-manager.ts +50 -22
- package/lib/telegram-bot.ts +71 -0
- package/lib/terminal-standalone.ts +58 -36
- package/lib/workspace/orchestrator.ts +1 -0
- package/middleware.ts +10 -0
- package/package.json +3 -2
- package/scripts/bench/README.md +1 -1
- package/scripts/bench/tasks/01-text-utils/validator.sh +1 -1
- package/scripts/bench/tasks/02-pagination/setup.sh +1 -1
- package/scripts/bench/tasks/02-pagination/validator.sh +1 -1
- package/scripts/bench/tasks/03-bug-fix/setup.sh +1 -1
- package/scripts/bench/tasks/03-bug-fix/validator.sh +1 -1
- package/src/core/db/database.ts +21 -12
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Jobs — scheduled connector polls that fan out to pipelines or chat
|
|
2
|
+
|
|
3
|
+
## What a Job is
|
|
4
|
+
|
|
5
|
+
A Job is a new Forge primitive (alongside Task and Pipeline). It periodically
|
|
6
|
+
calls a **connector tool** and, for every new item in the result, **dispatches**
|
|
7
|
+
to either a Pipeline run or a Chat session.
|
|
8
|
+
|
|
9
|
+
Typical use cases:
|
|
10
|
+
- Every 30 min: `teams.list_messages_in_current_chat` → for each unread → POST
|
|
11
|
+
to a chat session that asks the assistant to summarize and reply.
|
|
12
|
+
- Every hour: `mantis.search_bugs query="version:25.4 status:open"` → for each
|
|
13
|
+
new bug → trigger the `bug-triage` pipeline bound to project `my-app` with
|
|
14
|
+
`bug_id`, `summary` as params.
|
|
15
|
+
|
|
16
|
+
Job vs the other two:
|
|
17
|
+
|
|
18
|
+
| Concept | Triggered by | Does what |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Task (existing) | manual / Telegram / API | one CLI-agent invocation |
|
|
21
|
+
| Pipeline (existing) | manual / schedule / GitHub issue / **Job** | DAG of CLI-agent tasks |
|
|
22
|
+
| **Job** (new) | scheduler tick (every `schedule_interval_minutes`) | calls one connector tool, dedups, dispatches per item |
|
|
23
|
+
|
|
24
|
+
The CLI keeps `forge task` / `forge pipeline` unchanged. A new `forge jobs`
|
|
25
|
+
subcommand handles Job CRUD + manual trigger.
|
|
26
|
+
|
|
27
|
+
## Storage (all sqlite)
|
|
28
|
+
|
|
29
|
+
The Job definition lives in sqlite — no yaml files — so the extension can
|
|
30
|
+
create / edit / delete jobs without writing to disk.
|
|
31
|
+
|
|
32
|
+
```sql
|
|
33
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
34
|
+
id TEXT PRIMARY KEY, -- short uuid
|
|
35
|
+
name TEXT NOT NULL,
|
|
36
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
37
|
+
schedule_interval_minutes INTEGER NOT NULL DEFAULT 30,
|
|
38
|
+
|
|
39
|
+
-- Source: which connector tool to call each tick
|
|
40
|
+
source_connector TEXT NOT NULL, -- plugin_id, e.g. 'mantis'
|
|
41
|
+
source_tool TEXT NOT NULL, -- tool name, e.g. 'search_bugs'
|
|
42
|
+
source_input TEXT NOT NULL DEFAULT '{}', -- JSON: passed verbatim as tool input
|
|
43
|
+
|
|
44
|
+
-- How to find items in the tool result + dedup key
|
|
45
|
+
items_path TEXT, -- dotted path; empty = whole result if array
|
|
46
|
+
dedup_field TEXT NOT NULL, -- dotted path on each item, e.g. 'id' or 'meta.uuid'
|
|
47
|
+
|
|
48
|
+
-- Dispatch (one of two modes)
|
|
49
|
+
dispatch_type TEXT NOT NULL, -- 'pipeline' | 'chat'
|
|
50
|
+
dispatch_params TEXT NOT NULL DEFAULT '{}', -- JSON; shape depends on type — see below
|
|
51
|
+
|
|
52
|
+
-- Bookkeeping
|
|
53
|
+
last_run_at TEXT,
|
|
54
|
+
next_run_at TEXT,
|
|
55
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
56
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE TABLE IF NOT EXISTS job_runs (
|
|
60
|
+
id TEXT PRIMARY KEY,
|
|
61
|
+
job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
|
62
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
63
|
+
finished_at TEXT,
|
|
64
|
+
status TEXT NOT NULL DEFAULT 'running', -- running | ok | error
|
|
65
|
+
items_seen INTEGER NOT NULL DEFAULT 0,
|
|
66
|
+
items_new INTEGER NOT NULL DEFAULT 0,
|
|
67
|
+
items_dispatched INTEGER NOT NULL DEFAULT 0,
|
|
68
|
+
error TEXT,
|
|
69
|
+
trigger TEXT NOT NULL DEFAULT 'schedule' -- schedule | manual
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
CREATE TABLE IF NOT EXISTS job_seen (
|
|
73
|
+
job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
|
74
|
+
dedup_key TEXT NOT NULL,
|
|
75
|
+
first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
76
|
+
PRIMARY KEY (job_id, dedup_key)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
CREATE TABLE IF NOT EXISTS job_dispatches (
|
|
80
|
+
id TEXT PRIMARY KEY,
|
|
81
|
+
job_run_id TEXT NOT NULL REFERENCES job_runs(id) ON DELETE CASCADE,
|
|
82
|
+
item_key TEXT NOT NULL,
|
|
83
|
+
item_preview TEXT, -- short rendering for the UI
|
|
84
|
+
dispatch_type TEXT NOT NULL, -- mirrored from job
|
|
85
|
+
dispatch_target_id TEXT, -- pipeline_id OR chat session_id
|
|
86
|
+
status TEXT NOT NULL DEFAULT 'dispatched', -- dispatched | error
|
|
87
|
+
error TEXT,
|
|
88
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_job_runs_job ON job_runs(job_id, started_at DESC);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_job_dispatches_run ON job_dispatches(job_run_id, created_at DESC);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## dispatch_params shape
|
|
96
|
+
|
|
97
|
+
### `dispatch_type = 'pipeline'`
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"workflow_name": "bug-triage",
|
|
102
|
+
"project_path": "/Users/me/code/my-app",
|
|
103
|
+
"project_name": "my-app",
|
|
104
|
+
"input_template": {
|
|
105
|
+
"bug_id": "{{item.id}}",
|
|
106
|
+
"summary": "{{item.summary}}",
|
|
107
|
+
"priority": "{{item.priority}}"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Per item: render `input_template` (string substitution `{{item.<path>}}`), then
|
|
113
|
+
call existing `triggerPipeline(project_path, project_name, workflow_name,
|
|
114
|
+
rendered_input, dedup_key=item_key)`.
|
|
115
|
+
|
|
116
|
+
### `dispatch_type = 'chat'`
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"agent_profile": "my-litellm", // optional; falls back to settings.chatAgent
|
|
121
|
+
"session_title_template": "Bug {{item.id}}: {{item.summary}}",
|
|
122
|
+
"message_template": "Process Mantis bug {{item.id}} (priority {{item.priority}}).\nSummary: {{item.summary}}\n\nFind the relevant branch and prepare a triage note.",
|
|
123
|
+
"reuse_session": false // if true, all items append to one session; else fresh session per item
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Per item: POST `/api/sessions` (or reuse) on chat-standalone, then POST a
|
|
128
|
+
message rendered from `message_template`. The chat agent gets the item and
|
|
129
|
+
decides what tools to call (could be another connector call, code edit via
|
|
130
|
+
shell, etc.).
|
|
131
|
+
|
|
132
|
+
## Template syntax
|
|
133
|
+
|
|
134
|
+
Values inside `{{ ... }}` use dotted paths into the item:
|
|
135
|
+
- `{{item.id}}` → item.id
|
|
136
|
+
- `{{item.assignee.name}}` → item.assignee.name
|
|
137
|
+
- `{{item}}` → JSON.stringify(item) (for dumping into a chat message)
|
|
138
|
+
|
|
139
|
+
Missing paths render to empty string. Non-string values render via
|
|
140
|
+
`String(...)` (numbers/booleans) or `JSON.stringify(...)` (objects).
|
|
141
|
+
|
|
142
|
+
Only `{{item.*}}` is supported in v1. `{{now}}` / `{{settings.*}}` are not
|
|
143
|
+
needed yet.
|
|
144
|
+
|
|
145
|
+
## Scheduler
|
|
146
|
+
|
|
147
|
+
Runs inside the same Next.js worker as `pipeline-scheduler` (started in
|
|
148
|
+
`lib/init.ts`). Every 60s:
|
|
149
|
+
|
|
150
|
+
1. Load all `enabled = 1` jobs where `next_run_at IS NULL OR next_run_at <= now`.
|
|
151
|
+
2. For each: insert a `job_runs` row, dispatch the tick asynchronously, advance
|
|
152
|
+
`next_run_at = now + interval_minutes`, set `last_run_at = now`.
|
|
153
|
+
3. Per-tick work happens in a background promise (HTTP / SSE / spawn don't block
|
|
154
|
+
the scheduler loop).
|
|
155
|
+
|
|
156
|
+
A tick is **idempotent** — if the previous tick is still running for the same
|
|
157
|
+
job (run row marked `status = 'running'` with no `finished_at`), the next tick
|
|
158
|
+
skips it and logs.
|
|
159
|
+
|
|
160
|
+
## A tick in detail
|
|
161
|
+
|
|
162
|
+
1. Resolve the connector + tool definition via `lib/plugins/registry` (same
|
|
163
|
+
path the chat dispatcher uses).
|
|
164
|
+
2. Call `dispatchTool({id: '<job-run-id>', name: '<connector>.<tool>', input:
|
|
165
|
+
source_input})` from `lib/chat/tool-dispatcher`. This handles `http` /
|
|
166
|
+
`shell` / `browser` uniformly. (Browser-protocol jobs require the extension
|
|
167
|
+
bridge to be connected at tick time — if not, surface as run error.)
|
|
168
|
+
3. Parse the tool's `content` string as JSON. Apply `items_path` to find the
|
|
169
|
+
array (e.g. `bugs` → `result.bugs`). If parsed value is already an array,
|
|
170
|
+
use it directly.
|
|
171
|
+
4. For each item:
|
|
172
|
+
- Compute `key = pickPath(item, dedup_field)`. Stringify.
|
|
173
|
+
- `INSERT OR IGNORE INTO job_seen (job_id, dedup_key)` — if a new row was
|
|
174
|
+
written, it's a new item.
|
|
175
|
+
- For new items only: dispatch via the configured type, insert into
|
|
176
|
+
`job_dispatches` with the resulting target id.
|
|
177
|
+
5. Update `job_runs` row with counts + finished_at + status.
|
|
178
|
+
|
|
179
|
+
## API surface
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
GET /api/jobs list (enabled+disabled)
|
|
183
|
+
POST /api/jobs create
|
|
184
|
+
GET /api/jobs/:id detail (with last 20 runs)
|
|
185
|
+
PATCH /api/jobs/:id partial update
|
|
186
|
+
DELETE /api/jobs/:id cascade delete
|
|
187
|
+
POST /api/jobs/:id/run manual fire-now (returns run id)
|
|
188
|
+
GET /api/jobs/:id/runs?limit=20 run history
|
|
189
|
+
GET /api/jobs/:id/runs/:run_id run detail (with dispatches)
|
|
190
|
+
POST /api/jobs/:id/reset_dedup wipe job_seen rows (force re-process all)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
All gated by the existing Forge middleware (X-Forge-Token).
|
|
194
|
+
|
|
195
|
+
## CLI
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
forge jobs list
|
|
199
|
+
forge jobs new <interactive prompts> create
|
|
200
|
+
forge jobs run <id> fire now
|
|
201
|
+
forge jobs runs <id> history
|
|
202
|
+
forge jobs rm <id>
|
|
203
|
+
forge jobs disable <id> / enable <id>
|
|
204
|
+
forge jobs reset <id> wipe dedup state
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Extension UI (Tasks → Jobs)
|
|
208
|
+
|
|
209
|
+
`TasksTab.tsx` renames to `JobsTab.tsx`. Tab label "Tasks" → "Jobs".
|
|
210
|
+
|
|
211
|
+
Sections:
|
|
212
|
+
1. **Active jobs** — for each: name, schedule, last run time + items new/seen,
|
|
213
|
+
next run countdown, enable toggle, "Run now" button.
|
|
214
|
+
2. **+ New job** — modal:
|
|
215
|
+
- name, interval
|
|
216
|
+
- source: connector dropdown (from `/api/connectors`), tool dropdown
|
|
217
|
+
(populated from selected connector's tools), input JSON
|
|
218
|
+
- items_path + dedup_field (with examples per connector)
|
|
219
|
+
- dispatch type radio: pipeline | chat
|
|
220
|
+
- pipeline: workflow dropdown (`/api/pipelines/workflows`), project
|
|
221
|
+
dropdown (`/api/projects`), input_template builder
|
|
222
|
+
- chat: agent profile dropdown (`/api/agents`), session_title template,
|
|
223
|
+
message_template (textarea), reuse_session toggle
|
|
224
|
+
3. **Recent runs** (collapsed by default) — last 20 across all jobs.
|
|
225
|
+
|
|
226
|
+
Per architecture rule: extension is display + DOM connectors only. All
|
|
227
|
+
scheduling, dedup, dispatch happens server-side. The extension talks to Forge
|
|
228
|
+
HTTP only — no local state for jobs.
|
|
229
|
+
|
|
230
|
+
## Out of scope (v1)
|
|
231
|
+
|
|
232
|
+
- Cron expressions (interval-only)
|
|
233
|
+
- Item filtering before dispatch (just write the connector tool to return
|
|
234
|
+
filtered)
|
|
235
|
+
- Conditional dispatch (always-fire on new item; for skip-logic, use the
|
|
236
|
+
pipeline / chat to decide internally)
|
|
237
|
+
- Webhook triggers (still poll-based)
|
|
238
|
+
- Backfill controls (initial tick auto-marks everything as seen without
|
|
239
|
+
dispatching, so a brand-new job doesn't fire on history — controlled by
|
|
240
|
+
`mark_existing_as_seen` flag at create time, default true)
|
package/docs/LOCAL-DEPLOY.md
CHANGED
|
@@ -90,14 +90,14 @@ caffeinate -d -i -s &
|
|
|
90
90
|
### 注册为系统服务(开机自启 + 崩溃自重启)
|
|
91
91
|
|
|
92
92
|
```xml
|
|
93
|
-
<!-- ~/Library/LaunchAgents/com.
|
|
93
|
+
<!-- ~/Library/LaunchAgents/com.forge.my-workflow.plist -->
|
|
94
94
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
95
95
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
96
96
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
97
97
|
<plist version="1.0">
|
|
98
98
|
<dict>
|
|
99
99
|
<key>Label</key>
|
|
100
|
-
<string>com.
|
|
100
|
+
<string>com.forge.my-workflow</string>
|
|
101
101
|
<key>ProgramArguments</key>
|
|
102
102
|
<array>
|
|
103
103
|
<string>/usr/local/bin/mw</string>
|
|
@@ -119,7 +119,7 @@ caffeinate -d -i -s &
|
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
121
|
# 注册服务
|
|
122
|
-
launchctl load ~/Library/LaunchAgents/com.
|
|
122
|
+
launchctl load ~/Library/LaunchAgents/com.forge.my-workflow.plist
|
|
123
123
|
|
|
124
124
|
# 查看状态
|
|
125
125
|
launchctl list | grep my-workflow
|