@musashishao/folderforge 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +181 -0
  2. package/dist/adapters/child-mcp/client.js +114 -0
  3. package/dist/adapters/child-mcp/registry.js +66 -0
  4. package/dist/audit/audit-log.js +45 -0
  5. package/dist/audit/event-types.js +1 -0
  6. package/dist/core/config.js +211 -0
  7. package/dist/core/container.js +51 -0
  8. package/dist/core/errors.js +37 -0
  9. package/dist/core/logger.js +8 -0
  10. package/dist/core/types.js +4 -0
  11. package/dist/dashboard/server.js +191 -0
  12. package/dist/lsp/protocol.js +116 -0
  13. package/dist/main.js +190 -0
  14. package/dist/managers/db-manager.js +161 -0
  15. package/dist/managers/lsp-manager.js +269 -0
  16. package/dist/managers/process-manager.js +140 -0
  17. package/dist/policy/approvals.js +143 -0
  18. package/dist/policy/command-policy.js +99 -0
  19. package/dist/policy/glob-match.js +61 -0
  20. package/dist/policy/path-policy.js +73 -0
  21. package/dist/policy/policy-engine.js +156 -0
  22. package/dist/policy/rate-limiter.js +96 -0
  23. package/dist/policy/risk.js +112 -0
  24. package/dist/policy/secret-policy.js +132 -0
  25. package/dist/server/mcp-server.js +144 -0
  26. package/dist/server/transports/http.js +133 -0
  27. package/dist/server/transports/stdio.js +14 -0
  28. package/dist/tools/adapter-tools.js +62 -0
  29. package/dist/tools/browser-tools.js +76 -0
  30. package/dist/tools/build-tools.js +78 -0
  31. package/dist/tools/code-tools.js +250 -0
  32. package/dist/tools/coverage-tools.js +135 -0
  33. package/dist/tools/db-tools.js +130 -0
  34. package/dist/tools/diff-util.js +45 -0
  35. package/dist/tools/error-parser.js +57 -0
  36. package/dist/tools/file-tools.js +319 -0
  37. package/dist/tools/format-tools.js +118 -0
  38. package/dist/tools/git-tools.js +371 -0
  39. package/dist/tools/index.js +63 -0
  40. package/dist/tools/memory-tools.js +54 -0
  41. package/dist/tools/output-schemas.js +100 -0
  42. package/dist/tools/pagination.js +92 -0
  43. package/dist/tools/pkg-tools.js +260 -0
  44. package/dist/tools/process-tools.js +128 -0
  45. package/dist/tools/registry.js +194 -0
  46. package/dist/tools/schema-lock.js +152 -0
  47. package/dist/tools/search-tools.js +176 -0
  48. package/dist/tools/security-tools.js +147 -0
  49. package/dist/tools/terminal-tools.js +57 -0
  50. package/dist/tools/workspace-tools.js +186 -0
  51. package/dist/workspace/memory-store.js +67 -0
  52. package/dist/workspace/onboarding.js +46 -0
  53. package/dist/workspace/project-detector.js +95 -0
  54. package/dist/workspace/workspace-manager.js +106 -0
  55. package/docs/adapters.md +76 -0
  56. package/docs/architecture.md +66 -0
  57. package/docs/roadmap.md +172 -0
  58. package/docs/security.md +94 -0
  59. package/docs/tools.md +129 -0
  60. package/examples/claude-desktop.json +18 -0
  61. package/examples/codex.toml +18 -0
  62. package/examples/config.basic.yaml +37 -0
  63. package/examples/config.full.yaml +120 -0
  64. package/package.json +74 -0
@@ -0,0 +1,172 @@
1
+ # Roadmap
2
+
3
+ Status of FolderForge toward a stable 1.0.
4
+
5
+ ## Done (0.1)
6
+
7
+ - Core config loader with YAML merge and path normalization.
8
+ - Dependency container and workspace activation.
9
+ - Policy engine: path, command, and secret policies + risk model.
10
+ - Approval queue (once/session scopes).
11
+ - Append-only JSONL audit log + ring buffer.
12
+ - Full native tool catalog (files, search, terminal, processes, git, build,
13
+ code, memory, security, db).
14
+ - Native structural code search (`search_ast`) - regex-backed declaration finder,
15
+ no language server required.
16
+ - Task-preset routing exposed as a tool (`workspace_route`): switch the visible
17
+ tool set to `explore` / `run_ui` / `fix_tests`, or reset to all.
18
+ - MCP server with `tools/list` / `tools/call` handlers.
19
+ - stdio and Streamable HTTP transports.
20
+ - Local dashboard (`/status`, `/audit`, `/processes`, `/approvals`).
21
+ - New `main.ts` entrypoint with arg parsing.
22
+
23
+ ## Done (0.2)
24
+
25
+ - Child-MCP adapters wired end-to-end (Serena, Playwright, Desktop Commander) with tool namespacing (`serena__<tool>`).
26
+ - Persisted approvals across restarts (stored under `.folderforge/approvals.jsonl`).
27
+ - Dashboard auth token for non-loopback binds.
28
+ - Integration tests against the sample fixtures (registry pipeline, policy
29
+ enforcement, and child-MCP adapter discovery via a fake stdio MCP server).
30
+
31
+ ## Done (0.3)
32
+
33
+ - Policy "explain" tool (`policy_explain`): dry-run a call and return the
34
+ decision + reasoning.
35
+ - Streaming tool results for long-running commands: `process_tail` long-polls a
36
+ process session, blocking until new output or exit (backed by
37
+ `ProcessManager.readUntil`).
38
+ - Per-tool rate limits and quotas: sliding-window + rolling daily quota
39
+ (`RateLimiter`), enforced in the tool pipeline and surfaced via
40
+ `policy_ratelimits`; denied/approval-gated calls don't consume quota.
41
+ - Multi-project sessions: activate more than one workspace at once, switch the
42
+ current one (`workspace_list`, `workspace_switch`, `workspace_deactivate`),
43
+ with isolated memory stores per project.
44
+ - Pluggable secret scanners: Shannon-entropy detection flags bespoke
45
+ high-entropy tokens that no regex rule matches (configurable via
46
+ `secretScan`).
47
+
48
+ ## Done (1.0 hardening)
49
+
50
+ - Documented config surface with validation errors (`validateConfig` throws a
51
+ single aggregated, human-readable error).
52
+ - Hardened HTTP transport: bearer-token auth (constant-time), CORS allowlist +
53
+ preflight, and idle session expiry (`sessionTtlMs`).
54
+
55
+ ## Done (1.0)
56
+
57
+ - Frozen tool schema: the public native tool surface (names + `mutates`/`risk`
58
+ contract) is locked in `src/tools/schema-lock.ts`. A guard test
59
+ (`tests/unit/schema-lock.test.ts`) fails CI if the live registry diverges, so
60
+ accidental renames, removals, or risk reclassifications are caught before
61
+ release. Renaming/removing a tool is now an explicit, major-version change.
62
+ - Full policy-pipeline coverage: `tests/unit/policy-pipeline.test.ts` exercises
63
+ the end-to-end `registry.call()` path through all four modes (readonly / safe
64
+ / dev / danger) - risk classification, mode gating, approval creation,
65
+ once-vs-session scope, the no-quota-on-denied/gated-calls guarantee, and audit
66
+ event recording - composed with the existing per-policy unit suites.
67
+
68
+ ## 1.0 criteria
69
+
70
+ - [x] Documented config surface with validation errors.
71
+ - [x] Hardened HTTP transport (auth, CORS, session expiry).
72
+ - [x] Stable tool schema (no breaking renames) - frozen in
73
+ `src/tools/schema-lock.ts` and CI-guarded.
74
+ - [x] Full unit + integration coverage for the policy pipeline - per-policy unit
75
+ suites (rate limiter, entropy scanner, config validation, HTTP hardening,
76
+ command/path/secret policy) plus an end-to-end pipeline suite and multi-project
77
+ flows.
78
+
79
+ **1.0 is complete: all four release criteria are met.**
80
+
81
+ ## Done (1.2 - MCP protocol features)
82
+
83
+ These extend the server's MCP conformance beyond `tools/list` + `tools/call`.
84
+ They are wired through a single per-call `ToolCallControl` object
85
+ (`src/core/types.ts`) injected by the `tools/call` request handler
86
+ (`src/server/mcp-server.ts`) and threaded into every tool via `ToolContext.control`.
87
+ This adds **zero** new entries to the frozen tool surface, so the schema-lock is
88
+ untouched.
89
+
90
+ - **P4 - progress notifications.** When the client sends a `progressToken` in
91
+ the request `_meta`, `control.reportProgress(progress, total?, message?)`
92
+ emits `notifications/progress`. Consumers: `process_tail` reports a tick each
93
+ long-poll cycle (cursor as progress, status as message), and `git_push`
94
+ brackets the network call with a start/complete tick. Handlers without a token
95
+ see `reportProgress === undefined` and no-op.
96
+ - **P6 - cancellation.** `control.signal` mirrors the SDK's per-request
97
+ `AbortSignal` (aborted on `notifications/cancelled`). `registry.call()`
98
+ refuses pre-cancelled calls early; `ProcessManager.readUntil(signal)` wakes
99
+ immediately on abort instead of blocking out the full `timeoutMs`, so a
100
+ cancelled tail returns at once with `cancelled: true`.
101
+ - **P8 - elicitation.** `control.elicitInput(params)` is present only when the
102
+ client advertised the `elicitation` capability (checked via
103
+ `server.getClientCapabilities()`); otherwise it is `undefined` and handlers
104
+ fall back to non-interactive defaults. Two destructive native tools now elicit
105
+ an interactive confirmation before acting: `git_reset` (unstaging),
106
+ `git_push` (publishing commits to a shared remote), and `git_pull` (integrating
107
+ remote changes into the working tree). Clients without the
108
+ capability proceed non-interactively, still gated by policy/approval upstream.
109
+
110
+ Verification status: typechecked logic reviewed manually; unit tests cover
111
+ control propagation + early-cancel + progress emit
112
+ (`tests/unit/tool-control.test.ts`) and signal-driven wakeup
113
+ (`tests/unit/process-stream.test.ts`); integration tests cover the `git_reset`
114
+ and `git_push` elicitation accept/decline/no-capability paths end-to-end against
115
+ throwaway repos (`tests/integration/git-ops.test.ts`). Run
116
+ `npm run typecheck && npm test` in the repo (with `node_modules` installed)
117
+ before tagging 1.2.
118
+
119
+ ## Housekeeping
120
+
121
+ - Removed stale pre-rename artifacts from the working tree (legacy "vibemcp"
122
+ naming). The leftover approval log was renamed
123
+ `.trash/vibemcp-approvals.jsonl.removed` -> `.trash/legacy-approvals.removed`.
124
+ Both `.trash/` and `**/.vibemcp/` are already gitignored (never committed).
125
+ - Still pending a manual delete (the empty fixture dir cannot be removed via the
126
+ filesystem tooling): run
127
+ `rm -rf .trash tests/fixtures/sample-ts-project/.vibemcp`.
128
+
129
+ ## Next (post-1.0 ideas)
130
+
131
+ - Distributed/shared rate limiting for multi-instance deployments.
132
+ - Streaming over the MCP transport itself (incremental tool results) once the
133
+ protocol stabilizes that path.
134
+ - Expanded file/git/db integration tests (Q8) - broaden coverage beyond the
135
+ current unit suites to full `registry.call()` flows against the sample
136
+ fixtures.
137
+ - Wire P8 elicitation into a real consumer (interactive confirmation for
138
+ destructive db/git operations). **Done in 1.2** for `git_reset` and
139
+ `git_push`; db tools remain read-only so there is no destructive db consumer
140
+ to wire.
141
+
142
+ ## Done (1.2 - agent ergonomics)
143
+
144
+ Rounded out the tool surface so an agent can comfortably explore, edit, run, and
145
+ manage source control without falling back to raw `shell_exec`. All additions are
146
+ backwards-compatible (new tools only) and synchronized across the risk map
147
+ (`src/policy/risk.ts`), the frozen schema lock (`src/tools/schema-lock.ts`), and
148
+ the integration suites.
149
+
150
+ - **Git convenience tools.**
151
+ - `git_fetch` (MEDIUM, `openWorldHint`) - update remote-tracking refs only,
152
+ never touches the working tree; emits progress.
153
+ - `git_pull` (HIGH, `openWorldHint`) - merge or `--rebase` remote changes into
154
+ the current branch, with an elicitation confirmation (warns on a dirty tree)
155
+ and progress reporting.
156
+ - `git_stash` (MEDIUM) - `op`: `push` (default) | `pop` | `apply` | `list` |
157
+ `drop`. Deliberately omits `clear` to avoid irreversible data loss.
158
+ - **File convenience tools.**
159
+ - `file_move` (MEDIUM) - rename/relocate a file or directory; both endpoints
160
+ boundary-checked, refuses to clobber unless `overwrite=true`.
161
+ - `file_copy` (MEDIUM) - copy a file or directory (recursive); same overwrite
162
+ guard.
163
+ - `list_directory` (LOW) - enumerate a directory (optional recursion + entry
164
+ cap), skipping anything the path policy denies (secrets, `node_modules`,
165
+ `.git` internals).
166
+
167
+ Verification: `npm run typecheck && npm test && npm run build` all green
168
+ (26 test files, 215 tests). New behavior is covered in
169
+ `tests/integration/file-ops.test.ts` (list flat/recursive, move + overwrite +
170
+ escape guard, file/dir copy) and `tests/integration/git-ops.test.ts` (stash
171
+ push/list/pop, fetch+pull against a bare remote, pull cancellation on declined
172
+ elicitation).
@@ -0,0 +1,94 @@
1
+ # Security
2
+
3
+ FolderForge assumes the agent is capable but not fully trusted. Security is
4
+ enforced server-side; the agent can request anything, but the policy engine
5
+ decides.
6
+
7
+ ## Policy modes
8
+
9
+ Set via `policy.defaultMode` or the `policy_set_mode` tool.
10
+
11
+ | Mode | Mutations | HIGH risk | CRITICAL |
12
+ | --- | --- | --- | --- |
13
+ | `readonly` | denied | denied | denied |
14
+ | `safe` | allowed (LOW/MEDIUM) | approval | denied |
15
+ | `dev` | allowed | approval | denied |
16
+ | `danger` | allowed | approval | approval |
17
+
18
+ The decision logic lives in `PolicyEngine.evaluate` (`src/policy/policy-engine.ts`).
19
+ Use the `policy_explain` tool to dry-run any call and see the decision
20
+ (`allow`/`deny`/`approval`) and contributing factors **without** executing it or
21
+ creating an approval request (backed by `PolicyEngine.explain`).
22
+
23
+ ## Path policy
24
+
25
+ `src/policy/path-policy.ts` guarantees that every file path:
26
+
27
+ 1. resolves **inside** an allowed directory (`workspace.allowedDirectories`);
28
+ 2. is **not** matched by a denied glob (`workspace.deniedGlobs`, e.g. `**/.env`,
29
+ `**/*.pem`, `**/node_modules/**`);
30
+ 3. does **not** escape via symlink (the nearest existing ancestor is
31
+ `realpath`-resolved and re-checked);
32
+ 4. does not touch protected credential folders (`~/.ssh`, `~/.aws`, `~/.gnupg`,
33
+ `~/.config/gcloud`, `~/.kube`).
34
+
35
+ Violations throw `PathEscapeError` and surface as a structured tool error.
36
+
37
+ ## Command policy
38
+
39
+ `src/policy/command-policy.ts` classifies shell commands:
40
+
41
+ - **CRITICAL** (always blocked): `rm -rf /`, `sudo`, `mkfs`, `dd if=`,
42
+ `chmod -R 777 /`, `curl ... | bash`, `git reset --hard`, `git push --force`,
43
+ fork bombs, `docker system prune`, `kubectl delete`, `terraform apply`, ...
44
+ - **HIGH** (approval): `git push`, `git reset`, `docker rm`, `npm publish`,
45
+ `rm -rf ...`.
46
+ - **MEDIUM** (allowed, audited): package installs, `docker compose up`, builds.
47
+ - **LOW**: everything else.
48
+
49
+ Config `policy.blockedCommands` adds project-specific substring/wildcard rules
50
+ on top of the built-in regex set.
51
+
52
+ ## Secret policy
53
+
54
+ `src/policy/secret-policy.ts` detects and redacts common credentials (OpenAI,
55
+ Anthropic, AWS, GitHub, Google, Slack tokens, private-key blocks, generic
56
+ `key=value` secrets). It powers:
57
+
58
+ - `secret_scan` for explicit scans;
59
+ - terminal env redaction when `terminal.envPolicy: redact`;
60
+ - output redaction before content leaves the server.
61
+
62
+ ## Approvals
63
+
64
+ HIGH/CRITICAL (and any tool in `policy.requireApproval`) create a pending
65
+ `ApprovalRequest` (`src/policy/approvals.ts`). Resolve them in the dashboard
66
+ (`POST /approvals/:id/approve|deny`) or via approval tools. `session`-scoped
67
+ approvals remember the tool for the rest of the session.
68
+
69
+ Approvals are **persisted across restarts**: every create/approve/deny is
70
+ appended to `<project>/.vibemcp/approvals.jsonl` (append-only, compacted on
71
+ load). Pending and resolved requests survive a restart so the dashboard history
72
+ stays intact. Session-scoped allowances are **not** re-armed automatically - a
73
+ fresh process starts a fresh session, so a session approval from a previous run
74
+ must be granted again.
75
+
76
+ ## Dashboard auth
77
+
78
+ The dashboard (`src/dashboard/server.ts`) is unauthenticated when bound to a
79
+ loopback host (`127.0.0.1`, `::1`, `localhost`), since that is same-machine
80
+ only. When bound to any **non-loopback** address it **requires a bearer token**:
81
+
82
+ - Set it explicitly via `server.dashboard.token`, or
83
+ - leave it unset and FolderForge generates one at startup and logs it once.
84
+
85
+ Clients authenticate with `Authorization: Bearer <token>` or a `?token=<token>`
86
+ query parameter; the comparison is constant-time. Missing/invalid tokens get a
87
+ `401` with a `WWW-Authenticate: Bearer` header. Binding to a non-loopback host
88
+ with no token available is a startup error.
89
+
90
+ ## Audit
91
+
92
+ Every call, denial, and approval is appended to
93
+ `<project>/.folderforge/audit/audit.jsonl` and kept in a 500-entry ring buffer
94
+ for `audit_recent` and the dashboard `/audit` endpoint.
package/docs/tools.md ADDED
@@ -0,0 +1,129 @@
1
+ # Tools
2
+
3
+ Tools are registered by group in `src/tools/index.ts` and executed through
4
+ `ToolRegistry.call`, which classifies risk, consults the `PolicyEngine`, and
5
+ records audit events. Each tool declares a default risk level in
6
+ `src/policy/risk.ts` (`TOOL_RISK`).
7
+
8
+ ## Risk levels
9
+
10
+ | Level | Meaning | Behavior |
11
+ | --- | --- | --- |
12
+ | `LOW` | Read-only / safe | Always allowed (except readonly blocks mutations) |
13
+ | `MEDIUM` | Local mutation | Allowed in `safe`/`dev`/`danger`, audited |
14
+ | `HIGH` | Sensitive mutation | Requires approval |
15
+ | `CRITICAL` | Destructive | Denied unless `danger` mode + approval |
16
+
17
+ `shell_exec` is re-classified per command at call time by `CommandPolicy`.
18
+
19
+ ## Schema lock
20
+
21
+ The public native tool surface is frozen in `src/tools/schema-lock.ts`
22
+ (`FROZEN_TOOLS`), which is the **source of truth** for tool names and their
23
+ `mutates` / `risk` contract at 1.0. Renaming a tool, removing one, or changing
24
+ its mutation/risk classification is a **breaking change**: it requires a
25
+ major-version bump and a deliberate edit to that file. Adding a brand-new tool is
26
+ backwards-compatible - register it, then add an entry to the lock.
27
+
28
+ The guard test `tests/unit/schema-lock.test.ts` fails in CI if the live registry
29
+ and the lock ever diverge, so accidental renames or removals are caught before
30
+ release. A couple of entries are frozen at their *actual* runtime risk rather
31
+ than a tidier value (e.g. `audit_export` and `approval_request` fall back to the
32
+ `defineTool` default of `MEDIUM` because they are absent from `TOOL_RISK`);
33
+ reclassifying them is a separate, intentional change. Adapter (child-MCP) tools
34
+ are namespaced and discovered dynamically, so they are **not** part of the frozen
35
+ surface.
36
+
37
+ ### `parse_errors` (internal but registered)
38
+
39
+ `parse_errors` is an **internal helper** used by the build/quality tooling, not a
40
+ tool intended for direct day-to-day use. It nonetheless lives in the native
41
+ registry, so it shows up in `tools/list` and is frozen in the schema lock
42
+ (`mutates: false`, `risk: MEDIUM`). This is intentional: the schema-lock guard is
43
+ deliberately strict and freezes the *entire* live catalog so CI catches any
44
+ accidental drift. Don't be surprised to see `parse_errors` in the tool list -
45
+ it's expected, and removing or hiding it would be a lock change like any other.
46
+
47
+ ## Groups
48
+
49
+ ### Workspace
50
+ `workspace_status`, `workspace_activate`, `workspace_onboard`, `workspace_health`,
51
+ `workspace_route`, `project_detect_commands` - activate and inspect the active
52
+ project. `workspace_route` switches the visible tool set to a task preset
53
+ (`explore`, `run_ui`, `fix_tests`) or resets to all.
54
+
55
+ ### Files
56
+ `file_read`, `file_read_many`, `file_write`, `file_patch`, `file_edit_block`,
57
+ `file_move`, `file_copy`, `list_directory`, `file_delete` - all paths pass
58
+ through `PathPolicy.resolveSafe` (workspace boundary, denied globs, symlink-escape
59
+ checks). Mutations return a diff preview where applicable. `file_move` renames or
60
+ relocates a file/directory and `file_copy` copies one (recursively for
61
+ directories); both are boundary-checked on *both* endpoints and refuse to clobber
62
+ an existing destination unless `overwrite=true`. `list_directory` enumerates a
63
+ directory (optionally recursive, with an entry cap) and skips anything the path
64
+ policy denies, so secrets, `node_modules`, and `.git` internals never leak.
65
+
66
+ ### Search
67
+ `search_files`, `search_text`, `search_ast` - glob, content, and structural
68
+ declaration search honoring denied globs and ignore files. `search_ast` finds
69
+ functions/classes/methods/interfaces/types/consts by name via lightweight,
70
+ regex-backed structural matching (no language server required).
71
+
72
+ ### Terminal & processes
73
+ `shell_exec` (one-shot, risk-classified), and the process manager tools
74
+ `process_start`, `process_read`, `process_write`, `process_stop`,
75
+ `process_kill`, `process_list` for long-running dev servers.
76
+
77
+ ### Git
78
+ `git_status`, `git_diff`, `git_log`, `git_show`, `git_blame`, `git_branch`,
79
+ `git_add`, `git_checkout`, `git_commit`, `git_push`, `git_reset`, `git_fetch`,
80
+ `git_pull`, `git_stash`. Commit/push default to approval; `git_reset --hard` is
81
+ CRITICAL. `git_fetch` (MEDIUM) updates remote-tracking refs only and never
82
+ touches the working tree. `git_pull` (HIGH) integrates remote changes into the
83
+ current branch (merge or `--rebase`) and confirms interactively via elicitation
84
+ before running, warning when the working tree is dirty. `git_stash` (MEDIUM)
85
+ shelves and restores work via `op`: `push` (default) | `pop` | `apply` | `list` |
86
+ `drop`; it deliberately omits `clear` to avoid irreversible data loss.
87
+
88
+ ### Build & quality
89
+ `run_build`, `run_test`, `run_lint`, `run_typecheck`, `code_diagnostics` -
90
+ output is run through `src/tools/error-parser.ts` for structured diagnostics.
91
+
92
+ ### Code intelligence
93
+ `code_symbols_overview`, `code_find_symbol`, `code_find_references`,
94
+ `code_find_definition`, `code_find_implementations`, and symbol-level edits
95
+ (`code_replace_symbol_body`, `code_insert_before_symbol`, etc.).
96
+
97
+ ### Memory
98
+ `memory_list`, `memory_read`, `memory_write`, `memory_update` - per-project
99
+ persistent notes stored under `.folderforge/`.
100
+
101
+ ### Security
102
+ `secret_scan` - scans content/diffs for credential patterns
103
+ (`src/policy/secret-policy.ts`).
104
+
105
+ ### Policy & audit
106
+ `policy_get`, `policy_set_mode` - read or change the active policy mode
107
+ (`readonly`/`safe`/`dev`/`danger`). `policy_explain` - dry-run a tool call and
108
+ return the decision (`allow`/`deny`/`approval`) plus the contributing factors,
109
+ without executing the tool or creating an approval request. `audit_recent`,
110
+ `audit_export` - inspect or export the append-only audit trail.
111
+
112
+ ### Approvals
113
+ `approval_status`, `approval_request` - inspect pending approval requests created
114
+ by the engine, or raise one explicitly.
115
+
116
+ ### Browser & DB
117
+ Child-MCP adapter tools are exposed namespaced as `<adapter>__<tool>` (e.g.
118
+ `playwright__browser_navigate`, `serena__find_symbol`) - see `docs/adapters.md`.
119
+ `db_*` tools (`db_connect`, `db_list_connections`, `db_list_tables`,
120
+ `db_describe_table`, `db_query_readonly`, `db_explain`) are native. Read-only
121
+ queries are LOW; writes/migrations are HIGH.
122
+
123
+ ## Task presets
124
+
125
+ `src/tools/index.ts` exports `TASK_PRESETS` (`explore`, `run_ui`, `fix_tests`).
126
+ The `workspace_route` tool exposes this at runtime: calling it with a preset name
127
+ runs `registry.setActive(TASK_PRESETS[name])` so `tools/list` returns only that
128
+ focused subset; `workspace_route` with `reset: true` (or `preset: "all"`) restores
129
+ the full catalog.
@@ -0,0 +1,18 @@
1
+ {
2
+ "mcpServers": {
3
+ "folderforge": {
4
+ "command": "node",
5
+ "args": [
6
+ "/home/devops/FolderForge/dist/main.js",
7
+ "--stdio",
8
+ "--project",
9
+ "/home/devops/FolderForge",
10
+ "--config",
11
+ "/home/devops/FolderForge/examples/config.basic.yaml"
12
+ ],
13
+ "env": {
14
+ "FOLDERFORGE_LOG_LEVEL": "info"
15
+ }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ # Codex CLI MCP server configuration for FolderForge.
2
+ #
3
+ # Place this in ~/.codex/config.toml (or merge the [mcp_servers] block).
4
+ # Codex launches the server over stdio.
5
+
6
+ [mcp_servers.folderforge]
7
+ command = "node"
8
+ args = [
9
+ "/home/devops/FolderForge/dist/main.js",
10
+ "--stdio",
11
+ "--project",
12
+ "/home/devops/FolderForge",
13
+ "--config",
14
+ "/home/devops/FolderForge/examples/config.basic.yaml",
15
+ ]
16
+
17
+ [mcp_servers.folderforge.env]
18
+ FOLDERFORGE_LOG_LEVEL = "info"
@@ -0,0 +1,37 @@
1
+ # FolderForge - basic example config
2
+ #
3
+ # Minimal setup: one project, safe mode, stdio transport.
4
+ # Copy to your project root as `folderforge.yaml` (or pass via --config).
5
+
6
+ server:
7
+ name: folderforge
8
+ transport: stdio
9
+ http:
10
+ host: 127.0.0.1
11
+ port: 7331
12
+ dashboard:
13
+ host: 127.0.0.1
14
+ port: 7332
15
+ # Optional: required when binding dashboard to a non-loopback host.
16
+ # token: "put-a-long-random-string-here"
17
+
18
+ workspace:
19
+ defaultProject: /home/devops/FolderForge
20
+ allowedDirectories:
21
+ - /home/devops/FolderForge
22
+ deniedGlobs:
23
+ - "**/.env"
24
+ - "**/.env.*"
25
+ - "**/*.pem"
26
+ - "**/*.key"
27
+ - "**/node_modules/**"
28
+
29
+ policy:
30
+ defaultMode: safe
31
+ requireApproval:
32
+ - git_commit
33
+ - git_push
34
+ - file_delete
35
+ blockedCommands:
36
+ - "rm -rf /"
37
+ - "git push --force"
@@ -0,0 +1,120 @@
1
+ # FolderForge - full example config
2
+ #
3
+ # Exercises every configurable surface: HTTP transport, dev mode, git policy,
4
+ # terminal sandboxing, persisted approvals, and child-MCP adapters (Serena / Playwright / Desktop Commander).
5
+
6
+ server:
7
+ name: folderforge
8
+ transport: http
9
+ http:
10
+ host: 127.0.0.1
11
+ port: 7331
12
+ # Bearer token for the MCP HTTP endpoint. Required for non-loopback binds
13
+ # (auto-generated and logged once if omitted). Send as `Authorization: Bearer <token>`.
14
+ # token: "put-a-long-random-string-here"
15
+ # CORS allowlist. Use ["*"] to allow any origin; omit/empty to disable CORS.
16
+ # corsOrigins:
17
+ # - https://your-tool.example.com
18
+ # Idle session lifetime (ms) before the HTTP MCP session is rotated/expired.
19
+ sessionTtlMs: 1800000
20
+ dashboard:
21
+ host: 127.0.0.1
22
+ port: 7332
23
+ # Optional: required when binding dashboard to a non-loopback host.
24
+ # Requests must send `Authorization: Bearer <token>` or add `?token=<token>`.
25
+ # token: "put-a-long-random-string-here"
26
+
27
+ workspace:
28
+ defaultProject: /home/devops/FolderForge
29
+ allowedDirectories:
30
+ - /home/devops/FolderForge
31
+ - /home/devops/FolderForge/tests/fixtures
32
+ deniedGlobs:
33
+ - "**/.env"
34
+ - "**/.env.*"
35
+ - "**/id_rsa"
36
+ - "**/id_ed25519"
37
+ - "**/*.pem"
38
+ - "**/*.key"
39
+ - "**/node_modules/**"
40
+ - "**/.git/objects/**"
41
+
42
+ policy:
43
+ # readonly | safe | dev | danger
44
+ defaultMode: dev
45
+ requireApproval:
46
+ - git_push
47
+ - git_commit
48
+ - file_delete
49
+ - db_write
50
+ - shell_high_risk
51
+ - docker_prune
52
+ blockedCommands:
53
+ - "rm -rf /"
54
+ - "sudo rm"
55
+ - "mkfs"
56
+ - "dd if="
57
+ - "chmod -R 777 /"
58
+ - "curl * | bash"
59
+ - "wget * | sh"
60
+ - "git reset --hard"
61
+ - "git push --force"
62
+ - "docker system prune"
63
+ - "kubectl delete"
64
+ - "terraform apply"
65
+
66
+ terminal:
67
+ shell: /bin/bash
68
+ defaultTimeoutMs: 120000
69
+ maxOutputBytes: 200000
70
+ # redact | passthrough
71
+ envPolicy: redact
72
+
73
+ git:
74
+ # approval | allow | deny
75
+ allowCommit: approval
76
+ allowPush: approval
77
+ allowResetHard: false
78
+
79
+ # Per-tool rate limiting and quotas. Sliding window (maxCalls / windowMs) plus an
80
+ # optional rolling 24h dailyQuota. Denied or approval-gated calls don't consume quota.
81
+ rateLimit:
82
+ enabled: true
83
+ default:
84
+ maxCalls: 60
85
+ windowMs: 10000
86
+ overrides:
87
+ shell_exec:
88
+ maxCalls: 20
89
+ windowMs: 10000
90
+ dailyQuota: 1000
91
+ git_push:
92
+ maxCalls: 5
93
+ windowMs: 60000
94
+ dailyQuota: 50
95
+
96
+ # Secret scanning. Beyond the built-in regex rules, entropy detection flags
97
+ # bespoke high-entropy tokens (minEntropy is bits/char; minLength is the
98
+ # shortest token considered).
99
+ secretScan:
100
+ entropyEnabled: true
101
+ minEntropy: 4.0
102
+ minLength: 20
103
+
104
+ adapters:
105
+ serena:
106
+ enabled: false
107
+ command: serena
108
+ args: []
109
+ playwright:
110
+ enabled: true
111
+ command: npx
112
+ args:
113
+ - "-y"
114
+ - "@playwright/mcp@latest"
115
+ desktopCommander:
116
+ enabled: false
117
+ command: npx
118
+ args:
119
+ - "-y"
120
+ - "@wonderwhy-er/desktop-commander@latest"
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@musashishao/folderforge",
3
+ "version": "1.2.0",
4
+ "description": "FolderForge - the all-in-one MCP-native local development control plane for AI coding agents.",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "ai-agents",
9
+ "coding-agent",
10
+ "claude",
11
+ "cursor",
12
+ "codex",
13
+ "developer-tools",
14
+ "workspace",
15
+ "filesystem",
16
+ "stdio",
17
+ "cli"
18
+ ],
19
+ "homepage": "https://github.com/roronoazoroshao369/FolderForge#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/roronoazoroshao369/FolderForge/issues"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/roronoazoroshao369/FolderForge.git"
26
+ },
27
+ "license": "Apache-2.0",
28
+ "author": "",
29
+ "type": "module",
30
+ "bin": {
31
+ "folderforge": "./dist/main.js"
32
+ },
33
+ "main": "./dist/main.js",
34
+ "files": [
35
+ "dist",
36
+ "examples",
37
+ "docs",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "engines": {
42
+ "node": ">=22.0.0"
43
+ },
44
+ "scripts": {
45
+ "dev": "tsx src/main.ts",
46
+ "build": "tsc -p tsconfig.json",
47
+ "clean": "rm -rf dist",
48
+ "test": "vitest run",
49
+ "test:watch": "vitest",
50
+ "start": "node dist/main.js",
51
+ "typecheck": "tsc -p tsconfig.json --noEmit",
52
+ "lint": "tsc -p tsconfig.json --noEmit",
53
+ "prepublishOnly": "npm run clean && npm run build && npm test"
54
+ },
55
+ "dependencies": {
56
+ "@modelcontextprotocol/sdk": "^1.0.0",
57
+ "execa": "^9.0.0",
58
+ "fast-glob": "^3.3.0",
59
+ "ignore": "^6.0.0",
60
+ "pino": "^9.0.0",
61
+ "simple-git": "^3.25.0",
62
+ "yaml": "^2.5.0",
63
+ "zod": "^3.23.0"
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^22.0.0",
67
+ "tsx": "^4.19.0",
68
+ "typescript": "^5.6.0",
69
+ "vitest": "^2.0.0"
70
+ },
71
+ "publishConfig": {
72
+ "access": "public"
73
+ }
74
+ }