@akira-tl/forgerelay 0.6.2 → 0.7.1
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/CHANGELOG.md +26 -0
- package/capabilities/subagents/GUIDE.md +100 -40
- package/dist/activity/lifecycle.js +1 -1
- package/dist/capabilities.js +1 -1
- package/dist/capability-registry.js +34 -0
- package/dist/cli.js +80 -165
- package/dist/db/migrations.js +14 -0
- package/dist/db/schema.js +6 -0
- package/dist/server.js +29 -32
- package/dist/{local-agent-targets.js → subagents/cli-target.js} +6 -6
- package/dist/{local-agent-profiles.js → subagents/profiles.js} +13 -5
- package/dist/subagents/providers/adapters/acp.js +148 -0
- package/dist/subagents/providers/adapters/claude.js +75 -0
- package/dist/{local-agent-runtime.js → subagents/providers/adapters/codex.js} +10 -4
- package/dist/subagents/providers/adapters/opencode.js +137 -0
- package/dist/subagents/providers/adapters/pi.js +232 -0
- package/dist/{local-agent-availability.js → subagents/providers/availability.js} +24 -10
- package/dist/subagents/providers/continuation.js +11 -0
- package/dist/subagents/providers/contract.js +1 -0
- package/dist/subagents/providers/registry.js +26 -0
- package/dist/subagents/providers/shared.js +40 -0
- package/dist/subagents/sessions/capability.js +214 -0
- package/dist/subagents/sessions/delivery-mailbox.js +115 -0
- package/dist/subagents/sessions/execution.js +171 -0
- package/dist/subagents/sessions/manager.js +107 -0
- package/dist/subagents/sessions/mcp/audit.js +85 -0
- package/dist/subagents/sessions/mcp/runtime.js +19 -0
- package/dist/{local-agent-store.js → subagents/sessions/store.js} +75 -39
- package/dist/workspaces.js +3 -3
- package/docs/chatgpt-coding-workflow.md +2 -9
- package/docs/roadmap.md +42 -7
- package/package.json +2 -2
- package/scripts/release/release-gate.test.mjs +2 -2
- package/dist/local-agent-adapters.js +0 -653
- /package/dist/{local-agent-path.js → subagents/providers/path.js} +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SubagentSessionCapability } from "../capability.js";
|
|
2
|
+
export function createSubagentMcpRuntime(config, activityLifecycle, options = {}) {
|
|
3
|
+
const capability = config.subagents
|
|
4
|
+
? new SubagentSessionCapability(config, activityLifecycle, {
|
|
5
|
+
providerRunner: options.subagentProviderRunner,
|
|
6
|
+
})
|
|
7
|
+
: undefined;
|
|
8
|
+
return {
|
|
9
|
+
registryDependencies: capability
|
|
10
|
+
? {
|
|
11
|
+
subagentSession: {
|
|
12
|
+
available: true,
|
|
13
|
+
run: (input, context, runOptions) => capability.run(input, context, runOptions),
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
: {},
|
|
17
|
+
decorateResult: (workspaceId, result) => capability?.decorateResult(workspaceId, result) ?? result,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { openDatabase } from "
|
|
4
|
-
export class
|
|
3
|
+
import { openDatabase } from "../../db/client.js";
|
|
4
|
+
export class SubagentSessionStore {
|
|
5
5
|
database;
|
|
6
6
|
constructor(stateDir) {
|
|
7
7
|
this.database = openDatabase(stateDir);
|
|
@@ -27,7 +27,7 @@ export class LocalAgentStore {
|
|
|
27
27
|
.prepare("select * from local_agent_sessions order by updated_at desc")
|
|
28
28
|
.all();
|
|
29
29
|
}
|
|
30
|
-
return rows.map(
|
|
30
|
+
return rows.map(rowToSubagentSession);
|
|
31
31
|
}
|
|
32
32
|
create(input) {
|
|
33
33
|
const now = new Date().toISOString();
|
|
@@ -39,7 +39,17 @@ export class LocalAgentStore {
|
|
|
39
39
|
provider: input.provider,
|
|
40
40
|
model: input.model,
|
|
41
41
|
thinking: input.thinking,
|
|
42
|
-
status: "
|
|
42
|
+
status: input.activeRun ? "running" : "idle",
|
|
43
|
+
...(input.activeRun
|
|
44
|
+
? {
|
|
45
|
+
activeRun: {
|
|
46
|
+
id: input.activeRun.id,
|
|
47
|
+
status: "running",
|
|
48
|
+
...(input.activeRun.activityId ? { activityId: input.activeRun.activityId } : {}),
|
|
49
|
+
startedAt: input.activeRun.startedAt,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
43
53
|
createdAt: now,
|
|
44
54
|
updatedAt: now,
|
|
45
55
|
};
|
|
@@ -52,11 +62,21 @@ export class LocalAgentStore {
|
|
|
52
62
|
provider,
|
|
53
63
|
model,
|
|
54
64
|
thinking,
|
|
65
|
+
provider_session_id,
|
|
55
66
|
status,
|
|
67
|
+
active_run_id,
|
|
68
|
+
active_activity_id,
|
|
69
|
+
active_run_started_at,
|
|
70
|
+
latest_run_id,
|
|
71
|
+
latest_run_outcome,
|
|
72
|
+
latest_run_finished_at,
|
|
73
|
+
latest_response,
|
|
74
|
+
error,
|
|
75
|
+
hook_reports_json,
|
|
56
76
|
created_at,
|
|
57
77
|
updated_at
|
|
58
|
-
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
59
|
-
.run(record.id, record.workspaceId ?? null, record.workspaceRoot, record.profileName, record.provider, record.model ?? null, record.thinking ?? null, record.status, record.createdAt, record.updatedAt);
|
|
78
|
+
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, null, null, null, ?, ?)`)
|
|
79
|
+
.run(record.id, record.workspaceId ?? null, record.workspaceRoot, record.profileName, record.provider, record.model ?? null, record.thinking ?? null, null, record.status, record.activeRun?.id ?? null, record.activeRun?.activityId ?? null, record.activeRun?.startedAt ?? null, null, null, null, record.createdAt, record.updatedAt);
|
|
60
80
|
return record;
|
|
61
81
|
}
|
|
62
82
|
get(idOrPrefix) {
|
|
@@ -66,13 +86,23 @@ export class LocalAgentStore {
|
|
|
66
86
|
limit 1`)
|
|
67
87
|
.get(idOrPrefix, idOrPrefix);
|
|
68
88
|
if (exact)
|
|
69
|
-
return
|
|
89
|
+
return rowToSubagentSession(exact);
|
|
70
90
|
const matches = this.database.sqlite
|
|
71
91
|
.prepare(`select * from local_agent_sessions
|
|
72
92
|
where id like ? escape '\\' or provider_session_id like ? escape '\\'
|
|
73
93
|
order by updated_at desc`)
|
|
74
94
|
.all(`${escapeLike(idOrPrefix)}%`, `${escapeLike(idOrPrefix)}%`);
|
|
75
|
-
return matches.length === 1 ?
|
|
95
|
+
return matches.length === 1 ? rowToSubagentSession(matches[0]) : undefined;
|
|
96
|
+
}
|
|
97
|
+
getInScope(idOrPrefix, scope) {
|
|
98
|
+
const session = this.get(idOrPrefix);
|
|
99
|
+
if (!session)
|
|
100
|
+
return undefined;
|
|
101
|
+
if (scope.workspaceId && session.workspaceId !== scope.workspaceId)
|
|
102
|
+
return undefined;
|
|
103
|
+
if (scope.workspaceRoot && session.workspaceRoot !== resolve(scope.workspaceRoot))
|
|
104
|
+
return undefined;
|
|
105
|
+
return session;
|
|
76
106
|
}
|
|
77
107
|
update(id, patch) {
|
|
78
108
|
const current = this.getById(id);
|
|
@@ -93,12 +123,18 @@ export class LocalAgentStore {
|
|
|
93
123
|
thinking = ?,
|
|
94
124
|
provider_session_id = ?,
|
|
95
125
|
status = ?,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
126
|
+
active_run_id = ?,
|
|
127
|
+
active_activity_id = ?,
|
|
128
|
+
active_run_started_at = ?,
|
|
129
|
+
latest_run_id = ?,
|
|
130
|
+
latest_run_outcome = ?,
|
|
131
|
+
latest_run_finished_at = ?,
|
|
132
|
+
latest_response = null,
|
|
133
|
+
error = null,
|
|
134
|
+
hook_reports_json = null,
|
|
99
135
|
updated_at = ?
|
|
100
136
|
where id = ?`)
|
|
101
|
-
.run(updated.workspaceId ?? null, resolve(updated.workspaceRoot), updated.profileName, updated.provider, updated.model ?? null, updated.thinking ?? null, updated.providerSessionId ?? null, updated.status, updated.
|
|
137
|
+
.run(updated.workspaceId ?? null, resolve(updated.workspaceRoot), updated.profileName, updated.provider, updated.model ?? null, updated.thinking ?? null, updated.providerSessionId ?? null, updated.status, updated.activeRun?.id ?? null, updated.activeRun?.activityId ?? null, updated.activeRun?.startedAt ?? null, updated.latestRun?.id ?? null, updated.latestRun && updated.latestRun.status !== "running" ? updated.latestRun.status : null, updated.latestRun?.finishedAt ?? null, updated.updatedAt, updated.id);
|
|
102
138
|
return updated;
|
|
103
139
|
}
|
|
104
140
|
close() {
|
|
@@ -108,13 +144,29 @@ export class LocalAgentStore {
|
|
|
108
144
|
const row = this.database.sqlite
|
|
109
145
|
.prepare("select * from local_agent_sessions where id = ?")
|
|
110
146
|
.get(id);
|
|
111
|
-
return row ?
|
|
147
|
+
return row ? rowToSubagentSession(row) : undefined;
|
|
112
148
|
}
|
|
113
149
|
}
|
|
114
|
-
export function
|
|
115
|
-
return new
|
|
150
|
+
export function createSubagentSessionStore(config) {
|
|
151
|
+
return new SubagentSessionStore(config.stateDir);
|
|
116
152
|
}
|
|
117
|
-
function
|
|
153
|
+
function rowToSubagentSession(row) {
|
|
154
|
+
const activeRun = row.active_run_id
|
|
155
|
+
? {
|
|
156
|
+
id: row.active_run_id,
|
|
157
|
+
status: "running",
|
|
158
|
+
...(row.active_activity_id ? { activityId: row.active_activity_id } : {}),
|
|
159
|
+
...(row.active_run_started_at ? { startedAt: row.active_run_started_at } : {}),
|
|
160
|
+
}
|
|
161
|
+
: undefined;
|
|
162
|
+
const latestOutcome = readOutcome(row.latest_run_outcome);
|
|
163
|
+
const latestRun = row.latest_run_id && latestOutcome
|
|
164
|
+
? {
|
|
165
|
+
id: row.latest_run_id,
|
|
166
|
+
status: latestOutcome,
|
|
167
|
+
...(row.latest_run_finished_at ? { finishedAt: row.latest_run_finished_at } : {}),
|
|
168
|
+
}
|
|
169
|
+
: undefined;
|
|
118
170
|
return {
|
|
119
171
|
id: row.id,
|
|
120
172
|
workspaceId: row.workspace_id ?? undefined,
|
|
@@ -124,34 +176,18 @@ function rowToLocalAgentRecord(row) {
|
|
|
124
176
|
model: row.model ?? undefined,
|
|
125
177
|
thinking: row.thinking ?? undefined,
|
|
126
178
|
providerSessionId: row.provider_session_id ?? undefined,
|
|
127
|
-
status:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
hookReports: parseHookReports(row.hook_reports_json),
|
|
179
|
+
status: activeRun || row.status === "starting" || row.status === "running" ? "running" : "idle",
|
|
180
|
+
...(activeRun ? { activeRun } : {}),
|
|
181
|
+
...(latestRun ? { latestRun } : {}),
|
|
131
182
|
createdAt: row.created_at,
|
|
132
183
|
updatedAt: row.updated_at,
|
|
133
184
|
};
|
|
134
185
|
}
|
|
135
|
-
function
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
138
|
-
try {
|
|
139
|
-
const parsed = JSON.parse(value);
|
|
140
|
-
return Array.isArray(parsed) ? parsed : undefined;
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
function readStatus(status) {
|
|
147
|
-
if (status === "starting" ||
|
|
148
|
-
status === "running" ||
|
|
149
|
-
status === "idle" ||
|
|
150
|
-
status === "error" ||
|
|
151
|
-
status === "stopped") {
|
|
152
|
-
return status;
|
|
186
|
+
function readOutcome(value) {
|
|
187
|
+
if (value === "succeeded" || value === "failed" || value === "cancelled" || value === "interrupted") {
|
|
188
|
+
return value;
|
|
153
189
|
}
|
|
154
|
-
return
|
|
190
|
+
return undefined;
|
|
155
191
|
}
|
|
156
192
|
function escapeLike(value) {
|
|
157
193
|
return value.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
|
package/dist/workspaces.js
CHANGED
|
@@ -7,7 +7,7 @@ import { HookRunner } from "./hooks.js";
|
|
|
7
7
|
import { closeManagedWorktree, createManagedWorktree, resolveManagedWorktreeBase, } from "./git-worktrees.js";
|
|
8
8
|
import { AccessDeniedError, assertAllowedPath, isPathInsideRoot, resolveAllowedPath, } from "./roots.js";
|
|
9
9
|
import { loadWorkspaceSkills, markSkillActivated, resolveSkillReadPath, } from "./skills.js";
|
|
10
|
-
import {
|
|
10
|
+
import { loadSubagentProfiles, } from "./subagents/profiles.js";
|
|
11
11
|
const WORKSPACE_STALE_REMINDER_MS = 2 * 24 * 60 * 60 * 1_000;
|
|
12
12
|
const WORKSPACE_SESSION_IDLE_TTL_MS = 30 * 24 * 60 * 60 * 1_000;
|
|
13
13
|
const WORKSPACE_GC_INTERVAL_MS = 60 * 60 * 1_000;
|
|
@@ -634,7 +634,7 @@ export class WorkspaceRegistry {
|
|
|
634
634
|
async reusedWorkspaceContext(workspace) {
|
|
635
635
|
Object.assign(workspace, this.loadSkillsForWorkspace(workspace.root));
|
|
636
636
|
workspace.capabilityGuides = loadCapabilityGuides(this.config);
|
|
637
|
-
workspace.agentProfiles = await
|
|
637
|
+
workspace.agentProfiles = await loadSubagentProfiles(this.config, workspace.root);
|
|
638
638
|
workspace.scannedInstructionDirs.clear();
|
|
639
639
|
workspace.knownInstructionPathsByDir.clear();
|
|
640
640
|
workspace.loadedInstructionRealPaths.clear();
|
|
@@ -800,7 +800,7 @@ export class WorkspaceRegistry {
|
|
|
800
800
|
worktree: input.worktree,
|
|
801
801
|
...this.loadSkillsForWorkspace(input.root),
|
|
802
802
|
capabilityGuides: loadCapabilityGuides(this.config),
|
|
803
|
-
agentProfiles: await
|
|
803
|
+
agentProfiles: await loadSubagentProfiles(this.config, input.root),
|
|
804
804
|
activatedSkillDirs: new Set(),
|
|
805
805
|
activatedCapabilityGuideDirs: new Set(),
|
|
806
806
|
scannedInstructionDirs: new Set(),
|
|
@@ -235,16 +235,9 @@ ForgeRelay-owned `subagents` capability guide when delegation is actually needed
|
|
|
235
235
|
new setups. Existing user-authored or previously seeded Skills remain normal
|
|
236
236
|
user configuration and are not deleted.
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
Host 正常委派通过现有 `capability` Gateway 中的 `subagent.session` 完成,不增加新的 Core MCP tool。支持的生命周期操作包括 `start`、`resume`、`status`、`list`、`stop` 和 `delete`;具体参数与 provider continuation 能力以 `subagents` capability guide 为准。
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
forgerelay agents ls
|
|
242
|
-
forgerelay agents run <profile-or-provider-or-id> "<prompt>"
|
|
243
|
-
forgerelay agents show <id>
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
A first-class MCP subagent interface is planned so this CLI indirection can be
|
|
247
|
-
removed.
|
|
240
|
+
`forgerelay agents` CLI 继续保留给本地诊断和兼容场景,但 first-class MCP 路径不会通过 `bash -> forgerelay agents ...` 间接执行。Subagent Session 绑定实际 Execution Workspace,provider 原生 session/thread 保存 conversation history,ForgeRelay 只持久化必要的 ownership、continuation 和当前执行协调元数据。
|
|
248
241
|
|
|
249
242
|
## Tool modes
|
|
250
243
|
|
package/docs/roadmap.md
CHANGED
|
@@ -250,16 +250,51 @@ fake-LSP coverage remains the primary cross-platform protocol/lifecycle gate, wh
|
|
|
250
250
|
`rust-analyzer`, `gopls`, and `clangd` only when those external executables are
|
|
251
251
|
already present and otherwise reports explicit skips without installing them.
|
|
252
252
|
|
|
253
|
-
## 0.5 —
|
|
253
|
+
## 0.5 — Durable Activity and batch execution
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
0.5 established the execution-history substrate used by the later MCP App and
|
|
256
|
+
multi-workspace features:
|
|
257
|
+
|
|
258
|
+
- immutable local Audit Events and restart-safe Activity Records;
|
|
259
|
+
- durable Bash output plus late `bash_result` delivery;
|
|
260
|
+
- Host Turn snapshots with lazy detail/output queries for MCP Apps;
|
|
261
|
+
- native bulk read/edit/delete and heterogeneous `batch.execute` orchestration;
|
|
262
|
+
- parent/child Activity relationships and bounded capability batch policies;
|
|
263
|
+
- Windows-safe Activity/SQLite cleanup and release-test hardening.
|
|
264
|
+
|
|
265
|
+
Activity remains an observation of semantic ForgeRelay operations rather than a
|
|
266
|
+
second task/session runtime. Files, processes, Git state, and audit truth continue
|
|
267
|
+
to belong to the Workspace that actually executes the operation.
|
|
268
|
+
|
|
269
|
+
## 0.6 — Host UI, Workspace Relay, and Composite Workspace
|
|
270
|
+
|
|
271
|
+
0.6 turned the Activity substrate into a Host-facing multi-environment workflow:
|
|
258
272
|
|
|
259
|
-
|
|
273
|
+
- **0.6.0** — one ForgeRelay Panel per Host Turn, MCP Inspector/debug lifecycle,
|
|
274
|
+
virtual `skills://` loading, bounded process waits, and release-candidate support;
|
|
275
|
+
- **0.6.1** — Workspace Relay, authenticated direct/SSH-routed remote execution,
|
|
276
|
+
restart-safe relay identity/routes, and remote Activity/bootstrap forwarding;
|
|
277
|
+
- **0.6.2** — Composite Workspace as a first-class Workspace kind with named local,
|
|
278
|
+
managed-worktree, and relayed members, explicit member routing, aggregated
|
|
279
|
+
Composite Activity, and `close_workspace` dissolution that preserves members.
|
|
280
|
+
|
|
281
|
+
The 0.6 contract keeps execution ownership explicit: Gateway ForgeRelay presents
|
|
282
|
+
and routes; the selected member Workspace and its Execution ForgeRelay own files,
|
|
283
|
+
Git state, processes, Hooks, Skills, Language services, Activity, and Audit facts.
|
|
284
|
+
Workspace Relay is not file synchronization or failover, and Composite Workspace
|
|
285
|
+
never silently chooses a member.
|
|
286
|
+
|
|
287
|
+
## Later: first-class subagent MCP
|
|
288
|
+
|
|
289
|
+
ForgeRelay already owns provider adapters and resumable local agent sessions. A
|
|
290
|
+
future release may remove the current `bash -> forgerelay agents ...` indirection
|
|
291
|
+
for MCP hosts.
|
|
260
292
|
|
|
261
|
-
|
|
262
|
-
|
|
293
|
+
First-class subagent operations should reuse the Capability Gateway rather than
|
|
294
|
+
add another top-level MCP tool. The parent agent should continue choosing from
|
|
295
|
+
available provider/profile metadata while ForgeRelay owns provider-backed worker
|
|
296
|
+
lifecycle state. This remains provider-backed delegation, not an attempt to
|
|
297
|
+
emulate a Host-native subagent implementation.
|
|
263
298
|
|
|
264
299
|
## Worktree and history refinements
|
|
265
300
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akira-tl/forgerelay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Local development control plane for MCP coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/Akira-TL/forgerelay#readme",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"release:publish": "node scripts/release/publish.mjs",
|
|
48
48
|
"postinstall": "node scripts/fix-node-pty-permissions.mjs",
|
|
49
49
|
"start": "node dist/cli.js serve",
|
|
50
|
-
"test": "node --test scripts/debug/runtime.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/release-version.test.mjs && tsx src/oauth/router.test.ts && tsx src/remote-auth-cli.test.ts && tsx src/remote-ssh-auth-cli.test.ts && tsx src/remote-workspace-relay.test.ts && tsx src/remote-workspace-relay-process.test.ts && tsx src/config.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/logger.test.ts && tsx src/proxy-trust.test.ts && tsx src/mcp-app-template.test.ts && tsx src/hooks.test.ts && tsx src/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/workspace-lifecycle-app.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/
|
|
50
|
+
"test": "node --test scripts/debug/runtime.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/release-version.test.mjs && tsx src/oauth/router.test.ts && tsx src/remote-auth-cli.test.ts && tsx src/remote-ssh-auth-cli.test.ts && tsx src/remote-workspace-relay.test.ts && tsx src/remote-workspace-relay-process.test.ts && tsx src/config.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/logger.test.ts && tsx src/proxy-trust.test.ts && tsx src/mcp-app-template.test.ts && tsx src/hooks.test.ts && tsx src/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/workspace-lifecycle-app.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/subagents/providers/adapters/codex.test.ts && tsx src/subagents/providers/registry.test.ts && tsx src/subagents/providers/availability.test.ts && tsx src/subagents/profiles.test.ts && tsx src/subagents/cli-target.test.ts && tsx src/subagents/sessions/store.test.ts && tsx src/subagents/sessions/manager.test.ts && tsx src/subagents/sessions/mcp/capability.server.test.ts && tsx src/subagents/sessions/mcp/continuation.server.test.ts && tsx src/roots.test.ts && tsx src/file-mutations.test.ts && tsx src/operations/edit-preflight.test.ts && tsx src/skills.test.ts && tsx src/db/migrations.test.ts && tsx src/workspace-store.test.ts && tsx src/activity/audit-store.test.ts && tsx src/activity/bash-output-store.test.ts && tsx src/activity/lifecycle.test.ts && tsx src/activity/query-service.test.ts && tsx src/operations/core-operation-executor.test.ts && tsx src/operations/bulk-mutation.test.ts && tsx src/operations/batch/scheduler.test.ts && tsx src/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
|
|
51
51
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
52
52
|
"release:check": "node scripts/release-version.mjs check",
|
|
53
53
|
"release:tag-check": "node scripts/release-version.mjs tag",
|
|
@@ -79,7 +79,7 @@ test("release runtime and local parity share the checked-in Node contract", asyn
|
|
|
79
79
|
test("cloud verification produces one reusable npm package on Linux", async () => {
|
|
80
80
|
const workflow = await readFile(resolve(repoRoot, ".github/workflows/ci.yml"), "utf8");
|
|
81
81
|
assert.match(workflow, /if:\s*runner\.os == 'Linux'[\s\S]*run:\s*npm run release:pack/);
|
|
82
|
-
assert.match(workflow, /uses:\s*actions\/upload-artifact@
|
|
82
|
+
assert.match(workflow, /uses:\s*actions\/upload-artifact@v7/);
|
|
83
83
|
assert.match(workflow, /name:\s*npm-package/);
|
|
84
84
|
assert.match(workflow, /include-hidden-files:\s*true/);
|
|
85
85
|
assert.match(workflow, /overwrite:\s*true/);
|
|
@@ -89,7 +89,7 @@ test("release workflow is tag-only and promotes the verified npm artifact withou
|
|
|
89
89
|
const workflow = await readFile(resolve(repoRoot, ".github/workflows/release.yml"), "utf8");
|
|
90
90
|
assert.doesNotMatch(workflow, /workflow_dispatch:/);
|
|
91
91
|
assert.match(workflow, /needs:\s*verify/);
|
|
92
|
-
assert.match(workflow, /uses:\s*actions\/download-artifact@
|
|
92
|
+
assert.match(workflow, /uses:\s*actions\/download-artifact@v7/);
|
|
93
93
|
assert.match(workflow, /name:\s*npm-package/);
|
|
94
94
|
assert.match(workflow, /run:\s*npm run release:publish/);
|
|
95
95
|
assert.match(workflow, /npm install --global npm@11\.19\.1/);
|