@greppleai/grip 0.0.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/README.md +13 -7
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +4 -2
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/embedded-assets.d.ts +3 -0
- package/dist/bun/embedded-assets.d.ts.map +1 -0
- package/dist/bun/embedded-assets.js +52 -0
- package/dist/bun/embedded-assets.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +17 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.d.ts +13 -4
- package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.js +17 -1
- package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts +16 -0
- package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/guest-shared-client.js +54 -0
- package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -0
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts +23 -0
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +112 -0
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -0
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts +30 -0
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +243 -0
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -0
- package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts +3 -0
- package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/lima-owner-directory.js +31 -0
- package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -0
- package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts +9 -0
- package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/lima-owner-lock.js +89 -0
- package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -0
- package/dist/core/remote-workspace-protocol/session.d.ts +2 -0
- package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/session.js +3 -0
- package/dist/core/remote-workspace-protocol/session.js.map +1 -1
- package/dist/core/remote-workspace-protocol/shared-transport.d.ts +71 -0
- package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -0
- package/dist/core/remote-workspace-protocol/shared-transport.js +68 -0
- package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -0
- package/dist/core/sandbox/command.d.ts +2 -4
- package/dist/core/sandbox/command.d.ts.map +1 -1
- package/dist/core/sandbox/command.js +24 -46
- package/dist/core/sandbox/command.js.map +1 -1
- package/dist/core/sandbox/config.d.ts +91 -0
- package/dist/core/sandbox/config.d.ts.map +1 -0
- package/dist/core/sandbox/config.js +88 -0
- package/dist/core/sandbox/config.js.map +1 -0
- package/dist/core/sandbox/lima-guest-binary.d.ts +11 -0
- package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -0
- package/dist/core/sandbox/lima-guest-binary.js +140 -0
- package/dist/core/sandbox/lima-guest-binary.js.map +1 -0
- package/dist/core/sandbox/lima.d.ts +22 -3
- package/dist/core/sandbox/lima.d.ts.map +1 -1
- package/dist/core/sandbox/lima.js +434 -42
- package/dist/core/sandbox/lima.js.map +1 -1
- package/dist/core/sandbox/shared-lima-roots.d.ts +11 -0
- package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -0
- package/dist/core/sandbox/shared-lima-roots.js +25 -0
- package/dist/core/sandbox/shared-lima-roots.js.map +1 -0
- package/dist/core/sandbox/update-shared-guest-binary.d.ts +8 -0
- package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -0
- package/dist/core/sandbox/update-shared-guest-binary.js +100 -0
- package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -0
- package/dist/core/settings-manager.d.ts +1 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +25 -14
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +2 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +9 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/operations.d.ts +13 -2
- package/dist/core/tools/operations.d.ts.map +1 -1
- package/dist/core/tools/operations.js +132 -36
- package/dist/core/tools/operations.js.map +1 -1
- package/dist/daemon/activity-budget.d.ts +10 -0
- package/dist/daemon/activity-budget.d.ts.map +1 -0
- package/dist/daemon/activity-budget.js +34 -0
- package/dist/daemon/activity-budget.js.map +1 -0
- package/dist/daemon/config.d.ts +2 -0
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +15 -0
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/outbound-budget.d.ts +10 -0
- package/dist/daemon/outbound-budget.d.ts.map +1 -0
- package/dist/daemon/outbound-budget.js +30 -0
- package/dist/daemon/outbound-budget.js.map +1 -0
- package/dist/daemon/security.d.ts.map +1 -1
- package/dist/daemon/security.js +3 -1
- package/dist/daemon/security.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +104 -24
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shared-connection.d.ts +33 -0
- package/dist/daemon/shared-connection.d.ts.map +1 -0
- package/dist/daemon/shared-connection.js +271 -0
- package/dist/daemon/shared-connection.js.map +1 -0
- package/dist/daemon/shared-revision.d.ts +5 -0
- package/dist/daemon/shared-revision.d.ts.map +1 -0
- package/dist/daemon/shared-revision.js +61 -0
- package/dist/daemon/shared-revision.js.map +1 -0
- package/dist/daemon/shared-roots.d.ts +9 -0
- package/dist/daemon/shared-roots.d.ts.map +1 -0
- package/dist/daemon/shared-roots.js +33 -0
- package/dist/daemon/shared-roots.js.map +1 -0
- package/dist/daemon/workspace-runtime.d.ts +1 -1
- package/dist/daemon/workspace-runtime.d.ts.map +1 -1
- package/dist/daemon/workspace-runtime.js +42 -10
- package/dist/daemon/workspace-runtime.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +4 -3
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +5 -4
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +4 -3
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +5 -4
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +4 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-execution.js +3 -2
- package/dist/modes/interactive/components/hook-execution.js.map +1 -1
- package/dist/modes/interactive/components/message-card.d.ts +9 -0
- package/dist/modes/interactive/components/message-card.d.ts.map +1 -0
- package/dist/modes/interactive/components/message-card.js +24 -0
- package/dist/modes/interactive/components/message-card.js.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +4 -3
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +5 -4
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +27 -21
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +3 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -3
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +55 -44
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +3 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +5 -0
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js +1 -0
- package/dist/utils/photon.js.map +1 -1
- package/docs/daemon.md +6 -4
- package/docs/docs.json +1 -1
- package/docs/index.md +8 -12
- package/docs/packages.md +3 -3
- package/docs/quickstart.md +11 -19
- package/docs/sandbox.md +40 -117
- package/docs/settings.md +12 -11
- package/docs/termux.md +1 -18
- package/docs/usage.md +2 -2
- package/examples/README.md +0 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +5 -6
- package/dist/core/sandbox/docker.d.ts +0 -169
- package/dist/core/sandbox/docker.d.ts.map +0 -1
- package/dist/core/sandbox/docker.js +0 -633
- package/dist/core/sandbox/docker.js.map +0 -1
- package/examples/sandbox-docker/Dockerfile +0 -274
- package/examples/sandbox-docker/README.md +0 -88
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { lstat, open, readFile, unlink } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { prepareSharedLimaOwnerDirectory } from "./lima-owner-directory.js";
|
|
5
|
+
function isAlive(pid) {
|
|
6
|
+
if (!Number.isSafeInteger(pid) || pid < 1)
|
|
7
|
+
return false;
|
|
8
|
+
try {
|
|
9
|
+
process.kill(pid, 0);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return error.code === "EPERM";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Exclusive owner lifetime, not a client lease. Never silently steal a stale lock. */
|
|
17
|
+
export async function acquireSharedLimaOwnerLock(instanceName, baseDirectory) {
|
|
18
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(instanceName))
|
|
19
|
+
throw new Error("Invalid shared Lima instance name");
|
|
20
|
+
// The production lock must not follow TMPDIR: separate processes can otherwise
|
|
21
|
+
// claim the same named VM through different private temporary directories.
|
|
22
|
+
// An explicit base is reserved for isolated embedded tests.
|
|
23
|
+
const directory = await prepareSharedLimaOwnerDirectory(baseDirectory ?? "/tmp");
|
|
24
|
+
const digest = createHash("sha256").update(instanceName).digest("hex").slice(0, 32);
|
|
25
|
+
const path = join(directory, `lima-owner-${digest}.lock`);
|
|
26
|
+
const record = { pid: process.pid, nonce: randomBytes(16).toString("hex") };
|
|
27
|
+
let handle;
|
|
28
|
+
try {
|
|
29
|
+
handle = await open(path, "wx", 0o600);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error.code !== "EEXIST")
|
|
33
|
+
throw error;
|
|
34
|
+
// Even a dead PID is ambiguous (crash during a mutation or VM startup). Manual
|
|
35
|
+
// reconciliation is required; another owner must not implicitly take over.
|
|
36
|
+
let state = "unverifiable";
|
|
37
|
+
try {
|
|
38
|
+
const info = await lstat(path);
|
|
39
|
+
if (info.isFile() && info.uid === process.getuid?.() && (info.mode & 0o077) === 0) {
|
|
40
|
+
const existing = JSON.parse(await readFile(path, "utf8"));
|
|
41
|
+
state = typeof existing.pid === "number" && isAlive(existing.pid) ? "occupied" : "stale";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// A racing file change is not grounds for a new owner.
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Shared Lima owner lock ${state}; inspect and reconcile before retrying`);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
await handle.writeFile(JSON.stringify(record));
|
|
51
|
+
const identity = await handle.stat();
|
|
52
|
+
let released = false;
|
|
53
|
+
const assertHeld = async () => {
|
|
54
|
+
if (released)
|
|
55
|
+
throw new Error("Shared Lima owner lock already released");
|
|
56
|
+
const current = await lstat(path);
|
|
57
|
+
if (current.dev !== identity.dev || current.ino !== identity.ino || !current.isFile()) {
|
|
58
|
+
throw new Error("Shared Lima owner lock identity changed; refusing operation");
|
|
59
|
+
}
|
|
60
|
+
const content = JSON.parse(await readFile(path, "utf8"));
|
|
61
|
+
if (content.pid !== record.pid || content.nonce !== record.nonce) {
|
|
62
|
+
throw new Error("Shared Lima owner lock contents changed; refusing operation");
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
path,
|
|
67
|
+
instanceName,
|
|
68
|
+
assertHeld,
|
|
69
|
+
async release() {
|
|
70
|
+
if (released)
|
|
71
|
+
return;
|
|
72
|
+
try {
|
|
73
|
+
await assertHeld();
|
|
74
|
+
await unlink(path);
|
|
75
|
+
released = true;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await handle.close();
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
await handle.close();
|
|
85
|
+
// Do not unlink an ambiguous lock after an interrupted write.
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=lima-owner-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lima-owner-lock.js","sourceRoot":"","sources":["../../../src/core/remote-workspace-protocol/lima-owner-lock.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport { type FileHandle, lstat, open, readFile, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { prepareSharedLimaOwnerDirectory } from \"./lima-owner-directory.ts\";\n\nexport interface SharedLimaOwnerLock {\n\treadonly path: string;\n\treadonly instanceName: string;\n\tassertHeld(): Promise<void>;\n\trelease(): Promise<void>;\n}\n\ninterface LockRecord {\n\tpid: number;\n\tnonce: string;\n}\n\nfunction isAlive(pid: number): boolean {\n\tif (!Number.isSafeInteger(pid) || pid < 1) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\";\n\t}\n}\n\n/** Exclusive owner lifetime, not a client lease. Never silently steal a stale lock. */\nexport async function acquireSharedLimaOwnerLock(\n\tinstanceName: string,\n\tbaseDirectory?: string,\n): Promise<SharedLimaOwnerLock> {\n\tif (!/^[a-z0-9][a-z0-9-]*$/.test(instanceName)) throw new Error(\"Invalid shared Lima instance name\");\n\t// The production lock must not follow TMPDIR: separate processes can otherwise\n\t// claim the same named VM through different private temporary directories.\n\t// An explicit base is reserved for isolated embedded tests.\n\tconst directory = await prepareSharedLimaOwnerDirectory(baseDirectory ?? \"/tmp\");\n\tconst digest = createHash(\"sha256\").update(instanceName).digest(\"hex\").slice(0, 32);\n\tconst path = join(directory, `lima-owner-${digest}.lock`);\n\tconst record: LockRecord = { pid: process.pid, nonce: randomBytes(16).toString(\"hex\") };\n\tlet handle: FileHandle;\n\ttry {\n\t\thandle = await open(path, \"wx\", 0o600);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\t// Even a dead PID is ambiguous (crash during a mutation or VM startup). Manual\n\t\t// reconciliation is required; another owner must not implicitly take over.\n\t\tlet state = \"unverifiable\";\n\t\ttry {\n\t\t\tconst info = await lstat(path);\n\t\t\tif (info.isFile() && info.uid === process.getuid?.() && (info.mode & 0o077) === 0) {\n\t\t\t\tconst existing = JSON.parse(await readFile(path, \"utf8\")) as Partial<LockRecord>;\n\t\t\t\tstate = typeof existing.pid === \"number\" && isAlive(existing.pid) ? \"occupied\" : \"stale\";\n\t\t\t}\n\t\t} catch {\n\t\t\t// A racing file change is not grounds for a new owner.\n\t\t}\n\t\tthrow new Error(`Shared Lima owner lock ${state}; inspect and reconcile before retrying`);\n\t}\n\ttry {\n\t\tawait handle.writeFile(JSON.stringify(record));\n\t\tconst identity = await handle.stat();\n\t\tlet released = false;\n\t\tconst assertHeld = async (): Promise<void> => {\n\t\t\tif (released) throw new Error(\"Shared Lima owner lock already released\");\n\t\t\tconst current = await lstat(path);\n\t\t\tif (current.dev !== identity.dev || current.ino !== identity.ino || !current.isFile()) {\n\t\t\t\tthrow new Error(\"Shared Lima owner lock identity changed; refusing operation\");\n\t\t\t}\n\t\t\tconst content = JSON.parse(await readFile(path, \"utf8\")) as Partial<LockRecord>;\n\t\t\tif (content.pid !== record.pid || content.nonce !== record.nonce) {\n\t\t\t\tthrow new Error(\"Shared Lima owner lock contents changed; refusing operation\");\n\t\t\t}\n\t\t};\n\t\treturn {\n\t\t\tpath,\n\t\t\tinstanceName,\n\t\t\tassertHeld,\n\t\t\tasync release(): Promise<void> {\n\t\t\t\tif (released) return;\n\t\t\t\ttry {\n\t\t\t\t\tawait assertHeld();\n\t\t\t\t\tawait unlink(path);\n\t\t\t\t\treleased = true;\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tawait handle.close();\n\t\t// Do not unlink an ambiguous lock after an interrupted write.\n\t\tthrow error;\n\t}\n}\n"]}
|
|
@@ -59,6 +59,7 @@ export interface RemoteWorkspaceClientProtocolOptions {
|
|
|
59
59
|
maxTombstones?: number;
|
|
60
60
|
onCatalogChanged?: (event: RemoteWorkspaceCatalogChanged) => void;
|
|
61
61
|
onCatalogRefreshed?: (catalog: RemoteWorkspaceCatalog) => void | Promise<void>;
|
|
62
|
+
onDisconnect?: (message: string) => void;
|
|
62
63
|
}
|
|
63
64
|
export declare class RemoteWorkspaceClientProtocol {
|
|
64
65
|
private readonly transport;
|
|
@@ -72,6 +73,7 @@ export declare class RemoteWorkspaceClientProtocol {
|
|
|
72
73
|
private readonly maxTombstones;
|
|
73
74
|
private readonly onCatalogChanged;
|
|
74
75
|
private readonly onCatalogRefreshed;
|
|
76
|
+
private readonly onDisconnect;
|
|
75
77
|
private readonly connectionPrefix;
|
|
76
78
|
private readonly pending;
|
|
77
79
|
private readonly tombstones;
|