forgetrail 0.5.2 → 0.5.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.
- package/README.md +4 -3
- package/content/FORGETRAIL_LITE.md +4 -4
- package/docs/NPM.md +7 -7
- package/package.json +1 -1
- package/scripts/install.mjs +9 -1
- package/scripts/mcp-lib.mjs +38 -10
- package/scripts/mcp-status.mjs +7 -0
- package/scripts/tracking-cutover.test.mjs +26 -1
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
ForgeTrail gives your next coding session a place to start. It keeps the phase, decisions, and handoff in your repository so an agent can read them when you resume. Start with Lite for a small project. You do not have to run all seven phases to try the method.
|
|
14
14
|
|
|
15
|
-
ForgeTrail instructs the agent to read
|
|
15
|
+
ForgeTrail instructs the agent to read the ledger, preserve approved decisions, and pause at approval gates. The agent must write the handoff. Those updates are not automatic. Optional hooks enforce the checks documented for their supported host.
|
|
16
16
|
|
|
17
|
-
In session one, the agent drafts a Phase 1 brief, you approve it, and the agent logs the stack decision and a note for next time. In session two, a fresh chat reads that record, skips the settled questions, finishes the open Phase 1 item, and asks to move into Phase 2 with that phase's guidance. The record is
|
|
17
|
+
In session one, the agent drafts a Phase 1 brief, you approve it, and the agent logs the stack decision and a note for next time. In session two, a fresh chat reads that record, skips the settled questions, finishes the open Phase 1 item, and asks to move into Phase 2 with that phase's guidance. The record is the [AppLedger](https://appledger.dev) ledger in `appledger/`: the phase in `profiles/forgetrail.yaml`, plus decision, lesson, and session records. `pnpm dlx appledger init` creates it. Labeled walk-through: [`content/examples/two-session-continuity.md`](content/examples/two-session-continuity.md).
|
|
18
18
|
|
|
19
19
|
**Docs:** [forgetrail.dev/docs](https://forgetrail.dev/docs) · **Site:** [forgetrail.dev](https://forgetrail.dev)
|
|
20
20
|
|
|
@@ -38,9 +38,10 @@ The shortest supported first task is: create `appledger/`, draft `docs/PHASE_1_B
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
pnpm dlx forgetrail install --lite --with-genesis-stub
|
|
41
|
+
pnpm dlx appledger init --name "Your app name"
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
MCP: `npx -y forgetrail-mcp`
|
|
44
|
+
MCP: `npx -y forgetrail-mcp` (0.4.2 or later finds the methodology without `FORGETRAIL_ROOT`). Prefer `pnpm dlx` on Windows. Do not add `forgetrail` to an app's `dependencies`. Do not merge the two packages.
|
|
44
45
|
|
|
45
46
|
## What you get
|
|
46
47
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ForgeTrail Lite — portable kickoff for any agentic chat
|
|
2
2
|
|
|
3
|
-
> **ForgeTrail Lite v2.2.
|
|
3
|
+
> **ForgeTrail Lite v2.2.1**
|
|
4
4
|
> © Catalyst Forge, LLC — [www.catalystforge.com](https://www.catalystforge.com)
|
|
5
5
|
> Part of the **ForgeTrail** open-source methodology ([Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) in the upstream ForgeTrail repo).
|
|
6
6
|
>
|
|
@@ -320,7 +320,7 @@ Record anything non-obvious as a lesson in **`appledger/`** (for example, Playwr
|
|
|
320
320
|
2. **`.forgetrail/cursor/rules/forgetrail-updates-log.mdc`** — use the §12.5 snippet verbatim. **Symlink or copy** into `.cursor/rules/` so Cursor reminds agents when to update `FORGETRAIL_LITE_UPDATES.md` (§1.6). Optional: copy the upstream **`FORGETRAIL_LITE_UPDATES.md`** starter into `.forgetrail/` when you expect protocol feedback during the project.
|
|
321
321
|
3. **`.forgetrail/hooks/` and `.cursor/hooks.json`** — install host safety hooks (`content/hooks/`) into `.forgetrail/hooks/` and copy `cursor-hooks.json` to `.cursor/hooks.json`. On Cursor, this runs pre-commit verification, enforces pnpm lock consistency, gates git push at the tool level, and injects live phase context at session start. For Claude Code, add `claude-settings-hooks.json` into `.claude/settings.json`.
|
|
322
322
|
If any of these already exists and its content conflicts with the Lite defaults, **do not overwrite** — flag the conflict to the user and ask how to reconcile. Record the reconciliation as a decision in `appledger/`.
|
|
323
|
-
4. **Create `appledger/`** if it does not exist
|
|
323
|
+
4. **Create `appledger/`** if it does not exist. Run `pnpm dlx appledger init --name "<application name>"` (or `appledger init` when it is installed globally), then `pnpm dlx appledger check`. Init writes `manifest.yaml`, `profiles/forgetrail.yaml` with the `plan` phase `in_progress`, an application record, and a session record. It does not overwrite existing files. Init leaves the purpose as "Not supplied." Write the one-line purpose into the application record from what the user has already said, then run `check` again. Do **not** create `.forgetrail/workflow_tracking.json`. Criteria stay `pending` until evidence exists. **Without Node:** write the same four files by hand in the shape of the [minimal example ledger](https://github.com/Catalyst-Forge-LLC/appledger/tree/main/examples/minimal/appledger), and run `appledger check` once Node is available. A hand-written ledger is not checked until then.
|
|
324
324
|
5. **If git was initialized in step 2**, make the first commit now so the user has a clean baseline. **What lands in the commit depends on §1.5:** if **committing `.forgetrail/`**, steps 3–4 artifacts are included; if **gitignoring `.forgetrail/`**, only `.gitignore` (and any `.cursor/rules/` copies) — the workspace stays local-only and that is expected, not a mistake. Example: `git add -A && git commit -m "chore: ForgeTrail Lite bootstrap"`. Skip this step if the repo already had history — do not squash or amend what's there. Skip entirely if the user is in no-git mode (§4.1).
|
|
325
325
|
6. **Ask the §5 intake questions.** Do not write any project code yet. For the first user-facing reply, follow §9 (plain product language, one clear "reply with," no methodology jargon).
|
|
326
326
|
7. **Create `docs/`** (if missing) and **draft `docs/PHASE_1_BRIEF.md`** from the §6 template using the user's answers. Show it to the user, iterate, then **lock it**: mark the brief criteria met in `appledger/profiles/forgetrail.yaml` only when the user has approved them, and record major commitments as decision records.
|
|
@@ -1003,7 +1003,7 @@ Save this as `.forgetrail/AGENTS.md` so agents that auto-load it (Codex, Cursor,
|
|
|
1003
1003
|
|
|
1004
1004
|
```markdown
|
|
1005
1005
|
<!--
|
|
1006
|
-
Agent protocol based on ForgeTrail Lite v2.2.
|
|
1006
|
+
Agent protocol based on ForgeTrail Lite v2.2.1.
|
|
1007
1007
|
© Catalyst Forge, LLC — www.catalystforge.com
|
|
1008
1008
|
Licensed under Apache License 2.0 (upstream ForgeTrail repo).
|
|
1009
1009
|
-->
|
|
@@ -1179,4 +1179,4 @@ ForgeTrail Lite covers the shape of a project. The full **ForgeTrail MCP server*
|
|
|
1179
1179
|
|
|
1180
1180
|
---
|
|
1181
1181
|
|
|
1182
|
-
**ForgeTrail Lite v2.2.
|
|
1182
|
+
**ForgeTrail Lite v2.2.1** · © Catalyst Forge, LLC · [www.catalystforge.com](https://www.catalystforge.com) · [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
package/docs/NPM.md
CHANGED
|
@@ -10,12 +10,12 @@ Two public unscoped packages:
|
|
|
10
10
|
|
|
11
11
|
| Package | This tree | On npm until you publish | From | What it is |
|
|
12
12
|
| --- | --- | --- | --- | --- |
|
|
13
|
-
| [`forgetrail`](https://www.npmjs.com/package/forgetrail) | 0.5.
|
|
14
|
-
| [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.
|
|
13
|
+
| [`forgetrail`](https://www.npmjs.com/package/forgetrail) | 0.5.2 | 0.5.2 | repo root | CLI + Lite + templates. `pnpm dlx forgetrail install --lite` |
|
|
14
|
+
| [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.2 | 0.4.1 | `mcp-server/` | MCP bin. Depends on `forgetrail` for content. `pnpm dlx forgetrail-mcp` |
|
|
15
15
|
|
|
16
16
|
These are **installer and MCP channels**, not a library. App repos should not add `forgetrail` to `dependencies`.
|
|
17
17
|
|
|
18
|
-
`forgetrail@0.5.
|
|
18
|
+
`forgetrail@0.5.2` is on npm. This tree has Lite v2.2.1 and a new installer `Next:` step that are not in `0.5.2`, so `forgetrail` needs a version bump before its next publish. `forgetrail-mcp@0.4.2` is this tree and is not published yet. It adds `forgetrail` as a dependency and returns an explicit error when content is missing. `0.4.1` remains the registry copy until you publish from `mcp-server/`. `pnpm run pack:check` is the gate. It does not publish.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -59,11 +59,11 @@ The `Debugger listening` line on MCP `prepack` is Cursor attaching to a one-line
|
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
61
|
# Prefer pnpm dlx. npm 12 `npx forgetrail --help` on Windows failed to spawn the bin.
|
|
62
|
-
pnpm dlx forgetrail
|
|
63
|
-
pnpm dlx forgetrail
|
|
62
|
+
pnpm dlx forgetrail@<version> --help
|
|
63
|
+
pnpm dlx forgetrail@<version> install --lite --dry-run
|
|
64
64
|
|
|
65
|
-
# MCP starts
|
|
66
|
-
pnpm dlx forgetrail-mcp@0.4.
|
|
65
|
+
# MCP starts and reads content from its forgetrail dependency. ping should not say "content missing".
|
|
66
|
+
pnpm dlx forgetrail-mcp@0.4.2
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Optional Cursor MCP (content from a `forgetrail` install, or set the path):
|
package/package.json
CHANGED
package/scripts/install.mjs
CHANGED
|
@@ -88,6 +88,7 @@ export function runInstallForgetrail(rawArgv, { defaultToCwd = false } = {}) {
|
|
|
88
88
|
console.log(" First chat: _forgetrail/INITIAL_PROMPT.md");
|
|
89
89
|
console.log(" Project record: appledger/ (not workflow_tracking.json)");
|
|
90
90
|
console.log(" Hooks: .forgetrail/hooks/ (enforced via .cursor/hooks.json)");
|
|
91
|
+
printLedgerNext();
|
|
91
92
|
return { target, mode: "full" };
|
|
92
93
|
}
|
|
93
94
|
|
|
@@ -145,11 +146,18 @@ export function runInstallLite(rawArgv, { defaultToCwd = false } = {}) {
|
|
|
145
146
|
console.log(" Hooks: .forgetrail/hooks/ (enforced via .cursor/hooks.json)");
|
|
146
147
|
if (args.withGenesisStub) {
|
|
147
148
|
console.log(" Genesis: docs/GENESIS.md (stub — replace with your spec)");
|
|
148
|
-
console.log(" Next: see TRY_FORGETRAIL.md in the ForgeTrail repo");
|
|
149
149
|
}
|
|
150
|
+
printLedgerNext();
|
|
150
151
|
return { target, mode: "lite", withGenesisStub: !!args.withGenesisStub };
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
function printLedgerNext() {
|
|
155
|
+
console.log("\nNext, create the ledger in the app folder (the agent can run these):");
|
|
156
|
+
console.log(' pnpm dlx appledger init --name "Your app name"');
|
|
157
|
+
console.log(" pnpm dlx appledger check");
|
|
158
|
+
console.log("Then paste the kickoff line from https://forgetrail.dev/docs/try");
|
|
159
|
+
}
|
|
160
|
+
|
|
153
161
|
export const INSTALL_FULL_HELP = `
|
|
154
162
|
ForgeTrail template-in-repo install (offline / no MCP server required)
|
|
155
163
|
|
package/scripts/mcp-lib.mjs
CHANGED
|
@@ -125,21 +125,36 @@ export function posixPath(p) {
|
|
|
125
125
|
return p.replace(/\\/g, "/");
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/** True when this CLI runs from a clone that has mcp-server/ (the npm package does not ship it). */
|
|
129
|
+
export function isClone() {
|
|
130
|
+
return existsSync(join(MCP_SERVER_DIR, "package.json"));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** pnpm dlx and npx unpack into a cache that can be removed, so its path is not a stable FORGETRAIL_ROOT. */
|
|
134
|
+
export function isTemporaryInstall(p = FORGETRAIL_ROOT) {
|
|
135
|
+
return /[\\/](dlx|_npx)[\\/]/i.test(p);
|
|
136
|
+
}
|
|
137
|
+
|
|
128
138
|
export function mcpClientConfigObject() {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
if (existsSync(MCP_ENTRY)) {
|
|
140
|
+
return {
|
|
141
|
+
mcpServers: {
|
|
142
|
+
forgetrail: {
|
|
143
|
+
command: "node",
|
|
144
|
+
args: [posixPath(MCP_ENTRY)],
|
|
145
|
+
env: { FORGETRAIL_ROOT: posixPath(FORGETRAIL_ROOT) },
|
|
146
|
+
},
|
|
135
147
|
},
|
|
136
|
-
}
|
|
137
|
-
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const server = { command: "npx", args: ["-y", "forgetrail-mcp"] };
|
|
151
|
+
if (!isTemporaryInstall()) server.env = { FORGETRAIL_ROOT: posixPath(FORGETRAIL_ROOT) };
|
|
152
|
+
return { mcpServers: { forgetrail: server } };
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
/** Copy-paste MCP client setup — shown after `forgetrail mcp build`. */
|
|
141
156
|
export function printMcpClientSetupBanner({ showBuildComplete = true } = {}) {
|
|
142
|
-
const
|
|
157
|
+
const fromClone = existsSync(MCP_ENTRY);
|
|
143
158
|
|
|
144
159
|
if (showBuildComplete) {
|
|
145
160
|
console.log("\n✓ Build complete.\n");
|
|
@@ -149,8 +164,21 @@ export function printMcpClientSetupBanner({ showBuildComplete = true } = {}) {
|
|
|
149
164
|
console.log(" Cursor — project .cursor/mcp.json or Settings → MCP → add server:");
|
|
150
165
|
console.log(JSON.stringify(mcpClientConfigObject(), null, 2));
|
|
151
166
|
console.log("");
|
|
167
|
+
if (!fromClone) {
|
|
168
|
+
if (isTemporaryInstall()) {
|
|
169
|
+
console.log(" This forgetrail copy is in a temporary pnpm dlx or npx cache, so FORGETRAIL_ROOT is not set.");
|
|
170
|
+
console.log(" forgetrail-mcp finds the forgetrail package it depends on. For a fixed path: pnpm add -g forgetrail, then rerun this command.");
|
|
171
|
+
} else {
|
|
172
|
+
console.log(` FORGETRAIL_ROOT is this installed forgetrail package: ${posixPath(FORGETRAIL_ROOT)}`);
|
|
173
|
+
}
|
|
174
|
+
console.log("");
|
|
175
|
+
}
|
|
152
176
|
console.log(" Claude Desktop — %APPDATA%\\Claude\\claude_desktop_config.json (same mcpServers block)");
|
|
153
|
-
console.log(
|
|
177
|
+
console.log(
|
|
178
|
+
fromClone
|
|
179
|
+
? ` Claude Code — claude mcp add forgetrail node ${posixPath(MCP_ENTRY)}`
|
|
180
|
+
: " Claude Code — claude mcp add forgetrail -- npx -y forgetrail-mcp"
|
|
181
|
+
);
|
|
154
182
|
console.log("");
|
|
155
183
|
console.log(" Then reload MCP in Cursor (Settings → MCP) or restart Cursor.");
|
|
156
184
|
console.log(" Verify: forgetrail mcp ping | Reprint: forgetrail mcp cursor-config");
|
package/scripts/mcp-status.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
MCP_SERVER_DIR,
|
|
9
9
|
analyzeCursorMcpConfig,
|
|
10
10
|
findCursorMcpJson,
|
|
11
|
+
isClone,
|
|
11
12
|
staticMcpChecks,
|
|
12
13
|
printCursorConfigTemplate,
|
|
13
14
|
runMcpBuild,
|
|
@@ -121,6 +122,12 @@ export function runMcpCommand(argv) {
|
|
|
121
122
|
return;
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
if (cmd !== "cursor-config" && !isClone()) {
|
|
126
|
+
console.error(`forgetrail mcp ${cmd} runs from a ForgeTrail clone. This npm install does not include mcp-server/.`);
|
|
127
|
+
console.error("Use the published server instead: forgetrail mcp cursor-config prints a config that starts forgetrail-mcp.");
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
124
131
|
switch (cmd) {
|
|
125
132
|
case "build":
|
|
126
133
|
runMcpBuild();
|
|
@@ -44,9 +44,34 @@ test("install does not create workflow_tracking.json", () => {
|
|
|
44
44
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
45
45
|
assert.doesNotMatch(result.stdout, /\\workflow_tracking\.json/);
|
|
46
46
|
assert.match(result.stdout, /Project record: appledger/);
|
|
47
|
+
assert.match(result.stdout, /pnpm dlx appledger init --name/);
|
|
48
|
+
assert.match(result.stdout, /pnpm dlx appledger check/);
|
|
47
49
|
}
|
|
48
50
|
});
|
|
49
51
|
|
|
52
|
+
test("Lite step 4 runs appledger init and check", () => {
|
|
53
|
+
const lite = readFileSync(join(root, "content", "FORGETRAIL_LITE.md"), "utf8");
|
|
54
|
+
const step = lite.split("\n").find((line) => line.startsWith("4. **Create `appledger/`**"));
|
|
55
|
+
assert.ok(step);
|
|
56
|
+
assert.match(step, /pnpm dlx appledger init --name/);
|
|
57
|
+
assert.match(step, /appledger check/);
|
|
58
|
+
assert.match(step, /examples\/minimal\/appledger/);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("cursor-config from an npm install starts forgetrail-mcp, not a missing dist file", async () => {
|
|
62
|
+
const { mcpClientConfigObject, isTemporaryInstall } = await import("./mcp-lib.mjs");
|
|
63
|
+
const server = mcpClientConfigObject().mcpServers.forgetrail;
|
|
64
|
+
const hasDist = spawnSync(process.execPath, ["-e", "process.exit(require('node:fs').existsSync(process.argv[1]) ? 0 : 1)", join(root, "mcp-server", "dist", "index.js")]).status === 0;
|
|
65
|
+
if (hasDist) {
|
|
66
|
+
assert.equal(server.command, "node");
|
|
67
|
+
} else {
|
|
68
|
+
assert.deepEqual([server.command, ...server.args], ["npx", "-y", "forgetrail-mcp"]);
|
|
69
|
+
}
|
|
70
|
+
assert.equal(isTemporaryInstall("C:/Users/u/AppData/Local/pnpm-cache/dlx/abc/node_modules/forgetrail"), true);
|
|
71
|
+
assert.equal(isTemporaryInstall("/home/u/.npm/_npx/abc/node_modules/forgetrail"), true);
|
|
72
|
+
assert.equal(isTemporaryInstall("C:/Users/u/AppData/Local/pnpm/global/5/node_modules/forgetrail"), false);
|
|
73
|
+
});
|
|
74
|
+
|
|
50
75
|
test("session start warns on a legacy file and does not quote it as the live phase", () => {
|
|
51
76
|
const dir = mkdtempSync(join(tmpdir(), "ft-session-"));
|
|
52
77
|
mkdirSync(join(dir, ".forgetrail"), { recursive: true });
|
|
@@ -76,7 +101,7 @@ test("Lite and workflow instructions name the ledger", () => {
|
|
|
76
101
|
assert.ok(legacyAt > 0 && resumeAt > legacyAt);
|
|
77
102
|
const instructional = `${lite.slice(0, legacyAt)}\n${lite.slice(resumeAt)}`;
|
|
78
103
|
assert.match(lite.slice(legacyAt, resumeAt), /"schemaVersion": "lite-1"/);
|
|
79
|
-
assert.match(instructional, /ForgeTrail Lite v2\.2\.
|
|
104
|
+
assert.match(instructional, /ForgeTrail Lite v2\.2\.1/);
|
|
80
105
|
for (const line of instructional.split("\n")) {
|
|
81
106
|
if (!line.includes("workflow_tracking.json")) continue;
|
|
82
107
|
assert.match(line, /[Dd]o not|does not|not the live phase|not recreate/, line);
|