frely-cli 0.6.10 → 0.8.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.
Files changed (104) hide show
  1. package/README.md +97 -293
  2. package/README.zh-CN.md +230 -0
  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 +200 -176
  40. package/dist/agent-help.js +65 -32
  41. package/dist/agent-help.js.map +1 -1
  42. package/dist/auth.d.ts +3 -0
  43. package/dist/auth.js +52 -14
  44. package/dist/auth.js.map +1 -1
  45. package/dist/cloud.d.ts +1 -1
  46. package/dist/cloud.js +6 -13
  47. package/dist/cloud.js.map +1 -1
  48. package/dist/device/protocol.d.ts +11 -2
  49. package/dist/device/protocol.js +18 -2
  50. package/dist/device/protocol.js.map +1 -1
  51. package/dist/device/relay-client.d.ts +19 -2
  52. package/dist/device/relay-client.js +65 -13
  53. package/dist/device/relay-client.js.map +1 -1
  54. package/dist/diagnostics.js +12 -4
  55. package/dist/diagnostics.js.map +1 -1
  56. package/dist/index.js +203 -173
  57. package/dist/index.js.map +1 -1
  58. package/dist/key-budget.js +2 -2
  59. package/dist/key-budget.js.map +1 -1
  60. package/dist/mcp-authorization.js +9 -7
  61. package/dist/mcp-authorization.js.map +1 -1
  62. package/dist/mcp-command.d.ts +12 -4
  63. package/dist/mcp-command.js +54 -25
  64. package/dist/mcp-command.js.map +1 -1
  65. package/dist/provider/state.d.ts +2 -0
  66. package/dist/provider/state.js +1 -0
  67. package/dist/provider/state.js.map +1 -1
  68. package/dist/runtime/mcp-lease.js +1 -1
  69. package/dist/runtime/mcp-lease.js.map +1 -1
  70. package/dist/runtime/mcp.d.ts +139 -0
  71. package/dist/runtime/mcp.js +88 -29
  72. package/dist/runtime/mcp.js.map +1 -1
  73. package/dist/runtime/process-manager.d.ts +1 -1
  74. package/dist/runtime/process-manager.js +4 -2
  75. package/dist/runtime/process-manager.js.map +1 -1
  76. package/dist/runtime/relay-agent.d.ts +25 -0
  77. package/dist/runtime/relay-agent.js +63 -0
  78. package/dist/runtime/relay-agent.js.map +1 -0
  79. package/dist/runtime/relay-mcp.d.ts +5 -2
  80. package/dist/runtime/relay-mcp.js +6 -1
  81. package/dist/runtime/relay-mcp.js.map +1 -1
  82. package/dist/runtime/relay-session.d.ts +47 -0
  83. package/dist/runtime/relay-session.js +56 -0
  84. package/dist/runtime/relay-session.js.map +1 -0
  85. package/dist/runtime/sandbox.d.ts +16 -0
  86. package/dist/runtime/sandbox.js +149 -0
  87. package/dist/runtime/sandbox.js.map +1 -0
  88. package/dist/runtime/workspace-registry.d.ts +5 -0
  89. package/dist/runtime/workspace-registry.js +87 -0
  90. package/dist/runtime/workspace-registry.js.map +1 -0
  91. package/dist/runtime/workspace-router.d.ts +5 -0
  92. package/dist/runtime/workspace-router.js +32 -0
  93. package/dist/runtime/workspace-router.js.map +1 -0
  94. package/dist/runtime/workspace.js +3 -1
  95. package/dist/runtime/workspace.js.map +1 -1
  96. package/dist/skill/access.d.ts +4 -2
  97. package/dist/skill/access.js +7 -3
  98. package/dist/skill/access.js.map +1 -1
  99. package/dist/upgrade/installation.js +1 -1
  100. package/dist/upgrade/installation.js.map +1 -1
  101. package/dist/workspace-command.d.ts +8 -0
  102. package/dist/workspace-command.js +36 -0
  103. package/dist/workspace-command.js.map +1 -0
  104. package/package.json +2 -1
@@ -0,0 +1,113 @@
1
+ import { Workspace } from "../runtime/workspace.js";
2
+ /** Single active executor per task; created when the task starts running. */
3
+ export class AgentToolExecutor {
4
+ scheduler;
5
+ workspace;
6
+ disposed = false;
7
+ constructor(worktreeRoot, scheduler) {
8
+ this.scheduler = scheduler;
9
+ this.workspace = Workspace.open(worktreeRoot);
10
+ }
11
+ async execute(kind, args) {
12
+ if (this.disposed)
13
+ return failure("tool_failed", "Task session is disposed.");
14
+ try {
15
+ const result = await this.dispatch(kind, args);
16
+ return { ok: true, result };
17
+ }
18
+ catch (error) {
19
+ return failure("tool_failed", error instanceof Error ? error.message : "tool failed");
20
+ }
21
+ }
22
+ async dispatch(kind, args) {
23
+ const workspace = await this.workspace;
24
+ switch (kind) {
25
+ case "read": {
26
+ const path = stringArg(args, "path");
27
+ return this.scheduler.read(() => workspace.readFile(path));
28
+ }
29
+ case "write": {
30
+ const path = stringArg(args, "path");
31
+ const content = stringArg(args, "content");
32
+ const overwrite = args.overwrite === true;
33
+ return this.scheduler.write(() => workspace.writeFile(path, content, overwrite));
34
+ }
35
+ case "edit": {
36
+ const path = stringArg(args, "path");
37
+ const edits = args.edits;
38
+ if (!Array.isArray(edits))
39
+ throw new Error("edits must be an array.");
40
+ const expectedSha256 = typeof args.expectedSha256 === "string" ? args.expectedSha256 : undefined;
41
+ return this.scheduler.write(() => workspace.applyPatch(path, edits, expectedSha256));
42
+ }
43
+ case "bash": {
44
+ const command = stringArg(args, "command");
45
+ const cwd = typeof args.cwd === "string" ? args.cwd : ".";
46
+ const timeoutMs = numberArg(args, "timeoutMs", 30_000);
47
+ return this.scheduler.write(() => workspace.runCommand(command, cwd, timeoutMs));
48
+ }
49
+ case "grep": {
50
+ const query = stringArg(args, "query");
51
+ const path = typeof args.path === "string" ? args.path : ".";
52
+ return this.scheduler.read(() => workspace.searchFiles(path, query, {
53
+ regex: args.regex === true,
54
+ caseSensitive: args.caseSensitive === true,
55
+ maxResults: numberArg(args, "maxResults", 100),
56
+ contextLines: numberArg(args, "contextLines", 0),
57
+ }));
58
+ }
59
+ case "find": {
60
+ const pattern = stringArg(args, "pattern");
61
+ const path = typeof args.path === "string" ? args.path : ".";
62
+ return this.scheduler.read(() => workspace.findFiles(path, pattern, numberArg(args, "maxResults", 100)));
63
+ }
64
+ case "ls": {
65
+ const path = typeof args.path === "string" ? args.path : ".";
66
+ return this.scheduler.read(() => workspace.listDirectory(path));
67
+ }
68
+ default:
69
+ throw new Error(`Unknown tool kind: ${kind}`);
70
+ }
71
+ }
72
+ dispose() {
73
+ this.disposed = true;
74
+ }
75
+ }
76
+ export function toolKindFromMethod(method) {
77
+ switch (method) {
78
+ case "tool.read":
79
+ return "read";
80
+ case "tool.write":
81
+ return "write";
82
+ case "tool.edit":
83
+ return "edit";
84
+ case "tool.bash":
85
+ return "bash";
86
+ case "tool.grep":
87
+ return "grep";
88
+ case "tool.find":
89
+ return "find";
90
+ case "tool.ls":
91
+ return "ls";
92
+ default:
93
+ return null;
94
+ }
95
+ }
96
+ function stringArg(args, key) {
97
+ const value = args[key];
98
+ if (typeof value !== "string" || value.length === 0)
99
+ throw new Error(`${key} must be a non-empty string.`);
100
+ return value;
101
+ }
102
+ function numberArg(args, key, fallback) {
103
+ const value = args[key];
104
+ if (value === undefined)
105
+ return fallback;
106
+ if (typeof value !== "number" || !Number.isSafeInteger(value))
107
+ throw new Error(`${key} must be an integer.`);
108
+ return value;
109
+ }
110
+ function failure(code, message) {
111
+ return { ok: false, error: { code, message: message.slice(0, 512) } };
112
+ }
113
+ //# sourceMappingURL=tool-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-executor.js","sourceRoot":"","sources":["../../src/agent/tool-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export declare class WorktreeError extends Error {
2
+ readonly code: "not_a_git_repo" | "dirty_workspace" | "git_failed" | "merge_conflict" | "not_found" | "invalid_state";
3
+ constructor(code: "not_a_git_repo" | "dirty_workspace" | "git_failed" | "merge_conflict" | "not_found" | "invalid_state");
4
+ }
5
+ export type WorktreeInfo = {
6
+ path: string;
7
+ branch: string;
8
+ baseBranch: string;
9
+ baseCommit: string;
10
+ };
11
+ export declare function branchNameForTask(taskId: string): string;
12
+ export declare function worktreePathForTask(taskId: string, workspaceRoot: string, env?: NodeJS.ProcessEnv): string;
13
+ /** Verify a workspace is a clean git repository and return its base facts. */
14
+ export declare function inspectWorkspace(workspaceRoot: string): Promise<{
15
+ baseBranch: string;
16
+ baseCommit: string;
17
+ root: string;
18
+ }>;
19
+ export declare function createTaskWorktree(taskId: string, workspaceRoot: string, baseRef?: string): Promise<WorktreeInfo>;
20
+ export declare function removeTaskWorktree(taskId: string, workspaceRoot: string): Promise<void>;
21
+ export type MergeOutcome = {
22
+ status: "merged";
23
+ } | {
24
+ status: "merge_conflict";
25
+ detail: string;
26
+ };
27
+ /** Rebase the task branch (inside its worktree) onto the current baseline, then merge --no-ff. */
28
+ export declare function mergeTaskBranch(taskId: string, workspaceRoot: string): Promise<MergeOutcome>;
29
+ /** List of changed files (vs base) with bounded diff output. */
30
+ export declare function taskChangedFiles(taskId: string, workspaceRoot: string): Promise<string[]>;
31
+ /** Bounded unified diff of the task worktree vs its merge-base (committed + uncommitted changes). */
32
+ export declare function taskDiff(taskId: string, workspaceRoot: string, path?: string, maxBytes?: number): Promise<{
33
+ diff: string;
34
+ truncated: boolean;
35
+ }>;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Git worktree lifecycle for agent tasks (plan §4.4): task changes land in an
3
+ * isolated worktree outside the user workspace, merge back with --no-ff after
4
+ * approval, and rebase first when the baseline branch advanced.
5
+ */
6
+ import { execFile } from "node:child_process";
7
+ import { mkdir, rm } from "node:fs/promises";
8
+ import { dirname, join } from "node:path";
9
+ import { promisify } from "node:util";
10
+ import { agentDataDir, workspaceStorageKey } from "./task-store.js";
11
+ const exec = promisify(execFile);
12
+ export class WorktreeError extends Error {
13
+ code;
14
+ constructor(code) {
15
+ super(code);
16
+ this.code = code;
17
+ this.name = "WorktreeError";
18
+ }
19
+ }
20
+ export function branchNameForTask(taskId) {
21
+ return `frely/task/${taskId}`;
22
+ }
23
+ export function worktreePathForTask(taskId, workspaceRoot, env = process.env) {
24
+ return join(agentDataDir(env), "worktrees", workspaceStorageKey(workspaceRoot), taskId);
25
+ }
26
+ /** Verify a workspace is a clean git repository and return its base facts. */
27
+ export async function inspectWorkspace(workspaceRoot) {
28
+ let root;
29
+ try {
30
+ const out = await git(workspaceRoot, ["rev-parse", "--show-toplevel"]);
31
+ root = out.trim();
32
+ }
33
+ catch {
34
+ throw new WorktreeError("not_a_git_repo");
35
+ }
36
+ let status;
37
+ try {
38
+ status = (await git(root, ["status", "--porcelain"])).trim();
39
+ }
40
+ catch {
41
+ throw new WorktreeError("git_failed");
42
+ }
43
+ if (status.length > 0)
44
+ throw new WorktreeError("dirty_workspace");
45
+ const baseCommit = (await git(root, ["rev-parse", "HEAD"])).trim();
46
+ if (!/^[0-9a-f]{7,40}$/u.test(baseCommit))
47
+ throw new WorktreeError("git_failed");
48
+ let baseBranch;
49
+ try {
50
+ baseBranch = (await git(root, ["symbolic-ref", "--short", "HEAD"])).trim();
51
+ }
52
+ catch {
53
+ baseBranch = baseCommit; // detached HEAD: baseline is the commit itself
54
+ }
55
+ return { baseBranch: baseBranch || baseCommit, baseCommit, root };
56
+ }
57
+ export async function createTaskWorktree(taskId, workspaceRoot, baseRef) {
58
+ const facts = await inspectWorkspace(workspaceRoot);
59
+ const path = worktreePathForTask(taskId, facts.root);
60
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
61
+ const branch = branchNameForTask(taskId);
62
+ try {
63
+ await git(facts.root, ["worktree", "add", "-b", branch, path, baseRef ?? facts.baseCommit]);
64
+ }
65
+ catch {
66
+ await rm(path, { recursive: true, force: true }).catch(() => undefined);
67
+ throw new WorktreeError("git_failed");
68
+ }
69
+ return { path, branch, baseBranch: facts.baseBranch, baseCommit: facts.baseCommit };
70
+ }
71
+ export async function removeTaskWorktree(taskId, workspaceRoot) {
72
+ const facts = await inspectWorkspace(workspaceRoot).catch(() => null);
73
+ const root = facts?.root ?? workspaceRoot;
74
+ const path = worktreePathForTask(taskId, root);
75
+ const branch = branchNameForTask(taskId);
76
+ await git(root, ["worktree", "remove", "--force", path]).catch(() => undefined);
77
+ await rm(path, { recursive: true, force: true }).catch(() => undefined);
78
+ await git(root, ["branch", "-D", branch]).catch(() => undefined);
79
+ }
80
+ /** Rebase the task branch (inside its worktree) onto the current baseline, then merge --no-ff. */
81
+ export async function mergeTaskBranch(taskId, workspaceRoot) {
82
+ const facts = await inspectWorkspace(workspaceRoot);
83
+ const branch = branchNameForTask(taskId);
84
+ const worktree = worktreePathForTask(taskId, facts.root);
85
+ const baseTip = (await git(facts.root, ["rev-parse", facts.baseBranch])).trim();
86
+ // Uncommitted agent edits are committed first: merges only carry commits.
87
+ const dirty = (await git(worktree, ["status", "--porcelain"])).trim();
88
+ if (dirty.length > 0) {
89
+ await git(worktree, ["add", "-A"]);
90
+ await git(worktree, ["-c", "user.email=agent@frely.invalid", "-c", "user.name=frely agent", "commit", "-m", `Agent changes for ${taskId}`]);
91
+ }
92
+ // Rebase the task branch onto the current baseline tip inside its own worktree.
93
+ let rebaseFailed = false;
94
+ await git(worktree, ["rebase", baseTip]).catch(() => {
95
+ rebaseFailed = true;
96
+ });
97
+ if (rebaseFailed) {
98
+ await git(worktree, ["rebase", "--abort"]).catch(() => undefined);
99
+ return { status: "merge_conflict", detail: "Task branch cannot be rebased onto the current baseline." };
100
+ }
101
+ if (facts.baseBranch === facts.baseCommit) {
102
+ // Detached baseline: nothing to merge into; treat as conflict to force an explicit decision.
103
+ return { status: "merge_conflict", detail: "Workspace baseline is a detached commit." };
104
+ }
105
+ try {
106
+ await git(facts.root, ["merge", "--no-ff", branch, "-m", `Merge ${branch}`]);
107
+ return { status: "merged" };
108
+ }
109
+ catch (error) {
110
+ await git(facts.root, ["merge", "--abort"]).catch(() => undefined);
111
+ return { status: "merge_conflict", detail: error instanceof Error ? error.message.slice(0, 512) : "merge failed" };
112
+ }
113
+ }
114
+ /** List of changed files (vs base) with bounded diff output. */
115
+ export async function taskChangedFiles(taskId, workspaceRoot) {
116
+ const facts = await inspectWorkspace(workspaceRoot);
117
+ const branch = branchNameForTask(taskId);
118
+ const base = (await git(facts.root, ["merge-base", branch, facts.baseBranch]).catch(() => null))?.trim() ?? facts.baseCommit;
119
+ const out = await git(facts.root, ["diff", "--name-only", `${base}..${branch}`]);
120
+ return out.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
121
+ }
122
+ /** Bounded unified diff of the task worktree vs its merge-base (committed + uncommitted changes). */
123
+ export async function taskDiff(taskId, workspaceRoot, path, maxBytes = 256 * 1024) {
124
+ const facts = await inspectWorkspace(workspaceRoot);
125
+ const branch = branchNameForTask(taskId);
126
+ const worktree = worktreePathForTask(taskId, facts.root);
127
+ const base = (await git(facts.root, ["merge-base", branch, facts.baseBranch]).catch(() => null))?.trim() ?? facts.baseCommit;
128
+ // Include brand-new (untracked) files in the diff via intent-to-add markers.
129
+ await git(worktree, ["add", "--intent-to-add", "-A"]).catch(() => undefined);
130
+ const args = ["diff", base];
131
+ if (path)
132
+ args.push("--", path);
133
+ const out = await git(worktree, args, { maxBuffer: 16 * 1024 * 1024 });
134
+ const buffer = Buffer.from(out, "utf8");
135
+ if (buffer.byteLength <= maxBytes)
136
+ return { diff: out, truncated: false };
137
+ return { diff: buffer.subarray(0, maxBytes).toString("utf8"), truncated: true };
138
+ }
139
+ async function git(cwd, args, options) {
140
+ const { stdout } = await exec("git", args, { cwd, maxBuffer: options?.maxBuffer ?? 4 * 1024 * 1024 });
141
+ return stdout;
142
+ }
143
+ //# sourceMappingURL=worktrees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktrees.js","sourceRoot":"","sources":["../../src/agent/worktrees.ts"],"names":[],"mappings":"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"}