forgeos 0.1.0-alpha.21 → 0.1.0-alpha.23
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/AGENTS.md +1 -1
- package/CHANGELOG.md +30 -2
- package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
- package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
- package/docs/cair-protocol.md +103 -0
- package/docs/changelog.md +30 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
- package/package.json +2 -1
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/types.ts +3 -0
- package/src/forge/agent-memory/bridge.ts +28 -0
- package/src/forge/agent-memory/context-pack.ts +134 -8
- package/src/forge/agent-memory/types.ts +10 -1
- package/src/forge/cli/commands.ts +47 -0
- package/src/forge/cli/main.ts +4 -0
- package/src/forge/cli/new.ts +3 -1
- package/src/forge/cli/parse.ts +64 -11
- package/src/forge/cli/studio.ts +54 -0
- package/src/forge/cli/verify.ts +2 -0
- package/src/forge/compiler/frontend-graph/build.ts +58 -2
- package/src/forge/delta/explain.ts +113 -1
- package/src/forge/delta/index.ts +12 -0
- package/src/forge/delta/recorder.ts +60 -0
- package/src/forge/delta/status.ts +639 -2
- package/src/forge/delta/store.ts +281 -5
- package/src/forge/delta/timeline.ts +75 -1
- package/src/forge/version.ts +1 -1
- package/templates/nuxt-web/.vscode/settings.json +14 -0
- package/templates/nuxt-web/README.md +30 -0
- package/templates/nuxt-web/forge.config.ts +3 -0
- package/templates/nuxt-web/package.json +33 -0
- package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
- package/templates/nuxt-web/src/commands/createNote.ts +26 -0
- package/templates/nuxt-web/src/forge/schema.ts +12 -0
- package/templates/nuxt-web/src/policies.ts +6 -0
- package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
- package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
- package/templates/nuxt-web/tsconfig.json +17 -0
- package/templates/nuxt-web/web/app.vue +67 -0
- package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
- package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
- package/templates/nuxt-web/web/composables/forge.ts +13 -0
- package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
- package/templates/nuxt-web/web/nuxt.config.ts +11 -0
- package/templates/nuxt-web/web/package.json +17 -0
- package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
- package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
- package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
- package/templates/nuxt-web/web/tsconfig.json +3 -0
package/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.23 input=43fbd897d0f0a003e2f63e7048eb3281a5871034827653640e010161c0385d44 content=0d493cf0e41b71cb652d5e0e1b0c1f83d2a1281b748321f0b00f0773ba93074e
|
|
2
2
|
# AGENTS.md
|
|
3
3
|
|
|
4
4
|
<!-- forge-generated:start -->
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# forgeos
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.0-alpha.23
|
|
6
|
+
|
|
7
|
+
### Patch Changes
|
|
8
|
+
|
|
9
|
+
- Tighten the post-alpha.22 release surface and package evidence.
|
|
10
|
+
|
|
11
|
+
- Add a dedicated Nuxt template smoke workflow that installs `nuxt-web`, runs Forge generation/checks, runs Nuxt typecheck, and probes `forge dev --once`.
|
|
12
|
+
- Include `nuxt-web` in the default field-test template matrix.
|
|
13
|
+
- Add explicit `scopeTarget` metadata and human-readable target output for `forge agent context --change`, `--proof`, and `--handoff`.
|
|
14
|
+
- Teach `forge explain` to fall back to the current generated agent contract when DeltaDB has no runtime history, while marking the result as contract-defined instead of executed.
|
|
15
|
+
- Downgrade read-only observation commands such as `forge status`, `forge changed`, `forge handoff`, `forge explain`, `forge timeline`, and CAIR queries to low-confidence context-gathering sessions in DeltaDB.
|
|
16
|
+
- Package `docs/cair-protocol.md` in the npm tarball and expand the public security/threat-model docs for DeltaDB, agent memory, CAIR, Studio bridge, brownfield import, and Nuxt surfaces.
|
|
17
|
+
|
|
18
|
+
## 0.1.0-alpha.22
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Improve the post-alpha.21 agent workflow without adding new MCP tools.
|
|
23
|
+
|
|
24
|
+
- Add `forge agent context` scopes for entry, change, proof, and handoff context packs.
|
|
25
|
+
- Add DeltaDB verbose health details for queue redaction, operation age, semantic projection state, and overhead posture.
|
|
26
|
+
- Add `forge delta compact`, `forge delta prune`, and redacted `forge delta export` for local Delta maintenance and support bundles.
|
|
27
|
+
- Add `forge doctor delta` for recorder writability, queue drain, redaction, and gitignore checks.
|
|
28
|
+
- Add Semantic Timeline summary data for stale proofs and causal chains.
|
|
29
|
+
- Record CAIR snapshot/query/action activity as Delta timeline events without adding new MCP tools.
|
|
30
|
+
- Add a Studio snapshot handoff block and a dedicated CAIR Protocol documentation page.
|
|
31
|
+
- Add an official `nuxt-web` template with a Forge notes backend, client/server Nuxt plugins, a `useNotes` composable, a Nitro runtime-config route, and generated Vue composables.
|
|
32
|
+
|
|
3
33
|
## 0.1.0-alpha.21
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -23,8 +53,6 @@
|
|
|
23
53
|
- Preserve empty stdio command arguments, diagnose malformed command strings, and support structured `service.commandArgs` in external manifests.
|
|
24
54
|
- Include the basic example client demo in typecheck coverage.
|
|
25
55
|
|
|
26
|
-
## Unreleased
|
|
27
|
-
|
|
28
56
|
## 0.1.0-alpha.19
|
|
29
57
|
|
|
30
58
|
Alpha hardening:
|
|
Binary file
|
package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar
CHANGED
|
Binary file
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# CAIR Protocol
|
|
2
|
+
|
|
3
|
+
CAIR is ForgeOS' compact agent interface for reading code structure, querying symbols, and planning safe edits without loading the whole repository into an agent context window.
|
|
4
|
+
|
|
5
|
+
CAIR is intentionally CLI-first. It does not add a second mutating tool surface. Agents should use CAIR to inspect structure and create reviewable plans, then apply those plans through the ForgeOS CLI with hash checks and rollback journals.
|
|
6
|
+
|
|
7
|
+
## Read Workflow
|
|
8
|
+
|
|
9
|
+
Start with a compact snapshot:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
forge cair snapshot
|
|
13
|
+
forge cair query "Q STATUS"
|
|
14
|
+
forge cair query "Q ST"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Use symbol, definition, reference, impact, and dependency API queries before opening large files:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
forge cair query "Q S name=createTicket"
|
|
21
|
+
forge cair query "Q D S#1"
|
|
22
|
+
forge cair query "Q R S#1"
|
|
23
|
+
forge cair query "Q I S#1"
|
|
24
|
+
forge cair query "Q DEP.API package=zod symbol=object"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The goal is to make agent navigation evidence-backed: CAIR gives stable ids for modules, symbols, packages, APIs, and tests so an agent can select a small file set instead of scanning the whole project.
|
|
28
|
+
|
|
29
|
+
## Action Safety
|
|
30
|
+
|
|
31
|
+
Mutating CAIR actions should be planned first:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
forge cair action --plan "A RN t=S#1 nn=openTicket"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The plan lives under `.forge/cair/plans/` and records the target files and expected hashes. Applying a plan checks those hashes before editing:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
forge cair action "A APPLY plan=<P#|.forge/cair/plans/...json>"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Applied plans write rollback journals under `.forge/cair/journal/`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
forge cair action "A ROLLBACK journal=.forge/cair/journal/<journal>.json"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use `--dry-run` when exploring an action shape without creating a plan:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
forge cair action --dry-run "A CREATE.SYMBOL path=src/example.ts kind=function name=example export=true createFile=true"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Generated files stay protected by default. Use `--include-generated` only when the edit is intentionally about generated artifacts.
|
|
56
|
+
|
|
57
|
+
## DeltaDB Evidence
|
|
58
|
+
|
|
59
|
+
Successful CAIR CLI runs are recorded in DeltaDB as sanitized operational events:
|
|
60
|
+
|
|
61
|
+
| CAIR command | Delta event |
|
|
62
|
+
|--------------|-------------|
|
|
63
|
+
| `forge cair snapshot` | `cair.snapshot.created` |
|
|
64
|
+
| `forge cair query ...` | `cair.query.run` |
|
|
65
|
+
| `forge cair action --plan ...` | `cair.plan.created` |
|
|
66
|
+
| `forge cair action "A APPLY ..."` | `cair.plan.applied` |
|
|
67
|
+
| `forge cair action --dry-run ...` | `cair.action.previewed` |
|
|
68
|
+
|
|
69
|
+
The recorder stores compact verbs such as `Q ST` or `A APPLY`; it does not need to store full action bodies as first-class timeline data. Use:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
forge timeline cair:protocol --json
|
|
73
|
+
forge timeline --kind cair.plan.applied --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This makes CAIR navigation and guarded edits visible beside file changes, proofs, and agent activity.
|
|
77
|
+
|
|
78
|
+
## Compact Aliases
|
|
79
|
+
|
|
80
|
+
| Long form | Compact |
|
|
81
|
+
|-----------|---------|
|
|
82
|
+
| `Q STATUS` | `Q ST` |
|
|
83
|
+
| `Q SYMBOL` | `Q S` |
|
|
84
|
+
| `Q DEF` | `Q D` |
|
|
85
|
+
| `Q REFS` | `Q R` |
|
|
86
|
+
| `Q IMPACT` | `Q I` |
|
|
87
|
+
| `A RENAME.SYMBOL target=S#1 newName=x` | `A RN t=S#1 nn=x` |
|
|
88
|
+
|
|
89
|
+
## Agent Posture
|
|
90
|
+
|
|
91
|
+
Use this loop for code work:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
forge cair snapshot
|
|
95
|
+
forge cair query "Q ST"
|
|
96
|
+
forge cair query "Q S name=<symbol>"
|
|
97
|
+
forge cair query "Q I S#1"
|
|
98
|
+
forge cair action --plan "A RN t=S#1 nn=<newName>"
|
|
99
|
+
forge cair action "A APPLY plan=<P#|path>"
|
|
100
|
+
forge check --json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Do not use CAIR as a bypass around ForgeOS rules. Commands remain transactional writes, queries and liveQueries remain read-only, side effects still belong in actions and workflows, and generated artifacts remain derived.
|
package/docs/changelog.md
CHANGED
|
@@ -6,6 +6,36 @@ The canonical source file in the repository is `CHANGELOG.md`.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.1.0-alpha.23
|
|
10
|
+
|
|
11
|
+
- Tightened the post-alpha.22 release surface and package evidence:
|
|
12
|
+
added a dedicated Nuxt template smoke workflow, included `nuxt-web` in the
|
|
13
|
+
default field-test template matrix, packaged `docs/cair-protocol.md`, and
|
|
14
|
+
expanded the security/threat-model docs for DeltaDB, agent memory, CAIR,
|
|
15
|
+
Studio bridge, brownfield import, and Nuxt surfaces.
|
|
16
|
+
- `forge agent context` now returns explicit `scopeTarget` metadata and prints
|
|
17
|
+
the resolved context target for entry, change, proof, and handoff packs.
|
|
18
|
+
- `forge explain` now falls back to the current generated agent contract when
|
|
19
|
+
DeltaDB has no runtime history, marking the entry as contract-defined rather
|
|
20
|
+
than executed.
|
|
21
|
+
- DeltaDB work-session inference now treats read-only observation commands such
|
|
22
|
+
as `forge status`, `forge changed`, `forge handoff`, `forge explain`,
|
|
23
|
+
`forge timeline`, and CAIR queries as low-confidence context-gathering
|
|
24
|
+
sessions.
|
|
25
|
+
|
|
26
|
+
## 0.1.0-alpha.22
|
|
27
|
+
|
|
28
|
+
- Added focused post-alpha.21 workflow improvements without expanding MCP tools:
|
|
29
|
+
scoped Agent Memory context packs, DeltaDB verbose health details, Semantic
|
|
30
|
+
Timeline stale-proof/causal summaries, Studio snapshot handoff metadata,
|
|
31
|
+
local Delta maintenance commands (`compact`, `prune`, redacted `export`),
|
|
32
|
+
`forge doctor delta`, CAIR timeline events, and a dedicated CAIR Protocol
|
|
33
|
+
documentation page.
|
|
34
|
+
- Added an official `nuxt-web` template: a Forge notes backend plus Nuxt app
|
|
35
|
+
using client/server Forge plugins, `web/composables/useNotes.ts`, generated
|
|
36
|
+
Vue composables, a Nitro runtime-config route, and
|
|
37
|
+
`NUXT_PUBLIC_FORGE_URL`.
|
|
38
|
+
|
|
9
39
|
## 0.1.0-alpha.21
|
|
10
40
|
|
|
11
41
|
Alpha.21 hardens external-agent privacy and brownfield import polish:
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgeos",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.23",
|
|
4
4
|
"description": "Agent-native application framework and compiler for building Forge apps without a mandatory dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"adapters/",
|
|
8
8
|
"bin/",
|
|
9
|
+
"docs/cair-protocol.md",
|
|
9
10
|
"docs/forge-protocol.md",
|
|
10
11
|
"examples/go-billing/",
|
|
11
12
|
"examples/java-billing/",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.
|
|
1
|
+
{"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.23","releaseId":"forgeos@0.1.0-alpha.23+unknown","schemaVersion":"0.1.0"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @forge-generated generator=0.1.0-alpha.
|
|
1
|
+
// @forge-generated generator=0.1.0-alpha.23 input=43fbd897d0f0a003e2f63e7048eb3281a5871034827653640e010161c0385d44 content=8b537f90580f28c1630850bc7b7199e17d0bc62d05e9565fdf84da4bdbf9f6dc
|
|
2
2
|
export const releaseManifest = {
|
|
3
3
|
"defaultProvider": "local",
|
|
4
4
|
"diagnostics": [],
|
|
@@ -19,7 +19,7 @@ export const releaseManifest = {
|
|
|
19
19
|
"custom"
|
|
20
20
|
],
|
|
21
21
|
"packageName": "forgeos",
|
|
22
|
-
"packageVersion": "0.1.0-alpha.
|
|
23
|
-
"releaseId": "forgeos@0.1.0-alpha.
|
|
22
|
+
"packageVersion": "0.1.0-alpha.23",
|
|
23
|
+
"releaseId": "forgeos@0.1.0-alpha.23+unknown",
|
|
24
24
|
"schemaVersion": "0.1.0"
|
|
25
25
|
} as const;
|
|
@@ -29,6 +29,9 @@ export interface AgentMemoryCommandOptions {
|
|
|
29
29
|
eventName?: string;
|
|
30
30
|
input?: unknown;
|
|
31
31
|
entry?: string;
|
|
32
|
+
change?: string;
|
|
33
|
+
proof?: string;
|
|
34
|
+
handoff?: boolean;
|
|
32
35
|
current?: boolean;
|
|
33
36
|
dryRun?: boolean;
|
|
34
37
|
force?: boolean;
|
|
@@ -308,6 +311,9 @@ export async function runAgentMemoryCommand(options: AgentMemoryCommandOptions):
|
|
|
308
311
|
return await buildAgentMemoryContext({
|
|
309
312
|
workspaceRoot: options.workspaceRoot,
|
|
310
313
|
entry: options.entry,
|
|
314
|
+
change: options.change,
|
|
315
|
+
proof: options.proof,
|
|
316
|
+
handoff: options.handoff,
|
|
311
317
|
limit: options.limit,
|
|
312
318
|
});
|
|
313
319
|
} catch (error) {
|
|
@@ -1015,6 +1021,7 @@ function formatAgentMemoryContextHuman(result: AgentMemoryContextPack): string {
|
|
|
1015
1021
|
const lines = [
|
|
1016
1022
|
`Forge Agent Context (${result.scope}${result.entry ? `: ${result.entry}` : ""})`,
|
|
1017
1023
|
"",
|
|
1024
|
+
`target: ${formatAgentContextTarget(result)}`,
|
|
1018
1025
|
`events: ${summary.events}`,
|
|
1019
1026
|
`sources: ${summary.sources.length > 0 ? summary.sources.join(", ") : "none"}`,
|
|
1020
1027
|
`tools: ${summary.tools.length > 0 ? summary.tools.join(", ") : "none"}`,
|
|
@@ -1052,9 +1059,30 @@ function formatAgentMemoryContextHuman(result: AgentMemoryContextPack): string {
|
|
|
1052
1059
|
lines.push(` - ${question}`);
|
|
1053
1060
|
}
|
|
1054
1061
|
}
|
|
1062
|
+
if (result.recommendedCommands.length > 0) {
|
|
1063
|
+
lines.push("", "Next:");
|
|
1064
|
+
for (const command of result.recommendedCommands.slice(0, 6)) {
|
|
1065
|
+
lines.push(` ${command}`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1055
1068
|
return `${lines.join("\n")}\n`;
|
|
1056
1069
|
}
|
|
1057
1070
|
|
|
1071
|
+
function formatAgentContextTarget(result: AgentMemoryContextPack): string {
|
|
1072
|
+
const target = result.scopeTarget;
|
|
1073
|
+
const parts: string[] = [target.kind];
|
|
1074
|
+
if (target.value) {
|
|
1075
|
+
parts.push(target.value);
|
|
1076
|
+
}
|
|
1077
|
+
if (target.semanticTarget && target.semanticTarget !== target.value) {
|
|
1078
|
+
parts.push(`semantic=${target.semanticTarget}`);
|
|
1079
|
+
}
|
|
1080
|
+
if (target.currentSessionId) {
|
|
1081
|
+
parts.push(`session=${target.currentSessionId}`);
|
|
1082
|
+
}
|
|
1083
|
+
return parts.join(" ");
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1058
1086
|
function formatAgentMemoryEventsHuman(events: AgentMemoryEventRecord[]): string {
|
|
1059
1087
|
const sources = uniqueStrings(events.map((event) => event.sourceName));
|
|
1060
1088
|
const tools = uniqueStrings(events.flatMap((event) => {
|
|
@@ -4,14 +4,26 @@ import type { AgentMemoryContextEvent, AgentMemoryContextPack, AgentMemoryEventR
|
|
|
4
4
|
export async function buildAgentMemoryContext(input: {
|
|
5
5
|
workspaceRoot: string;
|
|
6
6
|
entry?: string;
|
|
7
|
+
change?: string;
|
|
8
|
+
proof?: string;
|
|
9
|
+
handoff?: boolean;
|
|
7
10
|
limit?: number;
|
|
8
11
|
}): Promise<AgentMemoryContextPack> {
|
|
9
12
|
const store = await DeltaStore.open(input.workspaceRoot, { access: "read" });
|
|
10
13
|
try {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
14
|
+
const scope = contextScope(input);
|
|
15
|
+
const target = contextTarget(input, scope);
|
|
16
|
+
const currentSession = await store.currentWorkSession();
|
|
17
|
+
const sessionId = scope === "change" && (input.change === "current" || !input.change)
|
|
18
|
+
? currentSession?.id
|
|
19
|
+
: undefined;
|
|
20
|
+
const events = await store.listAgentMemoryEvents({ target: eventTarget(input, scope), limit: input.limit ?? 50 });
|
|
21
|
+
const timeline = target || sessionId
|
|
22
|
+
? await store.semanticTimeline({ target, workSessionId: sessionId, limit: input.limit ?? 50 })
|
|
23
|
+
: undefined;
|
|
24
|
+
const current = timeline?.currentState && Object.keys(timeline.currentState).length > 0
|
|
25
|
+
? timeline.currentState
|
|
26
|
+
: await currentSessionState(store, currentSession);
|
|
15
27
|
const goals = events
|
|
16
28
|
.filter((event) => event.normalizedKind === "agent.prompt.submitted")
|
|
17
29
|
.map((event) => ({
|
|
@@ -35,9 +47,13 @@ export async function buildAgentMemoryContext(input: {
|
|
|
35
47
|
const openQuestions = timeline?.openQuestions ?? [];
|
|
36
48
|
return {
|
|
37
49
|
ok: true,
|
|
38
|
-
scope
|
|
39
|
-
|
|
50
|
+
scope,
|
|
51
|
+
scopeTarget: contextScopeTarget(input, scope, target, currentSession?.id),
|
|
52
|
+
entry: input.entry,
|
|
53
|
+
change: input.change,
|
|
54
|
+
proof: input.proof,
|
|
40
55
|
currentState: current,
|
|
56
|
+
recommendedCommands: recommendedCommands(scope, input, currentSession?.id),
|
|
41
57
|
agentMemory: {
|
|
42
58
|
summary: {
|
|
43
59
|
events: contextEventItems.length,
|
|
@@ -68,6 +84,111 @@ export async function buildAgentMemoryContext(input: {
|
|
|
68
84
|
}
|
|
69
85
|
}
|
|
70
86
|
|
|
87
|
+
function contextScope(input: {
|
|
88
|
+
entry?: string;
|
|
89
|
+
change?: string;
|
|
90
|
+
proof?: string;
|
|
91
|
+
handoff?: boolean;
|
|
92
|
+
}): AgentMemoryContextPack["scope"] {
|
|
93
|
+
if (input.handoff) {
|
|
94
|
+
return "handoff";
|
|
95
|
+
}
|
|
96
|
+
if (input.proof) {
|
|
97
|
+
return "proof";
|
|
98
|
+
}
|
|
99
|
+
if (input.change) {
|
|
100
|
+
return "change";
|
|
101
|
+
}
|
|
102
|
+
return input.entry ? "entry" : "current";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function contextTarget(
|
|
106
|
+
input: { entry?: string; change?: string; proof?: string },
|
|
107
|
+
scope: AgentMemoryContextPack["scope"],
|
|
108
|
+
): string | undefined {
|
|
109
|
+
if (scope === "entry") {
|
|
110
|
+
return input.entry;
|
|
111
|
+
}
|
|
112
|
+
if (scope === "proof") {
|
|
113
|
+
return input.proof?.includes(":") ? input.proof : `proof:${input.proof}`;
|
|
114
|
+
}
|
|
115
|
+
if (scope === "change" && input.change && input.change !== "current") {
|
|
116
|
+
return input.change.includes(":") ? input.change : `session:${input.change}`;
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function contextScopeTarget(
|
|
122
|
+
input: { entry?: string; change?: string; proof?: string; handoff?: boolean },
|
|
123
|
+
scope: AgentMemoryContextPack["scope"],
|
|
124
|
+
semanticTarget: string | undefined,
|
|
125
|
+
currentSessionId: string | undefined,
|
|
126
|
+
): AgentMemoryContextPack["scopeTarget"] {
|
|
127
|
+
if (scope === "entry") {
|
|
128
|
+
return { kind: "entry", value: input.entry, semanticTarget };
|
|
129
|
+
}
|
|
130
|
+
if (scope === "proof") {
|
|
131
|
+
return { kind: "proof", value: input.proof, semanticTarget };
|
|
132
|
+
}
|
|
133
|
+
if (scope === "change") {
|
|
134
|
+
const value = input.change ?? "current";
|
|
135
|
+
return {
|
|
136
|
+
kind: "change",
|
|
137
|
+
value,
|
|
138
|
+
...(semanticTarget ? { semanticTarget } : {}),
|
|
139
|
+
...(value === "current" && currentSessionId ? { currentSessionId } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (scope === "handoff") {
|
|
143
|
+
return { kind: "handoff", value: "handoff", currentSessionId };
|
|
144
|
+
}
|
|
145
|
+
return { kind: "current-session", value: "current", currentSessionId };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function eventTarget(
|
|
149
|
+
input: { entry?: string; change?: string; proof?: string },
|
|
150
|
+
scope: AgentMemoryContextPack["scope"],
|
|
151
|
+
): string | undefined {
|
|
152
|
+
if (scope === "entry") {
|
|
153
|
+
return input.entry;
|
|
154
|
+
}
|
|
155
|
+
if (scope === "proof") {
|
|
156
|
+
return input.proof;
|
|
157
|
+
}
|
|
158
|
+
if (scope === "change" && input.change !== "current") {
|
|
159
|
+
return input.change;
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function recommendedCommands(
|
|
165
|
+
scope: AgentMemoryContextPack["scope"],
|
|
166
|
+
input: { entry?: string; change?: string; proof?: string },
|
|
167
|
+
currentSessionId: string | undefined,
|
|
168
|
+
): string[] {
|
|
169
|
+
const commands = [
|
|
170
|
+
"forge agent timeline --json",
|
|
171
|
+
"forge delta status --verbose --json",
|
|
172
|
+
];
|
|
173
|
+
if (scope === "entry" && input.entry) {
|
|
174
|
+
commands.push(`forge timeline ${input.entry} --json`);
|
|
175
|
+
commands.push(`forge explain ${input.entry} --json`);
|
|
176
|
+
}
|
|
177
|
+
if (scope === "proof" && input.proof) {
|
|
178
|
+
commands.push(`forge timeline proof:${input.proof.replace(/^proof:/u, "")} --json`);
|
|
179
|
+
}
|
|
180
|
+
if (scope === "change") {
|
|
181
|
+
commands.push(`forge timeline --session ${input.change === "current" || !input.change ? "current" : input.change} --json`);
|
|
182
|
+
commands.push("forge changed --json");
|
|
183
|
+
}
|
|
184
|
+
if (scope === "handoff") {
|
|
185
|
+
commands.push("forge handoff --json");
|
|
186
|
+
commands.push(`forge timeline --session ${currentSessionId ?? "current"} --json`);
|
|
187
|
+
commands.push("forge changed --json");
|
|
188
|
+
}
|
|
189
|
+
return [...new Set(commands)];
|
|
190
|
+
}
|
|
191
|
+
|
|
71
192
|
function contextEvents(events: AgentMemoryEventRecord[]): AgentMemoryContextEvent[] {
|
|
72
193
|
return events.map((event) => {
|
|
73
194
|
const eventBindings = bindings(event);
|
|
@@ -92,8 +213,8 @@ function contextEvents(events: AgentMemoryEventRecord[]): AgentMemoryContextEven
|
|
|
92
213
|
});
|
|
93
214
|
}
|
|
94
215
|
|
|
95
|
-
async function currentSessionState(store: DeltaStore): Promise<Record<string, unknown>> {
|
|
96
|
-
const session = await store.currentWorkSession();
|
|
216
|
+
async function currentSessionState(store: DeltaStore, currentSession?: Awaited<ReturnType<DeltaStore["currentWorkSession"]>>): Promise<Record<string, unknown>> {
|
|
217
|
+
const session = currentSession ?? await store.currentWorkSession();
|
|
97
218
|
return session
|
|
98
219
|
? {
|
|
99
220
|
sessionId: session.id,
|
|
@@ -101,6 +222,11 @@ async function currentSessionState(store: DeltaStore): Promise<Record<string, un
|
|
|
101
222
|
inferredIntent: session.inferredIntent,
|
|
102
223
|
confidence: session.confidence,
|
|
103
224
|
status: session.status,
|
|
225
|
+
reasons: session.reasons.slice(0, 5).map((reason) => ({
|
|
226
|
+
signal: reason.signal,
|
|
227
|
+
weight: reason.weight,
|
|
228
|
+
...(reason.value ? { value: reason.value } : {}),
|
|
229
|
+
})),
|
|
104
230
|
}
|
|
105
231
|
: {};
|
|
106
232
|
}
|
|
@@ -92,9 +92,18 @@ export interface AgentMemoryContextEvent {
|
|
|
92
92
|
|
|
93
93
|
export interface AgentMemoryContextPack {
|
|
94
94
|
ok: true;
|
|
95
|
-
scope: "current" | "entry";
|
|
95
|
+
scope: "current" | "entry" | "change" | "proof" | "handoff";
|
|
96
|
+
scopeTarget: {
|
|
97
|
+
kind: "current-session" | "entry" | "change" | "proof" | "handoff";
|
|
98
|
+
value?: string;
|
|
99
|
+
semanticTarget?: string;
|
|
100
|
+
currentSessionId?: string;
|
|
101
|
+
};
|
|
96
102
|
entry?: string;
|
|
103
|
+
change?: string;
|
|
104
|
+
proof?: string;
|
|
97
105
|
currentState: Record<string, unknown>;
|
|
106
|
+
recommendedCommands: string[];
|
|
98
107
|
agentMemory: {
|
|
99
108
|
summary: {
|
|
100
109
|
events: number;
|
|
@@ -128,6 +128,14 @@ import {
|
|
|
128
128
|
import {
|
|
129
129
|
formatDeltaExplainHuman,
|
|
130
130
|
formatDeltaExplainJson,
|
|
131
|
+
formatDeltaCompactHuman,
|
|
132
|
+
formatDeltaCompactJson,
|
|
133
|
+
formatDeltaDoctorHuman,
|
|
134
|
+
formatDeltaDoctorJson,
|
|
135
|
+
formatDeltaExportHuman,
|
|
136
|
+
formatDeltaExportJson,
|
|
137
|
+
formatDeltaPruneHuman,
|
|
138
|
+
formatDeltaPruneJson,
|
|
131
139
|
formatDeltaRepairHuman,
|
|
132
140
|
formatDeltaRepairJson,
|
|
133
141
|
formatDeltaStatusHuman,
|
|
@@ -137,6 +145,10 @@ import {
|
|
|
137
145
|
formatDeltaTimelineHuman,
|
|
138
146
|
formatDeltaTimelineJson,
|
|
139
147
|
runDeltaExplain,
|
|
148
|
+
runDeltaCompact,
|
|
149
|
+
runDeltaDoctor,
|
|
150
|
+
runDeltaExport,
|
|
151
|
+
runDeltaPrune,
|
|
140
152
|
runDeltaRepair,
|
|
141
153
|
runDeltaSessionCommand,
|
|
142
154
|
runDeltaStatus,
|
|
@@ -1641,6 +1653,11 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
|
|
|
1641
1653
|
}
|
|
1642
1654
|
return result.exitCode;
|
|
1643
1655
|
}
|
|
1656
|
+
if (command.target === "delta") {
|
|
1657
|
+
const result = await runDeltaDoctor(command.workspaceRoot);
|
|
1658
|
+
process.stdout.write(command.json ? formatDeltaDoctorJson(result) : formatDeltaDoctorHuman(result));
|
|
1659
|
+
return result.exitCode;
|
|
1660
|
+
}
|
|
1644
1661
|
const result = await runDoctorCommand({ workspaceRoot: command.workspaceRoot });
|
|
1645
1662
|
if (command.json) {
|
|
1646
1663
|
process.stdout.write(formatDoctorJson(result));
|
|
@@ -1808,6 +1825,34 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
|
|
|
1808
1825
|
return result.exitCode;
|
|
1809
1826
|
}
|
|
1810
1827
|
case "delta": {
|
|
1828
|
+
if (command.subcommand === "compact") {
|
|
1829
|
+
const result = await runDeltaCompact({
|
|
1830
|
+
workspaceRoot: command.workspaceRoot,
|
|
1831
|
+
dryRun: command.dryRun,
|
|
1832
|
+
});
|
|
1833
|
+
process.stdout.write(command.json ? formatDeltaCompactJson(result) : formatDeltaCompactHuman(result));
|
|
1834
|
+
return result.exitCode;
|
|
1835
|
+
}
|
|
1836
|
+
if (command.subcommand === "prune") {
|
|
1837
|
+
const result = await runDeltaPrune({
|
|
1838
|
+
workspaceRoot: command.workspaceRoot,
|
|
1839
|
+
olderThan: command.olderThan,
|
|
1840
|
+
dryRun: command.dryRun,
|
|
1841
|
+
yes: command.yes,
|
|
1842
|
+
});
|
|
1843
|
+
process.stdout.write(command.json ? formatDeltaPruneJson(result) : formatDeltaPruneHuman(result));
|
|
1844
|
+
return result.exitCode;
|
|
1845
|
+
}
|
|
1846
|
+
if (command.subcommand === "export") {
|
|
1847
|
+
const result = await runDeltaExport({
|
|
1848
|
+
workspaceRoot: command.workspaceRoot,
|
|
1849
|
+
redacted: command.redacted,
|
|
1850
|
+
output: command.output,
|
|
1851
|
+
limit: command.limit,
|
|
1852
|
+
});
|
|
1853
|
+
process.stdout.write(command.json ? formatDeltaExportJson(result) : formatDeltaExportHuman(result));
|
|
1854
|
+
return result.exitCode;
|
|
1855
|
+
}
|
|
1811
1856
|
if (command.subcommand === "repair") {
|
|
1812
1857
|
const result = await runDeltaRepair({
|
|
1813
1858
|
workspaceRoot: command.workspaceRoot,
|
|
@@ -1842,6 +1887,8 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
|
|
|
1842
1887
|
session: command.sessionId,
|
|
1843
1888
|
limit: command.limit,
|
|
1844
1889
|
rebuild: command.rebuild,
|
|
1890
|
+
causal: command.causal,
|
|
1891
|
+
staleProofs: command.staleProofs,
|
|
1845
1892
|
});
|
|
1846
1893
|
process.stdout.write(command.json ? formatDeltaTimelineJson(result) : formatDeltaTimelineHuman(result));
|
|
1847
1894
|
return result.exitCode;
|
package/src/forge/cli/main.ts
CHANGED
|
@@ -18,6 +18,7 @@ function formatHelp(): string {
|
|
|
18
18
|
" forge handoff --json Compact work handoff for the next external code agent",
|
|
19
19
|
" forge agent onboard --target codex --json Prepare adapter, hooks, memory, and dev snapshot",
|
|
20
20
|
" forge doctor agent --target codex --json Check adapter, hooks, and Agent Memory readiness",
|
|
21
|
+
" forge doctor delta --json Check DeltaDB writability, queue drain, redaction, and gitignore posture",
|
|
21
22
|
" forge agent ingest codex --watch --file .forge/agent/events.ndjson --json",
|
|
22
23
|
" forge docs check --json Check public docs, ReadTheDocs config, links, and local MkDocs tooling",
|
|
23
24
|
" forge docs check --build --install-venv --json Build docs strictly in a local RTD-style venv",
|
|
@@ -25,6 +26,9 @@ function formatHelp(): string {
|
|
|
25
26
|
" forge release check --allow-missing-local-release --json Gate release readiness without failing on unprepared local artifacts",
|
|
26
27
|
" forge self-host check --prepared-only --json Report compose readiness without creating deploy files",
|
|
27
28
|
" forge delta status --verbose --json Include Delta schema, lock, and aggregate count details",
|
|
29
|
+
" forge delta compact --json Compact redacted local agent queue history",
|
|
30
|
+
" forge delta prune --older-than 30d --dry-run --json Plan local Delta operational retention",
|
|
31
|
+
" forge delta export --redacted --json Export redacted Delta status, timeline, and agent memory",
|
|
28
32
|
" forge studio open <app-path> --preview-port 5174 --target codex --json",
|
|
29
33
|
" forge studio snapshot <app-path> --preview-port 5174 --target codex --probe-codex-server --json",
|
|
30
34
|
" forge studio bridge <app-path> --preview-port 5174 --target codex --studio-url http://127.0.0.1:3765 --probe-codex-server --json",
|
package/src/forge/cli/new.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { run as runGenerate } from "../compiler/orchestrator/run.ts";
|
|
|
8
8
|
import { resolvePackageManagerArgv } from "../compiler/package-manager/executor.ts";
|
|
9
9
|
import { moduleDir } from "../platform/module.ts";
|
|
10
10
|
|
|
11
|
-
export type NewTemplateName = "agent-workroom" | "b2b-support-web" | "minimal-web";
|
|
11
|
+
export type NewTemplateName = "agent-workroom" | "b2b-support-web" | "minimal-web" | "nuxt-web";
|
|
12
12
|
export type NewPackageManager = "bun" | "npm" | "pnpm" | "yarn";
|
|
13
13
|
|
|
14
14
|
export interface NewCommandOptions {
|
|
@@ -46,6 +46,8 @@ const REQUIRED_GITIGNORE_PATHS = [
|
|
|
46
46
|
".forge/cache/",
|
|
47
47
|
".forge/pglite/",
|
|
48
48
|
".forge/delta/",
|
|
49
|
+
".forge/agent/*.ndjson",
|
|
50
|
+
".forge/agent/*.history",
|
|
49
51
|
".forge/local/",
|
|
50
52
|
".forge/test-cache/",
|
|
51
53
|
".forge/test-runs/",
|