@aion0/forge 0.8.1 → 0.8.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 (45) hide show
  1. package/RELEASE_NOTES.md +6 -6
  2. package/app/api/connectors/[id]/settings/route.ts +31 -37
  3. package/app/api/connectors/[id]/test/route.ts +260 -0
  4. package/app/api/connectors/install-local/route.ts +211 -0
  5. package/app/api/connectors/marketplace/route.ts +79 -0
  6. package/app/api/connectors/route.ts +41 -46
  7. package/app/api/jobs/route.ts +4 -0
  8. package/app/api/skills/install-local/route.ts +282 -0
  9. package/components/ConnectorsPanel.tsx +526 -211
  10. package/components/SettingsModal.tsx +1 -0
  11. package/components/SkillsPanel.tsx +42 -1
  12. package/lib/agents/claude-adapter.ts +4 -0
  13. package/lib/agents/types.ts +6 -0
  14. package/lib/chat/agent-loop.ts +13 -22
  15. package/lib/chat/protocols/http.ts +1 -1
  16. package/lib/chat/protocols/shell.ts +1 -1
  17. package/lib/chat/tool-dispatcher.ts +20 -20
  18. package/lib/connectors/migration.ts +110 -0
  19. package/lib/connectors/registry.ts +328 -0
  20. package/lib/connectors/sync.ts +305 -0
  21. package/lib/connectors/types.ts +253 -0
  22. package/lib/help-docs/00-overview.md +1 -0
  23. package/lib/help-docs/17-connectors.md +241 -189
  24. package/lib/help-docs/21-build-connector.md +314 -0
  25. package/lib/help-docs/CLAUDE.md +4 -2
  26. package/lib/init.ts +25 -0
  27. package/lib/jobs/dispatcher.ts +28 -8
  28. package/lib/jobs/scheduler.ts +66 -6
  29. package/lib/jobs/store.ts +51 -2
  30. package/lib/jobs/types.ts +32 -0
  31. package/lib/pipeline-scheduler.ts +3 -2
  32. package/lib/pipeline.ts +137 -15
  33. package/lib/plugins/registry.ts +9 -42
  34. package/lib/plugins/types.ts +4 -129
  35. package/lib/settings.ts +7 -0
  36. package/lib/skills.ts +27 -1
  37. package/lib/task-manager.ts +62 -2
  38. package/package.json +4 -1
  39. package/src/core/db/database.ts +4 -0
  40. package/lib/builtin-plugins/github-api.yaml +0 -93
  41. package/lib/builtin-plugins/gitlab.yaml +0 -860
  42. package/lib/builtin-plugins/mantis.probe.js +0 -176
  43. package/lib/builtin-plugins/mantis.yaml +0 -964
  44. package/lib/builtin-plugins/pmdb.yaml +0 -178
  45. package/lib/builtin-plugins/teams.yaml +0 -913
@@ -44,6 +44,14 @@ function db() {
44
44
  // Per-task model overrides (used by pipeline to set pipelineModel)
45
45
  export const taskModelOverrides = new Map<string, string>();
46
46
 
47
+ /**
48
+ * Per-task append-system-prompt overrides. Used by Forge job/pipeline
49
+ * to point the agent at specific skills for this run. Keyed by task
50
+ * id; lives in-process (re-applied via the pipeline state on restart
51
+ * since we re-create the task there).
52
+ */
53
+ export const taskAppendSystemPromptOverrides = new Map<string, string>();
54
+
47
55
  // ─── CRUD ────────────────────────────────────────────────────
48
56
 
49
57
  export function createTask(opts: {
@@ -351,6 +359,50 @@ async function processNextTask() {
351
359
  }
352
360
  }
353
361
 
362
+ /**
363
+ * Surface installed-connector PATs as env vars to shell tasks. Lets
364
+ * pipeline shell steps (push-and-mr, gh-issue-fix, ...) use the same
365
+ * credential the user typed into Settings → Connectors instead of
366
+ * relying on `glab auth login` / `gh auth login` having been run
367
+ * separately (and not revoked).
368
+ *
369
+ * Only well-known connectors map to env vars. Token never leaves the
370
+ * server — the bash child inherits the env directly.
371
+ */
372
+ function connectorEnv(): Record<string, string> {
373
+ try {
374
+ const { getInstalledConnector } = require('./connectors/registry');
375
+ const out: Record<string, string> = {};
376
+ const gitlab = getInstalledConnector('gitlab');
377
+ if (gitlab?.enabled) {
378
+ const tok = typeof gitlab.config?.token === 'string' ? gitlab.config.token.trim() : '';
379
+ if (tok) {
380
+ // glab CLI honours GITLAB_TOKEN; HTTP libs honour CI_JOB_TOKEN-style names too,
381
+ // but GITLAB_TOKEN covers glab + most curl-based scripts in our pipelines.
382
+ out.GITLAB_TOKEN = tok;
383
+ if (typeof gitlab.config?.base_url === 'string' && gitlab.config.base_url) {
384
+ // glab uses GITLAB_URI for the API host on self-hosted instances.
385
+ try {
386
+ const u = new URL(String(gitlab.config.base_url));
387
+ out.GITLAB_URI = u.origin;
388
+ } catch {}
389
+ }
390
+ }
391
+ }
392
+ const gh = getInstalledConnector('github-api');
393
+ if (gh?.enabled) {
394
+ const tok = typeof gh.config?.token === 'string' ? gh.config.token.trim() : '';
395
+ if (tok) {
396
+ out.GITHUB_TOKEN = tok;
397
+ out.GH_TOKEN = tok; // gh CLI honours either; set both for safety.
398
+ }
399
+ }
400
+ return out;
401
+ } catch {
402
+ return {};
403
+ }
404
+ }
405
+
354
406
  function executeShellTask(task: Task): Promise<void> {
355
407
  return new Promise((resolve) => {
356
408
  updateTaskStatus(task.id, 'running');
@@ -365,7 +417,11 @@ function executeShellTask(task: Task): Promise<void> {
365
417
  const shell = process.env.SHELL && process.env.SHELL.endsWith('bash') ? process.env.SHELL : '/bin/bash';
366
418
  const child = spawn(shell, ['-c', task.prompt], {
367
419
  cwd: task.projectPath,
368
- env: { ...process.env, PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin' },
420
+ env: {
421
+ ...process.env,
422
+ PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin',
423
+ ...connectorEnv(),
424
+ },
369
425
  stdio: ['ignore', 'pipe', 'pipe'],
370
426
  });
371
427
 
@@ -433,9 +489,13 @@ function executeTask(task: Task): Promise<void> {
433
489
  conversationId: task.conversationId || undefined,
434
490
  skipPermissions: true,
435
491
  outputFormat: adapter.config.capabilities?.supportsStreamJson ? 'stream-json' : undefined,
492
+ appendSystemPrompt: taskAppendSystemPromptOverrides.get(task.id),
436
493
  });
437
494
 
438
- const env = { ...process.env, ...(spawnOpts.env || {}) };
495
+ // Surface connector PATs (GITLAB_TOKEN, GITHUB_TOKEN, ) so the
496
+ // child's Bash invocations (claude's Bash tool, gh/glab shells)
497
+ // pick them up automatically. Same logic as executeShellTask.
498
+ const env = { ...process.env, ...connectorEnv(), ...(spawnOpts.env || {}) };
439
499
  delete env.CLAUDECODE;
440
500
 
441
501
  updateTaskStatus(task.id, 'running');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aion0/forge",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -34,14 +34,17 @@
34
34
  "@anthropic-ai/sdk": "^0.96.0",
35
35
  "@auth/core": "^0.34.3",
36
36
  "@modelcontextprotocol/sdk": "^1.28.0",
37
+ "@types/adm-zip": "^0.5.8",
37
38
  "@xterm/addon-fit": "^0.11.0",
38
39
  "@xterm/addon-search": "^0.16.0",
39
40
  "@xterm/addon-unicode11": "^0.9.0",
40
41
  "@xterm/addon-webgl": "^0.19.0",
41
42
  "@xterm/xterm": "^6.0.0",
42
43
  "@xyflow/react": "^12.10.1",
44
+ "adm-zip": "^0.5.17",
43
45
  "ai": "^6.0.116",
44
46
  "better-sqlite3": "^12.6.2",
47
+ "cron-parser": "^5.5.0",
45
48
  "esbuild": "^0.27.3",
46
49
  "next": "^16.2.1",
47
50
  "next-auth": "5.0.0-beta.30",
@@ -34,6 +34,10 @@ function initSchema(db: Database.Database) {
34
34
  migrate("ALTER TABLE skills ADD COLUMN installed_version TEXT NOT NULL DEFAULT ''");
35
35
  migrate('ALTER TABLE skills ADD COLUMN rating REAL DEFAULT 0');
36
36
  migrate('ALTER TABLE skills ADD COLUMN deleted_remotely INTEGER NOT NULL DEFAULT 0');
37
+ // 'registry' (synced from forge-skills) vs 'local' (uploaded by user).
38
+ // Local skills are kept across syncs (they're not in the remote registry,
39
+ // so the deleted_remotely housekeeping would otherwise wipe them).
40
+ migrate("ALTER TABLE skills ADD COLUMN source TEXT NOT NULL DEFAULT 'registry'");
37
41
  migrate('ALTER TABLE project_pipelines ADD COLUMN last_run_at TEXT');
38
42
  migrate('ALTER TABLE pipeline_runs ADD COLUMN dedup_key TEXT');
39
43
  migrate("ALTER TABLE tasks ADD COLUMN agent TEXT DEFAULT 'claude'");
@@ -1,93 +0,0 @@
1
- id: github-api
2
- name: GitHub API
3
- icon: 🐙
4
- version: 0.1.0
5
- author: forge
6
- description: |
7
- GitHub REST API connector — runs entirely server-side (no browser tab
8
- needed). Set settings.token to a personal access token for private
9
- repos / higher rate limits; public-only endpoints work unauthenticated.
10
-
11
- Demonstrates the `protocol: http` runtime: the connector declares the
12
- request shape and Forge issues it from the server. Templates expand
13
- {settings.*} (user-supplied) and {args.*} (LLM-supplied) into url,
14
- headers, query, and body.
15
-
16
- category: connector
17
- mode: server-side
18
-
19
- settings:
20
- token:
21
- type: string
22
- label: GitHub token (optional)
23
- description: Personal access token. Leave empty for public endpoints.
24
- secret: true
25
-
26
- tools:
27
- get_repo:
28
- description: |
29
- Fetch metadata for a GitHub repository (description, stars, default
30
- branch, etc.).
31
- protocol: http
32
- parameters:
33
- repo:
34
- type: string
35
- required: true
36
- description: 'Repository in "owner/name" form (e.g. "anthropics/anthropic-sdk-python").'
37
- request:
38
- method: GET
39
- url: 'https://api.github.com/repos/{args.repo}'
40
- headers:
41
- Accept: 'application/vnd.github+json'
42
- Authorization: 'Bearer {settings.token}'
43
- User-Agent: 'forge-github-connector'
44
-
45
- list_issues:
46
- description: |
47
- List issues in a GitHub repository. Default returns open issues
48
- (most recent first). Use state="closed" or state="all" to widen.
49
- protocol: http
50
- parameters:
51
- repo:
52
- type: string
53
- required: true
54
- description: 'Repository in "owner/name" form.'
55
- state:
56
- type: string
57
- description: 'open | closed | all (default: open).'
58
- per_page:
59
- type: number
60
- description: 'Results per page (1–100, default 30).'
61
- request:
62
- method: GET
63
- url: 'https://api.github.com/repos/{args.repo}/issues'
64
- headers:
65
- Accept: 'application/vnd.github+json'
66
- Authorization: 'Bearer {settings.token}'
67
- User-Agent: 'forge-github-connector'
68
- query:
69
- state: '{args.state}'
70
- per_page: '{args.per_page}'
71
-
72
- search_repos:
73
- description: |
74
- Search GitHub repositories by keyword. Sorted by stars desc by
75
- default. Use q to pass GitHub search qualifiers
76
- (e.g. "language:go forks:>100 created:>2024").
77
- protocol: http
78
- parameters:
79
- q:
80
- type: string
81
- required: true
82
- description: 'Search query (GitHub search syntax).'
83
- request:
84
- method: GET
85
- url: 'https://api.github.com/search/repositories'
86
- headers:
87
- Accept: 'application/vnd.github+json'
88
- Authorization: 'Bearer {settings.token}'
89
- User-Agent: 'forge-github-connector'
90
- query:
91
- q: '{args.q}'
92
- sort: stars
93
- order: desc