@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.
- package/README.md +181 -0
- package/dist/adapters/child-mcp/client.js +114 -0
- package/dist/adapters/child-mcp/registry.js +66 -0
- package/dist/audit/audit-log.js +45 -0
- package/dist/audit/event-types.js +1 -0
- package/dist/core/config.js +211 -0
- package/dist/core/container.js +51 -0
- package/dist/core/errors.js +37 -0
- package/dist/core/logger.js +8 -0
- package/dist/core/types.js +4 -0
- package/dist/dashboard/server.js +191 -0
- package/dist/lsp/protocol.js +116 -0
- package/dist/main.js +190 -0
- package/dist/managers/db-manager.js +161 -0
- package/dist/managers/lsp-manager.js +269 -0
- package/dist/managers/process-manager.js +140 -0
- package/dist/policy/approvals.js +143 -0
- package/dist/policy/command-policy.js +99 -0
- package/dist/policy/glob-match.js +61 -0
- package/dist/policy/path-policy.js +73 -0
- package/dist/policy/policy-engine.js +156 -0
- package/dist/policy/rate-limiter.js +96 -0
- package/dist/policy/risk.js +112 -0
- package/dist/policy/secret-policy.js +132 -0
- package/dist/server/mcp-server.js +144 -0
- package/dist/server/transports/http.js +133 -0
- package/dist/server/transports/stdio.js +14 -0
- package/dist/tools/adapter-tools.js +62 -0
- package/dist/tools/browser-tools.js +76 -0
- package/dist/tools/build-tools.js +78 -0
- package/dist/tools/code-tools.js +250 -0
- package/dist/tools/coverage-tools.js +135 -0
- package/dist/tools/db-tools.js +130 -0
- package/dist/tools/diff-util.js +45 -0
- package/dist/tools/error-parser.js +57 -0
- package/dist/tools/file-tools.js +319 -0
- package/dist/tools/format-tools.js +118 -0
- package/dist/tools/git-tools.js +371 -0
- package/dist/tools/index.js +63 -0
- package/dist/tools/memory-tools.js +54 -0
- package/dist/tools/output-schemas.js +100 -0
- package/dist/tools/pagination.js +92 -0
- package/dist/tools/pkg-tools.js +260 -0
- package/dist/tools/process-tools.js +128 -0
- package/dist/tools/registry.js +194 -0
- package/dist/tools/schema-lock.js +152 -0
- package/dist/tools/search-tools.js +176 -0
- package/dist/tools/security-tools.js +147 -0
- package/dist/tools/terminal-tools.js +57 -0
- package/dist/tools/workspace-tools.js +186 -0
- package/dist/workspace/memory-store.js +67 -0
- package/dist/workspace/onboarding.js +46 -0
- package/dist/workspace/project-detector.js +95 -0
- package/dist/workspace/workspace-manager.js +106 -0
- package/docs/adapters.md +76 -0
- package/docs/architecture.md +66 -0
- package/docs/roadmap.md +172 -0
- package/docs/security.md +94 -0
- package/docs/tools.md +129 -0
- package/examples/claude-desktop.json +18 -0
- package/examples/codex.toml +18 -0
- package/examples/config.basic.yaml +37 -0
- package/examples/config.full.yaml +120 -0
- package/package.json +74 -0
package/docs/roadmap.md
ADDED
|
@@ -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).
|
package/docs/security.md
ADDED
|
@@ -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
|
+
}
|