@aion0/forge 0.9.1 → 0.9.3

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 (71) hide show
  1. package/RELEASE_NOTES.md +5 -5
  2. package/app/api/agents/[id]/test/route.ts +150 -0
  3. package/app/api/connectors/[id]/sync-cli/route.ts +73 -0
  4. package/app/api/connectors/tool-test/route.ts +70 -0
  5. package/app/api/jobs/[id]/cancel/route.ts +50 -0
  6. package/app/api/jobs/[id]/dispatched-pipelines/route.ts +24 -0
  7. package/app/api/jobs/[id]/run/route.ts +22 -2
  8. package/app/api/jobs/route.ts +11 -1
  9. package/app/api/pipelines/[id]/schema/route.ts +53 -0
  10. package/app/api/pipelines/bulk-delete/route.ts +39 -0
  11. package/app/api/pipelines/gc/route.ts +27 -0
  12. package/app/api/schedules/[id]/cancel/route.ts +27 -0
  13. package/app/api/schedules/[id]/route.ts +173 -0
  14. package/app/api/schedules/[id]/run/route.ts +45 -0
  15. package/app/api/schedules/[id]/runs/route.ts +22 -0
  16. package/app/api/schedules/[id]/stop/route.ts +33 -0
  17. package/app/api/schedules/route.ts +175 -0
  18. package/app/api/tasks/bulk-delete/route.ts +47 -0
  19. package/bin/forge-server.mjs +22 -1
  20. package/cli/mw.mjs +186 -7657
  21. package/cli/mw.ts +26 -0
  22. package/components/ConnectorsPanel.tsx +46 -0
  23. package/components/Dashboard.tsx +23 -10
  24. package/components/JobsView.tsx +245 -6
  25. package/components/PipelineEditor.tsx +38 -1
  26. package/components/PipelineView.tsx +325 -4
  27. package/components/ScheduleCreateModal.tsx +1507 -0
  28. package/components/SchedulesView.tsx +605 -0
  29. package/components/SettingsModal.tsx +106 -0
  30. package/docs/Team-Workflow-Integration.md +487 -0
  31. package/docs/UI-Design-Brief-SidePanel.md +278 -0
  32. package/lib/__tests__/foreach-batch-yaml.test.ts +33 -0
  33. package/lib/__tests__/foreach-before.test.ts +201 -0
  34. package/lib/__tests__/foreach-parse.test.ts +114 -0
  35. package/lib/__tests__/foreach-snapshot.test.ts +112 -0
  36. package/lib/__tests__/foreach-source.test.ts +105 -0
  37. package/lib/__tests__/foreach-template.test.ts +112 -0
  38. package/lib/chat/agent-loop.ts +3 -3
  39. package/lib/chat-standalone.ts +26 -1
  40. package/lib/claude-process.ts +8 -5
  41. package/lib/connectors/sync.ts +8 -2
  42. package/lib/crypto.ts +1 -1
  43. package/lib/dirs.ts +22 -7
  44. package/lib/help-docs/05-pipelines.md +171 -0
  45. package/lib/help-docs/13-schedules.md +165 -0
  46. package/lib/help-docs/23-automation-states.md +148 -0
  47. package/lib/help-docs/CLAUDE.md +6 -6
  48. package/lib/init.ts +25 -6
  49. package/lib/jobs/recipes.ts +3 -2
  50. package/lib/jobs/scheduler.ts +215 -11
  51. package/lib/jobs/store.ts +79 -3
  52. package/lib/jobs/types.ts +31 -0
  53. package/lib/logger.ts +1 -1
  54. package/lib/notify.ts +13 -6
  55. package/lib/pipeline-gc.ts +105 -0
  56. package/lib/pipeline-scheduler.ts +29 -0
  57. package/lib/pipeline.ts +811 -330
  58. package/lib/schedules/action-runner.ts +257 -0
  59. package/lib/schedules/scheduler.ts +422 -0
  60. package/lib/schedules/state.ts +41 -0
  61. package/lib/schedules/store.ts +618 -0
  62. package/lib/schedules/types.ts +117 -0
  63. package/lib/settings.ts +35 -0
  64. package/lib/task-manager.ts +56 -13
  65. package/lib/telegram-bot.ts +9 -3
  66. package/lib/workflow-marketplace.ts +7 -1
  67. package/lib/workspace/skill-installer.ts +7 -6
  68. package/package.json +3 -1
  69. package/lib/help-docs/19-jobs.md +0 -145
  70. package/lib/help-docs/20-mantis-bug-fix.md +0 -115
  71. package/lib/help-docs/22-recipes.md +0 -124
@@ -1,115 +0,0 @@
1
- # Mantis → Bug Fix → MR pipeline
2
-
3
- End-to-end: a Mantis bug surfaces (via a Forge **Job** polling mantis.get_bug
4
- / mantis.search_bugs) → triggers a Pipeline → Pipeline checks out the right
5
- base branch in a worktree → headless Claude implements the fix → pipeline
6
- opens a GitLab MR via `glab` → pipeline pings the assignee + reporter on
7
- Teams with the MR URL.
8
-
9
- Mirrors the `gitlab-issue-fix-and-review` builtin but driven by Mantis
10
- content (description / priority / category / assignee / reporter), MR
11
- opens against an explicit `base_branch` you pass in from the Job (because
12
- Mantis doesn't carry milestones the way GitLab issues do).
13
-
14
- ## Builtin name
15
-
16
- `mantis-bug-fix-and-mr` — registered in Forge's built-in workflow set,
17
- visible in the Pipelines view's workflow dropdown and pickable from the
18
- extension Jobs tab when you wire a Pipeline-dispatch Job.
19
-
20
- ## Inputs (set by the Job's `input_template`)
21
-
22
- | Key | Required | Source |
23
- |---|---|---|
24
- | `bug_id` | yes | `{{item.id}}` |
25
- | `project` | yes | injected by `triggerPipeline` from the Job's project setting |
26
- | `base_branch` | **yes** | `{{item.product_version}}` mapped to a branch, OR a literal like `"release/25.4"` you write into the template |
27
- | `summary` | yes | `{{item.summary}}` |
28
- | `description` | yes | `{{item.description}}` |
29
- | `priority` | opt | `{{item.priority}}` |
30
- | `category` | opt | `{{item.category}}` |
31
- | `assignee` | opt | `{{item.assignee}}` — used as Teams chat name |
32
- | `reporter` | opt | `{{item.reporter}}` — used as Teams chat name |
33
- | `extra_context` | opt | literal hint text for Claude |
34
- | `mr_title_template` | opt | default `Fix Mantis #{bug_id}: {summary}` |
35
- | `mr_body_template` | opt | default closes-ref + Claude summary; vars `{bug_id} {summary} {description} {claude_summary}` |
36
- | `teams_message_template` | opt | default `🤖 Mantis #{bug_id} fixed — please review MR: {mr_url}\nBug: {summary}`; vars `{bug_id} {summary} {role} {mr_url}` |
37
-
38
- ## Nodes
39
-
40
- ```
41
- resolve parse git remote → HOST + PROJECT_PATH; check glab; require base_branch
42
- worktree-setup git worktree add -b fix/mantis-<id> .forge/worktrees/mantis-<id> origin/<base>
43
- fix-code headless Claude — reads bug context, edits in worktree, commits
44
- push-and-mr if any commits: push fix/mantis-<id>, glab mr create → MR_URL
45
- notify-teams curl /api/connector-tool teams.send_message twice (assignee + reporter)
46
- ```
47
-
48
- `fix-code` runs as a normal Claude task (not shell) so it can think, browse,
49
- edit, and commit. `notify-teams` short-circuits if `push-and-mr` couldn't
50
- create an MR (e.g. Claude made no changes).
51
-
52
- ## Talking to connectors from a pipeline
53
-
54
- `notify-teams` calls `POST http://127.0.0.1:8403/api/connector-tool` —
55
- a loopback-only endpoint that wraps `lib/chat/tool-dispatcher`. Body:
56
-
57
- ```json
58
- { "plugin_id": "teams", "tool": "send_message",
59
- "input": { "name": "Alice", "text": "MR: https://..." } }
60
- ```
61
-
62
- Returns the standard `{ content, is_error }` tool-result shape. Works for
63
- `browser` / `http` / `shell` protocol connectors. Browser-protocol calls
64
- need the extension bridge connected at pipeline runtime (Chrome open +
65
- extension signed in).
66
-
67
- ## Wiring it up from a Job
68
-
69
- 1. Confirm `glab` is installed + authed for the target host:
70
- `glab auth login --hostname <your-gitlab.example.com>`
71
- 2. Make sure the project has a git remote (`git remote get-url origin`) the
72
- `glab mr create` call can reach.
73
- 3. Forge extension → Jobs → + New job. Pick:
74
- - Connector / tool: `mantis` / `get_bug` (single bug) or `search_bugs` (a query)
75
- - dispatch: Pipeline → workflow `mantis-bug-fix-and-mr` → your project
76
- - `input_template` (auto-prefilled when you pick the workflow; map item
77
- keys to inputs, hardcode `base_branch` if Mantis doesn't carry it):
78
- ```json
79
- {
80
- "bug_id": "{{item.id}}",
81
- "summary": "{{item.summary}}",
82
- "description": "{{item.description}}",
83
- "priority": "{{item.priority}}",
84
- "category": "{{item.category}}",
85
- "assignee": "{{item.assignee}}",
86
- "reporter": "{{item.reporter}}",
87
- "base_branch": "release/25.4"
88
- }
89
- ```
90
- 4. Save → Run now (first tick is a backfill-no-op; click Reset dedup +
91
- Run now to force one actual dispatch for testing).
92
-
93
- ## Customising
94
-
95
- - Branch derivation rules (e.g. `target_version` → `release/<major.minor>`):
96
- edit the `resolve` node in your local copy at
97
- `~/.forge/data/flows/mantis-bug-fix-and-mr.yaml` (a copy will be created
98
- when you click Edit in the Pipelines view; once a local file exists it
99
- overrides the builtin).
100
- - MR title / body templates: set via the Job's `input_template` — no
101
- pipeline edit needed.
102
- - Teams routing: today it uses the Mantis username verbatim as the Teams
103
- chat name (substring match). For better mapping, post-process in
104
- `notify-teams` to convert username → real name via a lookup table or
105
- a second connector call.
106
-
107
- ## Troubleshooting
108
-
109
- | Symptom | Cause + fix |
110
- |---|---|
111
- | `ERROR: base_branch is required` | The Job's `input_template` didn't supply it — Mantis bugs don't always carry one. Hardcode it in the template or map from `product_version`. |
112
- | `NO_CHANGES — Claude did not commit` | Bug description was too thin or Claude couldn't find the affected code. Add hints via `extra_context` or open the worktree manually and iterate. |
113
- | `glab mr create` returns nothing | Token expired / target branch protected / source branch already has an open MR. The pipeline falls back to `glab mr view` to surface the existing URL — check Pipelines log. |
114
- | Teams send returns `No extension connected to the bridge` | The pipeline ran when Chrome / extension weren't online. Notification fails but the MR still landed; re-fire the `notify-teams` node manually or message the people yourself. |
115
- | Mantis username doesn't match any Teams chat | The fuzzy substring match in `teams.send_message` falls back to whatever the LLM-less DOM script can match. Add a lookup step before `notify-teams` to translate names. |
@@ -1,124 +0,0 @@
1
- # Recipes & GitLab MR auto-fix
2
-
3
- A **Recipe** is a parameterized template for a Job + its dispatched pipeline. Instead of hand-filling 12 fields in the Jobs form, you pick a recipe, fill 3-4 high-level params, and Forge instantiates the rest.
4
-
5
- Recipes live under `~/.forge/data/recipes/*.yaml`. The canonical catalog is `aiwatching/forge-workflow` on GitHub; Marketplace ↓ Sync pulls the latest registry.
6
-
7
- ## Built-in recipes
8
-
9
- | Name | What it does | Source tool |
10
- |---|---|---|
11
- | `gitlab-mr-watch` | Watch ONE specific MR for new review comments → run `mr-review-fix` | `gitlab.get_mr` |
12
- | `gitlab-my-mrs-watch` | Watch all MRs assigned to you → run `mr-review-fix` per MR | `gitlab.list_my_mrs` |
13
- | `mantis-bug-fix` | Manual fire — fix a single Mantis bug → run `mantis-bug-fix-and-mr` | `mantis.get_bug` |
14
- | `mantis-bug-watch` | Periodic — fix bugs matching a filter | `mantis.search_bugs` |
15
-
16
- ## Creating a Job from a recipe
17
-
18
- Extension → Jobs tab → **+ From recipe…** → pick one → fill the form → Create.
19
-
20
- For `gitlab-mr-watch` you fill:
21
- - **Local project name** (picks a directory under `projectRoots`)
22
- - **MR URL** — paste the full URL like `https://gitlab.example.com/namespace/repo/-/merge_requests/123`. Forge auto-extracts namespace/repo + iid.
23
- - **Poll interval** (minutes, default 5)
24
- - **Triage policy** (free-form, optional — ships with a sensible default)
25
-
26
- ## Special param types
27
-
28
- - `project_picker` — dropdown of dirs under your configured `projectRoots`
29
- - `gitlab_mr_url` — single MR URL; Forge parses out `<name>__path` (`namespace/repo`) + `<name>__iid` (numeric iid) at instantiation time. Reference them in templates via `{{params.mr_url__path}}` / `{{params.mr_url__iid}}`.
30
- - `number` — coerces string → number
31
- - `boolean` — coerces truthy strings
32
-
33
- ## The `mr-review-fix` pipeline — 5 nodes
34
-
35
- 1. **ingest** (shell, no worktree) — `glab api` pulls MR meta + ALL notes + diff into `/tmp/mr-<iid>-*.{json,txt}`. Emits `SOURCE_BRANCH`, `MR_TITLE`, `MR_AUTHOR`, `LATEST_COMMENTER`, file paths.
36
- 2. **triage** (AI, no worktree, no shell) — reads all notes holistically, decides action.
37
- 3. **fix** (AI, branch `mr-<iid>` worktree) — runs the git work only on ACT path.
38
- 4. **reply** (shell) — posts a comment on the MR describing the outcome; adds a label; closes the MR if needed.
39
- 5. **cleanup** (shell) — Teams notify + worktree removal + tmp file cleanup.
40
-
41
- ### Four triage actions
42
-
43
- | ACTION | Meaning | Reply posted? | Label | MR state |
44
- |---|---|---|---|---|
45
- | `act` | Comments name a concrete fix → apply it | yes (with diff summary) | `forge:fix-applied` | push fixup to source_branch |
46
- | `skip` | Substantive but no change needed (lgtm, nits, questions) | yes (explanation) | `forge:no-fix-needed` | unchanged |
47
- | `close` | MR itself shouldn't merge (duplicate, wrong direction, already-fixed-elsewhere) | yes (rationale) | `forge:no-merge` | **closed** via `glab api PUT state_event=close` |
48
- | `noop` | Latest non-system comment is Forge's own or this Job's user → nothing changed since last run | **no** (silent) | none | unchanged |
49
-
50
- The `noop` case is the loop-breaker. Without it, Forge's auto-reply bumps `user_notes_count`, the next tick sees a new state, fires again, posts another reply — endless self-conversation.
51
-
52
- ### Required GitLab labels (one-time)
53
-
54
- Create these in **GitLab → Project → Labels → New label** (any colors):
55
-
56
- ```
57
- forge:fix-applied (suggest green)
58
- forge:no-fix-needed (suggest blue)
59
- forge:no-merge (suggest red)
60
- ```
61
-
62
- If a label is missing, the label-add step logs a failure but the rest of the pipeline still runs.
63
-
64
- ### Triage prompt — when to customize
65
-
66
- The recipe ships with a default `triage_instructions` covering common cases. Overwrite when you need project-specific rules. Examples:
67
-
68
- ```
69
- Only act if the reviewer is from team @backend. Skip everything else.
70
- ```
71
-
72
- ```
73
- Act ONLY on Code Review Bot 'error' findings; skip all human comments.
74
- ```
75
-
76
- ```
77
- Treat any comment containing "MUST" as actionable; everything else SKIP.
78
- ```
79
-
80
- Keep the noop clause at the bottom of any custom policy:
81
-
82
- ```
83
- NOOP when the latest non-system comment is authored by @<your-username>
84
- or starts with '🤖 Forge:'.
85
- ```
86
-
87
- ## Per-MR vs per-comment dispatch
88
-
89
- Older recipe versions used `gitlab.list_mr_notes` and fired ONE pipeline per new comment — 50 historical comments on first Fire meant 50 pipelines. Current recipes use `gitlab.get_mr` + dedup on `user_notes_count`:
90
-
91
- - Fetches the MR object once; scheduler wraps as 1-item list
92
- - `user_notes_count` only changes when comments are added/removed → label flips, status changes, assignee changes don't false-trigger
93
- - First Fire registers the current count as "seen" via `__mark_existing_as_seen: true` — no backfill stampede
94
-
95
- ## Marketplace ↔ local copy split
96
-
97
- - **Marketplace** (Settings → Marketplace → Templates → Recipes / Pipelines) lists ONLY items from the registry (`forge-workflow` repo). Editing-by-hand or "Import as new copy" workflows don't appear here.
98
- - **Pipelines tab** lists ALL local workflow yamls — registry-sourced installs, your custom edits, anything in `~/.forge/data/flows/`.
99
- - **Reinstall** button overwrites a local copy with the current registry version (use after a version bump).
100
- - Local copies are **independent** of marketplace — Forge will never silently overwrite a local file you've edited.
101
-
102
- ## Cleanup recipes
103
-
104
- ```bash
105
- # Delete a Job + its dedup state + any pending pipeline runs
106
- sqlite3 ~/.forge/data/workflow.db <<'SQL'
107
- DELETE FROM jobs WHERE name='mr-watch-FortiNAC-14636';
108
- DELETE FROM job_dedup_keys WHERE job_id NOT IN (SELECT id FROM jobs);
109
- DELETE FROM pipelines WHERE workflow_name='mr-review-fix' AND status IN ('pending','running');
110
- SQL
111
-
112
- # Force re-trigger on next tick — clears dedup so any state looks "new"
113
- sqlite3 ~/.forge/data/workflow.db "DELETE FROM job_dedup_keys WHERE job_id IN (SELECT id FROM jobs WHERE source_tool='get_mr');"
114
- ```
115
-
116
- ## Where things live on disk
117
-
118
- | Path | Purpose |
119
- |---|---|
120
- | `~/.forge/data/recipes/*.yaml` | Local recipe copies |
121
- | `~/.forge/data/flows/*.yaml` | Local workflow copies (mr-review-fix, mantis-bug-fix-and-mr, custom) |
122
- | `~/.forge/data/workflow.db` | Job rows, dedup keys, run history |
123
- | `~/.forge/data/pipelines/*.json` | Per-run state for each pipeline execution |
124
- | `~/.forge/data/workflow-cache.json` | Last-synced registry from `forge-workflow` repo |