frely-cli 0.7.1 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +25 -35
  2. package/README.zh-CN.md +25 -35
  3. package/dist/agent/agent-service.d.ts +77 -0
  4. package/dist/agent/agent-service.js +348 -0
  5. package/dist/agent/agent-service.js.map +1 -0
  6. package/dist/agent/app-install.d.ts +49 -0
  7. package/dist/agent/app-install.js +133 -0
  8. package/dist/agent/app-install.js.map +1 -0
  9. package/dist/agent/app-key.d.ts +14 -0
  10. package/dist/agent/app-key.js +46 -0
  11. package/dist/agent/app-key.js.map +1 -0
  12. package/dist/agent/compose.d.ts +23 -0
  13. package/dist/agent/compose.js +42 -0
  14. package/dist/agent/compose.js.map +1 -0
  15. package/dist/agent/ops-server.d.ts +18 -0
  16. package/dist/agent/ops-server.js +175 -0
  17. package/dist/agent/ops-server.js.map +1 -0
  18. package/dist/agent/ops-stdio.d.ts +5 -0
  19. package/dist/agent/ops-stdio.js +47 -0
  20. package/dist/agent/ops-stdio.js.map +1 -0
  21. package/dist/agent/ops.d.ts +25 -0
  22. package/dist/agent/ops.js +82 -0
  23. package/dist/agent/ops.js.map +1 -0
  24. package/dist/agent/protocol.d.ts +72 -0
  25. package/dist/agent/protocol.js +195 -0
  26. package/dist/agent/protocol.js.map +1 -0
  27. package/dist/agent/supervisor.d.ts +80 -0
  28. package/dist/agent/supervisor.js +278 -0
  29. package/dist/agent/supervisor.js.map +1 -0
  30. package/dist/agent/task-store.d.ts +82 -0
  31. package/dist/agent/task-store.js +220 -0
  32. package/dist/agent/task-store.js.map +1 -0
  33. package/dist/agent/tool-executor.d.ts +28 -0
  34. package/dist/agent/tool-executor.js +113 -0
  35. package/dist/agent/tool-executor.js.map +1 -0
  36. package/dist/agent/worktrees.d.ts +35 -0
  37. package/dist/agent/worktrees.js +143 -0
  38. package/dist/agent/worktrees.js.map +1 -0
  39. package/dist/agent-help.d.ts +198 -210
  40. package/dist/agent-help.js +47 -62
  41. package/dist/agent-help.js.map +1 -1
  42. package/dist/cloud.d.ts +1 -1
  43. package/dist/cloud.js +6 -13
  44. package/dist/cloud.js.map +1 -1
  45. package/dist/device/protocol.d.ts +11 -2
  46. package/dist/device/protocol.js +18 -2
  47. package/dist/device/protocol.js.map +1 -1
  48. package/dist/device/relay-client.d.ts +10 -1
  49. package/dist/device/relay-client.js +38 -11
  50. package/dist/device/relay-client.js.map +1 -1
  51. package/dist/diagnostics.js +12 -4
  52. package/dist/diagnostics.js.map +1 -1
  53. package/dist/index.js +195 -141
  54. package/dist/index.js.map +1 -1
  55. package/dist/key-budget.js +2 -2
  56. package/dist/key-budget.js.map +1 -1
  57. package/dist/mcp-authorization.js +9 -7
  58. package/dist/mcp-authorization.js.map +1 -1
  59. package/dist/mcp-command.d.ts +12 -4
  60. package/dist/mcp-command.js +54 -48
  61. package/dist/mcp-command.js.map +1 -1
  62. package/dist/provider/state.d.ts +2 -0
  63. package/dist/provider/state.js +1 -0
  64. package/dist/provider/state.js.map +1 -1
  65. package/dist/runtime/mcp-lease.js +1 -1
  66. package/dist/runtime/mcp-lease.js.map +1 -1
  67. package/dist/runtime/mcp.d.ts +139 -0
  68. package/dist/runtime/mcp.js +30 -0
  69. package/dist/runtime/mcp.js.map +1 -1
  70. package/dist/runtime/relay-agent.d.ts +25 -0
  71. package/dist/runtime/relay-agent.js +63 -0
  72. package/dist/runtime/relay-agent.js.map +1 -0
  73. package/dist/runtime/relay-mcp.d.ts +3 -1
  74. package/dist/runtime/relay-mcp.js +6 -1
  75. package/dist/runtime/relay-mcp.js.map +1 -1
  76. package/dist/runtime/relay-session.d.ts +2 -2
  77. package/dist/runtime/relay-session.js +1 -1
  78. package/dist/runtime/relay-session.js.map +1 -1
  79. package/dist/runtime/sandbox.d.ts +2 -0
  80. package/dist/runtime/sandbox.js +13 -0
  81. package/dist/runtime/sandbox.js.map +1 -1
  82. package/dist/runtime/workspace-registry.js +1 -1
  83. package/dist/skill/access.d.ts +4 -2
  84. package/dist/skill/access.js +7 -3
  85. package/dist/skill/access.js.map +1 -1
  86. package/dist/upgrade/installation.js +1 -1
  87. package/dist/upgrade/installation.js.map +1 -1
  88. package/dist/workspace-command.d.ts +1 -1
  89. package/dist/workspace-command.js +2 -2
  90. package/dist/workspace-command.js.map +1 -1
  91. package/package.json +1 -1
@@ -0,0 +1,348 @@
1
+ /**
2
+ * AgentService: orchestrates agent tasks end-to-end — validation, worktrees,
3
+ * the agent host process, events, budget, and the merge workflow. This is the
4
+ * single implementation behind the GUI, the device relay (`method: "agent"`),
5
+ * and the `frely app` CLI.
6
+ */
7
+ import { randomBytes } from "node:crypto";
8
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
9
+ import { dirname } from "node:path";
10
+ import { FairRwScheduler } from "../runtime/scheduler.js";
11
+ import { AgentToolExecutor, toolKindFromMethod } from "./tool-executor.js";
12
+ import { AGENT_DEFAULT_MAX_COST_USD, AGENT_MAX_COST_USD_LIMIT, AGENT_DEFAULT_MAX_CONCURRENT_TASKS, AGENT_START_RATE_LIMIT_PER_MINUTE, AGENT_TASK_MAX_GOAL_BYTES, AgentStoreError, agentConfigPath, isTerminalStatus, nextRuntimeStatus, TaskStore, } from "./task-store.js";
13
+ import { newTaskId } from "./protocol.js";
14
+ import { branchNameForTask, createTaskWorktree, mergeTaskBranch, removeTaskWorktree, taskDiff, WorktreeError } from "./worktrees.js";
15
+ export class AgentServiceError extends Error {
16
+ code;
17
+ constructor(code, message) {
18
+ super(message ?? code);
19
+ this.code = code;
20
+ this.name = "AgentServiceError";
21
+ }
22
+ }
23
+ export const DEFAULT_AGENT_CONFIG = {
24
+ schemaVersion: 1,
25
+ remoteControlEnabled: false,
26
+ defaultMaxCostUsd: AGENT_DEFAULT_MAX_COST_USD,
27
+ maxCostUsdLimit: AGENT_MAX_COST_USD_LIMIT,
28
+ maxConcurrentTasks: AGENT_DEFAULT_MAX_CONCURRENT_TASKS,
29
+ };
30
+ export async function loadAgentConfig(env = process.env) {
31
+ try {
32
+ const raw = JSON.parse(await readFile(agentConfigPath(env), "utf8"));
33
+ return {
34
+ schemaVersion: 1,
35
+ remoteControlEnabled: raw.remoteControlEnabled === true,
36
+ defaultMaxCostUsd: boundedCost(raw.defaultMaxCostUsd, AGENT_DEFAULT_MAX_COST_USD),
37
+ maxCostUsdLimit: boundedCost(raw.maxCostUsdLimit, AGENT_MAX_COST_USD_LIMIT),
38
+ maxConcurrentTasks: boundedConcurrency(raw.maxConcurrentTasks),
39
+ };
40
+ }
41
+ catch {
42
+ return { ...DEFAULT_AGENT_CONFIG };
43
+ }
44
+ }
45
+ export async function saveAgentConfig(config, env = process.env) {
46
+ const path = agentConfigPath(env);
47
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
48
+ const tmp = `${path}.${randomBytes(8).toString("hex")}.tmp`;
49
+ await writeFile(tmp, `${JSON.stringify(config, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
50
+ await rename(tmp, path);
51
+ }
52
+ function boundedCost(value, fallback) {
53
+ return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= AGENT_MAX_COST_USD_LIMIT ? value : fallback;
54
+ }
55
+ function boundedConcurrency(value) {
56
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 && value <= 4 ? value : AGENT_DEFAULT_MAX_CONCURRENT_TASKS;
57
+ }
58
+ export class AgentService {
59
+ deps;
60
+ executors = new Map();
61
+ scheduler = new FairRwScheduler(4);
62
+ credentialsSent = false;
63
+ budgetCancels = new Set();
64
+ _supervisor = null;
65
+ constructor(deps) {
66
+ this.deps = deps;
67
+ }
68
+ supervisor() {
69
+ this._supervisor ??= this.deps.resolveSupervisor();
70
+ return this._supervisor;
71
+ }
72
+ async startTask(input) {
73
+ const goal = typeof input.goal === "string" ? input.goal.trim() : "";
74
+ if (goal.length === 0 || Buffer.byteLength(goal) > AGENT_TASK_MAX_GOAL_BYTES)
75
+ throw new AgentServiceError("invalid_args", "goal must be 1..65536 bytes.");
76
+ if (typeof input.workspace !== "string" || input.workspace.length === 0)
77
+ throw new AgentServiceError("invalid_args", "workspace is required.");
78
+ const config = (await this.deps.config?.()) ?? DEFAULT_AGENT_CONFIG;
79
+ if (input.source.kind !== "gui" && !config.remoteControlEnabled)
80
+ throw new AgentServiceError("remote_control_disabled", "Run `frely app remote enable` first.");
81
+ const maxCostUsd = boundedCost(input.maxCostUsd ?? config.defaultMaxCostUsd, config.defaultMaxCostUsd);
82
+ const tasks = await this.deps.store.list();
83
+ const now = Date.now();
84
+ const active = tasks.filter((task) => !isTerminalStatus(task.status));
85
+ if (active.length >= config.maxConcurrentTasks)
86
+ throw new AgentServiceError("too_many_tasks");
87
+ const recentStarts = tasks.filter((task) => now - Date.parse(task.createdAt) < 60_000).length;
88
+ if (recentStarts >= AGENT_START_RATE_LIMIT_PER_MINUTE)
89
+ throw new AgentServiceError("rate_limited");
90
+ let worktree;
91
+ const taskId = newTaskId();
92
+ try {
93
+ worktree = await createTaskWorktree(taskId, input.workspace);
94
+ }
95
+ catch (error) {
96
+ if (error instanceof WorktreeError) {
97
+ if (error.code === "not_a_git_repo")
98
+ throw new AgentServiceError("workspace_not_git_repo");
99
+ if (error.code === "dirty_workspace")
100
+ throw new AgentServiceError("workspace_dirty");
101
+ }
102
+ throw error;
103
+ }
104
+ const id = taskId;
105
+ const record = {
106
+ id,
107
+ source: input.source,
108
+ workspace: input.workspace,
109
+ worktreePath: worktree.path,
110
+ branch: worktree.branch,
111
+ baseBranch: worktree.baseBranch,
112
+ baseCommit: worktree.baseCommit,
113
+ goal,
114
+ model: input.model ?? null,
115
+ maxCostUsd,
116
+ status: "queued",
117
+ mergeStatus: "none",
118
+ usage: { inputTokens: 0, outputTokens: 0, costUsd: 0 },
119
+ error: null,
120
+ mergeRequest: null,
121
+ approval: null,
122
+ createdAt: new Date().toISOString(),
123
+ updatedAt: new Date().toISOString(),
124
+ settledAt: null,
125
+ };
126
+ await this.deps.store.create(record);
127
+ try {
128
+ const connection = await this.ensureHostWithCredentials();
129
+ this.executors.set(id, new AgentToolExecutor(worktree.path, this.scheduler));
130
+ await connection.request("task.start", {
131
+ taskId: id,
132
+ worktreePath: worktree.path,
133
+ goal,
134
+ model: input.model ?? null,
135
+ budgetUsd: maxCostUsd,
136
+ baseBranch: worktree.baseBranch,
137
+ baseCommit: worktree.baseCommit,
138
+ });
139
+ }
140
+ catch (error) {
141
+ this.executors.delete(id);
142
+ await this.deps.store.update(id, (task) => ({ ...task, status: "failed", error: error instanceof Error ? error.message : "task start failed", settledAt: new Date().toISOString() }));
143
+ await this.deps.store.appendEvent(id, { type: "status", status: "failed", detail: "Agent host unavailable." });
144
+ if (error instanceof AgentServiceError)
145
+ throw error;
146
+ throw new AgentServiceError("host_unavailable", error instanceof Error ? error.message : "agent host unavailable");
147
+ }
148
+ return (await this.deps.store.read(id));
149
+ }
150
+ async listTasks(workspace) {
151
+ const tasks = await this.deps.store.list();
152
+ return workspace ? tasks.filter((task) => task.workspace === workspace) : tasks;
153
+ }
154
+ async getTask(id) {
155
+ return this.deps.store.read(id);
156
+ }
157
+ async getEvents(id, cursor = 0) {
158
+ return this.deps.store.readEvents(id, cursor);
159
+ }
160
+ async sendMessage(id, message) {
161
+ if (typeof message !== "string" || message.length === 0 || message.length > 64 * 1024)
162
+ throw new AgentServiceError("invalid_args");
163
+ const task = await this.deps.store.read(id);
164
+ if (task.status !== "running" && task.status !== "waiting_input")
165
+ throw new AgentServiceError("invalid_state", `Cannot send a message to a ${task.status} task.`);
166
+ const connection = await this.supervisor().ensureHost();
167
+ await connection.request("task.message", { taskId: id, message });
168
+ }
169
+ async cancelTask(id) {
170
+ const task = await this.deps.store.read(id);
171
+ if (isTerminalStatus(task.status))
172
+ return task;
173
+ if (task.status === "queued" && !this.executors.has(id)) {
174
+ return this.settleCancelled(id, "Cancelled before start.");
175
+ }
176
+ try {
177
+ const connection = await this.supervisor().ensureHost();
178
+ await connection.request("task.cancel", { taskId: id, reason: "User requested cancellation." }, 10_000);
179
+ }
180
+ catch (error) {
181
+ this.debug("agent.task.cancel_failed", id, error);
182
+ return this.settleCancelled(id, "Cancelled (host unreachable).");
183
+ }
184
+ return this.deps.store.read(id);
185
+ }
186
+ async settleCancelled(id, detail) {
187
+ this.executors.delete(id);
188
+ const record = await this.deps.store.update(id, (task) => ({ ...task, status: "cancelled", settledAt: new Date().toISOString() }));
189
+ await this.deps.store.appendEvent(id, { type: "status", status: "cancelled", detail });
190
+ return record;
191
+ }
192
+ async getDiff(id, path) {
193
+ const task = await this.deps.store.read(id);
194
+ try {
195
+ return await taskDiff(id, task.workspace, path);
196
+ }
197
+ catch (error) {
198
+ if (error instanceof WorktreeError && error.code === "not_a_git_repo")
199
+ throw new AgentServiceError("workspace_not_git_repo");
200
+ throw new AgentServiceError("internal", error instanceof Error ? error.message : "diff failed");
201
+ }
202
+ }
203
+ async requestMerge(id, note) {
204
+ const task = await this.deps.store.read(id);
205
+ if (task.status !== "completed")
206
+ throw new AgentServiceError("invalid_state", "Only completed tasks can request a merge.");
207
+ if (task.mergeStatus !== "none")
208
+ throw new AgentServiceError("invalid_state", `Merge already ${task.mergeStatus}.`);
209
+ return this.deps.store.update(id, (record) => ({
210
+ ...record,
211
+ mergeStatus: "merge_requested",
212
+ mergeRequest: { requestedAt: new Date().toISOString(), ...(note !== undefined && note.length > 0 ? { note: note.slice(0, 2048) } : {}) },
213
+ }));
214
+ }
215
+ async approveMerge(id, approvedBy) {
216
+ const task = await this.deps.store.read(id);
217
+ if (task.mergeStatus !== "merge_requested")
218
+ throw new AgentServiceError("invalid_state", `Merge state is ${task.mergeStatus}.`);
219
+ const approved = await this.deps.store.update(id, (record) => ({
220
+ ...record,
221
+ mergeStatus: "approved",
222
+ approval: { approvedAt: new Date().toISOString(), approvedBy },
223
+ }));
224
+ const outcome = await mergeTaskBranch(id, task.workspace);
225
+ if (outcome.status === "merged") {
226
+ await removeTaskWorktree(id, task.workspace).catch(() => undefined);
227
+ return this.deps.store.update(id, (record) => ({ ...record, mergeStatus: "merged" }));
228
+ }
229
+ return this.deps.store.update(id, (record) => ({ ...record, mergeStatus: "merge_conflict", error: outcome.detail }));
230
+ }
231
+ async discardTask(id) {
232
+ const task = await this.deps.store.read(id);
233
+ if (task.mergeStatus === "merged" || task.mergeStatus === "discarded")
234
+ throw new AgentServiceError("invalid_state", `Task already ${task.mergeStatus}.`);
235
+ await removeTaskWorktree(id, task.workspace).catch(() => undefined);
236
+ this.executors.delete(id);
237
+ return this.deps.store.update(id, (record) => ({ ...record, mergeStatus: "discarded" }));
238
+ }
239
+ async stopHost() {
240
+ for (const executor of this.executors.values())
241
+ executor.dispose();
242
+ this.executors.clear();
243
+ await this.supervisor().stop();
244
+ }
245
+ status() {
246
+ return { host: this.supervisor().status() };
247
+ }
248
+ // --- host wiring ---------------------------------------------------------
249
+ async ensureHostWithCredentials() {
250
+ const connection = await this.supervisor().ensureHost();
251
+ if (!this.credentialsSent) {
252
+ const credentials = this.deps.modelCredentials?.();
253
+ if (credentials)
254
+ connection.notify("model.credentials", credentials);
255
+ this.credentialsSent = true;
256
+ }
257
+ return connection;
258
+ }
259
+ debug(event, taskId, error) {
260
+ this.deps.log?.(JSON.stringify({ timestamp: new Date().toISOString(), pid: process.pid, event, taskId, ...(error ? { error: error instanceof Error ? error.message : String(error) } : {}) }));
261
+ }
262
+ eventsQueue = Promise.resolve();
263
+ onTaskEvent = (taskId, event) => {
264
+ // Hosts may burst events in a single tick (e.g. running+completed); apply them
265
+ // strictly in arrival order so a late non-terminal write cannot overwrite a terminal one.
266
+ this.eventsQueue = this.eventsQueue
267
+ .then(() => this.handleTaskEvent(taskId, event))
268
+ .catch((error) => this.debug("agent.event_apply_failed", taskId, error));
269
+ };
270
+ async handleTaskEvent(taskId, event) {
271
+ if (event.type === "status") {
272
+ const current = await this.deps.store.read(taskId).catch(() => null);
273
+ if (!current)
274
+ return;
275
+ const next = nextRuntimeStatus(current.status, event);
276
+ if (next === null) {
277
+ this.debug("agent.task.status_rejected", taskId);
278
+ return;
279
+ }
280
+ await this.deps.store.update(taskId, (task) => ({
281
+ ...task,
282
+ status: next,
283
+ error: next === "failed" ? event.detail ?? "Task failed." : task.error,
284
+ settledAt: isTerminalStatus(next) ? new Date().toISOString() : task.settledAt,
285
+ }));
286
+ if (isTerminalStatus(next)) {
287
+ this.executors.get(taskId)?.dispose();
288
+ this.executors.delete(taskId);
289
+ void this.supervisor().ensureHost().then((connection) => connection.request("session.dispose", { taskId }, 5_000)).catch(() => undefined);
290
+ }
291
+ }
292
+ if (event.type === "usage") {
293
+ const task = await this.deps.store.read(taskId).catch(() => null);
294
+ if (!task)
295
+ return;
296
+ await this.deps.store.update(taskId, (record) => ({
297
+ ...record,
298
+ usage: {
299
+ inputTokens: record.usage.inputTokens + event.inputTokens,
300
+ outputTokens: record.usage.outputTokens + event.outputTokens,
301
+ costUsd: Math.max(record.usage.costUsd, event.costUsd),
302
+ },
303
+ }));
304
+ const latest = await this.deps.store.read(taskId);
305
+ if (latest.usage.costUsd >= latest.maxCostUsd && !isTerminalStatus(latest.status) && !this.budgetCancels.has(taskId)) {
306
+ this.budgetCancels.add(taskId);
307
+ void this.supervisor()
308
+ .ensureHost()
309
+ .then((connection) => connection.request("task.cancel", { taskId, reason: "Budget limit reached." }, 10_000))
310
+ .catch(() => this.settleCancelled(taskId, "Budget limit reached (host unreachable)."));
311
+ }
312
+ }
313
+ await this.deps.store.appendEvent(taskId, event);
314
+ }
315
+ onHostLost = (error) => {
316
+ this.credentialsSent = false;
317
+ this.budgetCancels.clear();
318
+ void this.failRunningTasks(error).catch(() => undefined);
319
+ };
320
+ async failRunningTasks(error) {
321
+ const detail = error ? `Agent host exited unexpectedly: ${error.message}` : "Agent host exited unexpectedly.";
322
+ for (const task of await this.deps.store.list()) {
323
+ if (isTerminalStatus(task.status))
324
+ continue;
325
+ this.executors.delete(task.id);
326
+ await this.deps.store.update(task.id, (record) => ({ ...record, status: "failed", error: detail, settledAt: new Date().toISOString() }));
327
+ await this.deps.store.appendEvent(task.id, { type: "status", status: "failed", detail });
328
+ }
329
+ }
330
+ onToolRequest = async (request, args, taskId) => {
331
+ const kind = toolKindFromMethod(request.method);
332
+ if (!kind)
333
+ throw new Error(`Unsupported tool method: ${request.method}`);
334
+ const executor = this.executors.get(taskId);
335
+ if (!executor) {
336
+ const task = await this.deps.store.read(taskId).catch(() => null);
337
+ if (!task)
338
+ throw new Error("Unknown task.");
339
+ throw new Error(`Task ${taskId} is ${task.status}; tools are unavailable.`);
340
+ }
341
+ const result = await executor.execute(kind, args);
342
+ if (!result.ok)
343
+ throw new Error(result.error.message);
344
+ return result.result;
345
+ };
346
+ }
347
+ export { TaskStore, AgentStoreError, branchNameForTask };
348
+ //# sourceMappingURL=agent-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-service.js","sourceRoot":"","sources":["../../src/agent/agent-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export declare const APP_INSTALL_SCHEMA_VERSION = 1;
2
+ export declare const CAPSULE_MANIFEST_NAME = "capsule-manifest.json";
3
+ export type AppInstall = {
4
+ schemaVersion: number;
5
+ appVersion: string;
6
+ capsulePath: string;
7
+ protocolVersion: number;
8
+ };
9
+ export type CapsuleManifest = {
10
+ schemaVersion: number;
11
+ capsuleKind: string;
12
+ sourceCommit: string;
13
+ target: {
14
+ id: string;
15
+ platform: string;
16
+ architecture: string;
17
+ };
18
+ versions: {
19
+ piNode: string;
20
+ protocol: string;
21
+ };
22
+ runtime: {
23
+ executable: string;
24
+ };
25
+ application: {
26
+ entrypoint: string;
27
+ agentHostEntrypoint?: string;
28
+ launch?: string[];
29
+ };
30
+ };
31
+ export declare class AppInstallError extends Error {
32
+ readonly code: "app_not_installed" | "app_manifest_invalid" | "capsule_invalid" | "capsule_platform_mismatch" | "capsule_integrity_failed";
33
+ constructor(code: "app_not_installed" | "app_manifest_invalid" | "capsule_invalid" | "capsule_platform_mismatch" | "capsule_integrity_failed");
34
+ }
35
+ export declare function appInstallPath(env?: NodeJS.ProcessEnv): string;
36
+ export declare function readAppInstall(path?: string, env?: NodeJS.ProcessEnv): Promise<AppInstall>;
37
+ export type CapsuleFacts = {
38
+ manifest: CapsuleManifest;
39
+ nodeExecutable: string;
40
+ agentHostEntrypoint: string;
41
+ entrypointIsAgentHost: boolean;
42
+ };
43
+ /** Structural capsule verification: manifest shape, platform match, entrypoints. */
44
+ export declare function verifyCapsule(appInstall: AppInstall): Promise<CapsuleFacts>;
45
+ /**
46
+ * Full integrity walk (sha256 of every payload file against the manifest).
47
+ * Expensive; run once per supervisor lifetime, not on every host restart.
48
+ */
49
+ export declare function verifyCapsuleIntegrity(appInstall: AppInstall): Promise<void>;
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Reads `~/.config/frely/app.json` (written by the Frely App) and verifies the
3
+ * referenced Runtime Capsule well enough to launch its agent host entry.
4
+ */
5
+ import { createHash } from "node:crypto";
6
+ import { homedir } from "node:os";
7
+ import { lstat, readFile, readlink, stat } from "node:fs/promises";
8
+ import { join, relative, resolve } from "node:path";
9
+ export const APP_INSTALL_SCHEMA_VERSION = 1;
10
+ export const CAPSULE_MANIFEST_NAME = "capsule-manifest.json";
11
+ export class AppInstallError extends Error {
12
+ code;
13
+ constructor(code) {
14
+ super(code);
15
+ this.code = code;
16
+ this.name = "AppInstallError";
17
+ }
18
+ }
19
+ export function appInstallPath(env = process.env) {
20
+ return join(env.XDG_CONFIG_HOME || join(homedir(), ".config"), "frely", "app.json");
21
+ }
22
+ export async function readAppInstall(path, env = process.env) {
23
+ let raw;
24
+ try {
25
+ raw = await readFile(path ?? appInstallPath(env), "utf8");
26
+ }
27
+ catch {
28
+ throw new AppInstallError("app_not_installed");
29
+ }
30
+ let value;
31
+ try {
32
+ value = JSON.parse(raw);
33
+ }
34
+ catch {
35
+ throw new AppInstallError("app_manifest_invalid");
36
+ }
37
+ const record = value;
38
+ if (record.schemaVersion !== APP_INSTALL_SCHEMA_VERSION)
39
+ throw new AppInstallError("app_manifest_invalid");
40
+ if (typeof record.appVersion !== "string" || typeof record.capsulePath !== "string" || !Number.isSafeInteger(record.protocolVersion)) {
41
+ throw new AppInstallError("app_manifest_invalid");
42
+ }
43
+ return { schemaVersion: APP_INSTALL_SCHEMA_VERSION, appVersion: record.appVersion, capsulePath: record.capsulePath, protocolVersion: record.protocolVersion };
44
+ }
45
+ /** Structural capsule verification: manifest shape, platform match, entrypoints. */
46
+ export async function verifyCapsule(appInstall) {
47
+ let manifestRaw;
48
+ try {
49
+ manifestRaw = await readFile(join(appInstall.capsulePath, CAPSULE_MANIFEST_NAME), "utf8");
50
+ }
51
+ catch {
52
+ throw new AppInstallError("capsule_invalid");
53
+ }
54
+ let manifest;
55
+ try {
56
+ manifest = JSON.parse(manifestRaw);
57
+ }
58
+ catch {
59
+ throw new AppInstallError("capsule_invalid");
60
+ }
61
+ if (manifest.schemaVersion !== 2 || manifest.capsuleKind !== "pi-node-runtime")
62
+ throw new AppInstallError("capsule_invalid");
63
+ if (typeof manifest.sourceCommit !== "string" || !/^[0-9a-f]{40}$/u.test(manifest.sourceCommit))
64
+ throw new AppInstallError("capsule_invalid");
65
+ const platform = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "darwin" : "linux";
66
+ if (manifest.target.platform !== platform)
67
+ throw new AppInstallError("capsule_platform_mismatch");
68
+ const nodeExecutable = join(appInstall.capsulePath, manifest.runtime.executable);
69
+ if (!(await isFile(nodeExecutable)))
70
+ throw new AppInstallError("capsule_invalid");
71
+ const agentHostEntrypoint = manifest.application.agentHostEntrypoint ?? manifest.application.entrypoint;
72
+ const entrypointPath = join(appInstall.capsulePath, agentHostEntrypoint);
73
+ if (!(await isFile(entrypointPath)))
74
+ throw new AppInstallError("capsule_invalid");
75
+ return {
76
+ manifest,
77
+ nodeExecutable,
78
+ agentHostEntrypoint: entrypointPath,
79
+ entrypointIsAgentHost: manifest.application.agentHostEntrypoint !== undefined,
80
+ };
81
+ }
82
+ /**
83
+ * Full integrity walk (sha256 of every payload file against the manifest).
84
+ * Expensive; run once per supervisor lifetime, not on every host restart.
85
+ */
86
+ export async function verifyCapsuleIntegrity(appInstall) {
87
+ const manifest = JSON.parse(await readFile(join(appInstall.capsulePath, CAPSULE_MANIFEST_NAME), "utf8"));
88
+ const integrity = manifest.integrity;
89
+ if (!integrity || integrity.algorithm !== "sha256")
90
+ throw new AppInstallError("capsule_invalid");
91
+ const seen = new Set();
92
+ let totalSize = 0;
93
+ let count = 0;
94
+ for (const entry of integrity.files) {
95
+ if (typeof entry.path !== "string" || entry.path.startsWith("/") || entry.path.includes(".."))
96
+ throw new AppInstallError("capsule_invalid");
97
+ if (seen.has(entry.path))
98
+ throw new AppInstallError("capsule_invalid");
99
+ seen.add(entry.path);
100
+ const full = resolve(appInstall.capsulePath, entry.path);
101
+ if (relative(appInstall.capsulePath, full).startsWith(".."))
102
+ throw new AppInstallError("capsule_invalid");
103
+ const info = await lstat(full).catch(() => null);
104
+ if (!info)
105
+ throw new AppInstallError("capsule_integrity_failed");
106
+ if (entry.symlinkTarget !== undefined) {
107
+ if (!info.isSymbolicLink())
108
+ throw new AppInstallError("capsule_integrity_failed");
109
+ const target = await readlink(full);
110
+ if (target !== entry.symlinkTarget)
111
+ throw new AppInstallError("capsule_integrity_failed");
112
+ continue;
113
+ }
114
+ if (!info.isFile())
115
+ throw new AppInstallError("capsule_integrity_failed");
116
+ const hash = createHash("sha256");
117
+ const content = await readFile(full);
118
+ hash.update(content);
119
+ if (hash.digest("hex") !== entry.sha256)
120
+ throw new AppInstallError("capsule_integrity_failed");
121
+ if (typeof entry.bytes === "number" && entry.bytes !== content.byteLength)
122
+ throw new AppInstallError("capsule_integrity_failed");
123
+ totalSize += content.byteLength;
124
+ count += 1;
125
+ }
126
+ if (count !== integrity.payloadFileCount || totalSize !== integrity.payloadSize)
127
+ throw new AppInstallError("capsule_integrity_failed");
128
+ }
129
+ async function isFile(path) {
130
+ const info = await stat(path).catch(() => null);
131
+ return info !== null && info.isFile();
132
+ }
133
+ //# sourceMappingURL=app-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-install.js","sourceRoot":"","sources":["../../src/agent/app-install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare const DEFAULT_LIFETIME_USD = 50;
2
+ export declare const MAX_LIFETIME_USD = 500;
3
+ export declare class AppKeyError extends Error {
4
+ readonly code: string;
5
+ readonly status: number;
6
+ constructor(code: string, status: number, message: string);
7
+ }
8
+ export interface ProvisionedAppKey {
9
+ keyId: string;
10
+ rawKey: string;
11
+ name: string;
12
+ lifetimeUsd: number | null;
13
+ }
14
+ export declare function provisionAgentKey(lifetimeUsd?: number): Promise<ProvisionedAppKey>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `frely app key`: provision a device-scoped Frely API key for agent tasks
3
+ * (plan frely-app-agent-toolset §9.3). The key is shown once and never stored
4
+ * by the CLI; it is bound to a device the caller owns and capped at a
5
+ * lifetime spend limit enforced by the relay backend.
6
+ */
7
+ import { requireLogin } from "../auth.js";
8
+ import { ensureDevice, relayFetch } from "../device/control.js";
9
+ const ENDPOINT = "/api/user/device-relay/agent-key";
10
+ export const DEFAULT_LIFETIME_USD = 50;
11
+ export const MAX_LIFETIME_USD = 500;
12
+ export class AppKeyError extends Error {
13
+ code;
14
+ status;
15
+ constructor(code, status, message) {
16
+ super(message);
17
+ this.code = code;
18
+ this.status = status;
19
+ this.name = "AppKeyError";
20
+ }
21
+ }
22
+ export async function provisionAgentKey(lifetimeUsd = DEFAULT_LIFETIME_USD) {
23
+ if (!Number.isFinite(lifetimeUsd) || lifetimeUsd <= 0 || lifetimeUsd > MAX_LIFETIME_USD) {
24
+ throw new Error(`--lifetime-usd must be a positive amount of at most ${MAX_LIFETIME_USD}.`);
25
+ }
26
+ const auth = await requireLogin();
27
+ const device = await ensureDevice();
28
+ const response = await relayFetch(auth.config.relayUrl, auth.credential, ENDPOINT, {
29
+ method: "POST",
30
+ body: JSON.stringify({ deviceId: device.deviceId, lifetimeUsd }),
31
+ });
32
+ if (!response.ok) {
33
+ const body = await response.json().catch(() => null);
34
+ throw new AppKeyError(body?.error?.code ?? "agent_key_failed", response.status, body?.error?.message ?? `Agent key provisioning failed (${response.status}).`);
35
+ }
36
+ const created = await response.json();
37
+ if (typeof created.apiKey?.id !== "string" || typeof created.rawKey !== "string" || created.rawKey.length === 0)
38
+ throw new AppKeyError("agent_key_invalid", response.status, "Agent key response was invalid.");
39
+ return {
40
+ keyId: created.apiKey.id,
41
+ rawKey: created.rawKey,
42
+ name: created.apiKey.name ?? `frely-app ${device.deviceId.slice(-8)}`,
43
+ lifetimeUsd: created.limits?.lifetimeAmount ?? null,
44
+ };
45
+ }
46
+ //# sourceMappingURL=app-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-key.js","sourceRoot":"","sources":["../../src/agent/app-key.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAEpC,MAAM,OAAO,WAAY,SAAQ,KAAK;IACf;IAAuB;IAA5C,YAAqB,IAAY,EAAW,MAAc,EAAE,OAAe;QACzE,KAAK,CAAC,OAAO,CAAC,CAAC;QADI,SAAI,GAAJ,IAAI,CAAQ;QAAW,WAAM,GAAN,MAAM,CAAQ;QAExD,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AASD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,cAAsB,oBAAoB;IAChF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,WAAW,GAAG,gBAAgB,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,uDAAuD,gBAAgB,GAAG,CAAC,CAAC;IAC9F,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE;QACjF,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;KACjE,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAA2D,CAAC;QAC/G,MAAM,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,kBAAkB,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,kCAAkC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;IACjK,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA+G,CAAC;IACnJ,IAAI,OAAO,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,WAAW,CAAC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;IAChN,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,aAAa,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QACrE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,IAAI,IAAI;KACpD,CAAC;AACJ,CAAC"}