@hearsay-tools/squawk 0.17.0-dev.5723 → 0.17.0-dev.5728
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/dist/delegation/entry-exists.d.ts +2 -0
- package/dist/delegation/entry-exists.js +10 -0
- package/dist/delegation/entry-exists.js.map +1 -0
- package/dist/delegation/identity-file-store.d.ts +22 -0
- package/dist/delegation/identity-file-store.js +16 -0
- package/dist/delegation/identity-file-store.js.map +1 -0
- package/dist/delegation/posix-workspace-identity.d.ts +3 -0
- package/dist/delegation/posix-workspace-identity.js +68 -0
- package/dist/delegation/posix-workspace-identity.js.map +1 -0
- package/dist/delegation/routes.d.ts +75 -75
- package/dist/delegation/transport.d.ts +13 -13
- package/dist/delegation/windows-identity-store.d.ts +5 -0
- package/dist/delegation/windows-identity-store.js +15 -0
- package/dist/delegation/windows-identity-store.js.map +1 -0
- package/dist/delegation/workspace.js +9 -75
- package/dist/delegation/workspace.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/server/activity-routes.d.ts +23 -23
- package/dist/server/live-routes.d.ts +6 -6
- package/dist/server/server.d.ts +1571 -1571
- package/package.json +4 -4
- package/scripts/benchmark-family-reconcile.ts +4 -0
- package/scripts/benchmark-run-store.ts +4 -0
- package/scripts/benchmark-stuck-destroys.ts +4 -0
- package/scripts/benchmark-workspace-events.ts +4 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { lstat } from 'node:fs/promises';
|
|
2
|
+
/** Whether a directory entry exists at `path`, without following a final symlink. Any error but ENOENT throws. */
|
|
3
|
+
export async function entryExists(path) {
|
|
4
|
+
return lstat(path).then(() => true, (error) => {
|
|
5
|
+
if (error.code === 'ENOENT')
|
|
6
|
+
return false;
|
|
7
|
+
throw error;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=entry-exists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-exists.js","sourceRoot":"","sources":["../../src/delegation/entry-exists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,kHAAkH;AAClH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAA4B,EAAE,EAAE;QACnE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC1C,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the ownership policy in `workspace.ts` keeps its identity files: the receipt directory,
|
|
3
|
+
* receipts, cleanup checkpoints and Git administration markers. The store owns the platform's
|
|
4
|
+
* safety rules; the policy owns what the files prove (ADR 0032).
|
|
5
|
+
*
|
|
6
|
+
* A process entry installs the store for its host. Only entries import the Windows store, so the
|
|
7
|
+
* policy and its many importers never load it (hearsay-tools/cezarion#3244).
|
|
8
|
+
*/
|
|
9
|
+
export interface IdentityFileStore {
|
|
10
|
+
/** Create the private receipt directory when `create` is set, and refuse an existing unsafe one. */
|
|
11
|
+
directory(path: string, create: boolean): Promise<void>;
|
|
12
|
+
/** Read an identity file of at most `cap` bytes. `privateParent` is false for a marker in Git's admin directory. */
|
|
13
|
+
read(path: string, cap: number, privateParent: boolean): Promise<string>;
|
|
14
|
+
/** Create a new private identity file; fail when one exists. */
|
|
15
|
+
write(path: string, content: string, privateParent: boolean): Promise<void>;
|
|
16
|
+
/** Replace a private identity file atomically. `assertCurrent` throws when the caller lost ownership. */
|
|
17
|
+
replace(path: string, content: string, cap: number, assertCurrent?: () => void): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/** Install the store for this process; `undefined` restores the host default. */
|
|
20
|
+
export declare function installIdentityFileStore(store: IdentityFileStore | undefined): void;
|
|
21
|
+
/** The installed store, else the POSIX store on a non-Windows host. Windows has no default. */
|
|
22
|
+
export declare function identityFileStore(): IdentityFileStore;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { posixIdentityFileStore } from './posix-workspace-identity.js';
|
|
2
|
+
let installed;
|
|
3
|
+
/** Install the store for this process; `undefined` restores the host default. */
|
|
4
|
+
export function installIdentityFileStore(store) {
|
|
5
|
+
installed = store;
|
|
6
|
+
}
|
|
7
|
+
/** The installed store, else the POSIX store on a non-Windows host. Windows has no default. */
|
|
8
|
+
export function identityFileStore() {
|
|
9
|
+
if (installed)
|
|
10
|
+
return installed;
|
|
11
|
+
if (process.platform === 'win32') {
|
|
12
|
+
throw new Error('No workspace identity store is installed: a Windows process entry must call installWindowsIdentityStore');
|
|
13
|
+
}
|
|
14
|
+
return posixIdentityFileStore;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=identity-file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-file-store.js","sourceRoot":"","sources":["../../src/delegation/identity-file-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAqBvE,IAAI,SAAwC,CAAC;AAE7C,iFAAiF;AACjF,MAAM,UAAU,wBAAwB,CAAC,KAAoC;IAC3E,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,iBAAiB;IAC/B,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,yGAAyG,CAAC,CAAC;IAC7H,CAAC;IACD,OAAO,sBAAsB,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { lstat, mkdir, open, realpath, rename, rm } from 'node:fs/promises';
|
|
4
|
+
import { entryExists as exists } from './entry-exists.js';
|
|
5
|
+
async function directory(dir, create) {
|
|
6
|
+
if (create)
|
|
7
|
+
await mkdir(dir, { mode: 0o700 }).catch((error) => {
|
|
8
|
+
if (error.code !== 'EEXIST')
|
|
9
|
+
throw error;
|
|
10
|
+
});
|
|
11
|
+
if (await exists(dir)) {
|
|
12
|
+
const info = await lstat(dir);
|
|
13
|
+
if (!info.isDirectory() || info.isSymbolicLink() || await realpath(dir) !== dir || (info.mode & 0o077) !== 0) {
|
|
14
|
+
throw new Error('Unsafe owned workspace receipt directory');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function read(path, cap) {
|
|
19
|
+
const info = await lstat(path);
|
|
20
|
+
if (!info.isFile() || info.isSymbolicLink())
|
|
21
|
+
throw new Error('Unsafe owned workspace identity file');
|
|
22
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
23
|
+
try {
|
|
24
|
+
const opened = await file.stat();
|
|
25
|
+
if (!opened.isFile() || opened.size > cap || (opened.mode & 0o077) !== 0)
|
|
26
|
+
throw new Error('Unsafe owned workspace identity file');
|
|
27
|
+
const buffer = Buffer.alloc(cap + 1);
|
|
28
|
+
const { bytesRead } = await file.read(buffer, 0, buffer.length, 0);
|
|
29
|
+
if (bytesRead > cap)
|
|
30
|
+
throw new Error('Oversized owned workspace identity file');
|
|
31
|
+
return buffer.subarray(0, bytesRead).toString('utf8');
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await file.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function write(path, content) {
|
|
38
|
+
const file = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
39
|
+
try {
|
|
40
|
+
await file.writeFile(content);
|
|
41
|
+
await file.sync();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
await file.close();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function replace(path, content, cap, assertCurrent) {
|
|
48
|
+
if (await exists(path))
|
|
49
|
+
await read(path, cap);
|
|
50
|
+
assertCurrent?.();
|
|
51
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
52
|
+
await write(temporary, content);
|
|
53
|
+
try {
|
|
54
|
+
assertCurrent?.();
|
|
55
|
+
await rename(temporary, path);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await rm(temporary, { force: true });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Mode bits and no-follow opens: the directory is 0700, each file 0600, and a replace renames a temporary file. */
|
|
62
|
+
export const posixIdentityFileStore = {
|
|
63
|
+
directory,
|
|
64
|
+
read: (path, cap) => read(path, cap),
|
|
65
|
+
write: (path, content) => write(path, content),
|
|
66
|
+
replace,
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=posix-workspace-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posix-workspace-identity.js","sourceRoot":"","sources":["../../src/delegation/posix-workspace-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,WAAW,IAAI,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE1D,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,MAAe;IACnD,IAAI,MAAM;QAAE,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;YACnF,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QAC3C,CAAC,CAAC,CAAC;IACH,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,MAAM,QAAQ,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7G,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC;AACD,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,GAAW;IAC3C,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACrG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChG,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAClI,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACrC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACnE,IAAI,SAAS,GAAG,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAChF,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;YAAS,CAAC;QAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AACnC,CAAC;AACD,KAAK,UAAU,KAAK,CAAC,IAAY,EAAE,OAAe;IAChD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACvH,IAAI,CAAC;QAAC,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC3F,CAAC;AACD,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,OAAe,EAAE,GAAW,EAAE,aAA0B;IAC3F,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9C,aAAa,EAAE,EAAE,CAAC;IAClB,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAChD,MAAM,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC;QAAC,aAAa,EAAE,EAAE,CAAC;QAAC,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAAC,CAAC;AAC7G,CAAC;AAED,oHAAoH;AACpH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD,SAAS;IACT,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC;IACpC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;IAC9C,OAAO;CACR,CAAC"}
|
|
@@ -27,6 +27,18 @@ export declare function delegationFailure(error: unknown): {
|
|
|
27
27
|
export declare function createDelegationRoutes(service: DelegationService, credentials: CredentialRegistry): import("hono/hono-base").HonoBase<Env, {
|
|
28
28
|
"/list": {
|
|
29
29
|
$get: {
|
|
30
|
+
output: {
|
|
31
|
+
error: string;
|
|
32
|
+
code?: "invalid_input" | undefined;
|
|
33
|
+
};
|
|
34
|
+
outputFormat: "json";
|
|
35
|
+
status: 400;
|
|
36
|
+
input: {
|
|
37
|
+
query: {
|
|
38
|
+
offset?: string | undefined;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
} | {
|
|
30
42
|
output: {
|
|
31
43
|
workers: {
|
|
32
44
|
workerId: string;
|
|
@@ -64,24 +76,21 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
64
76
|
offset?: string | undefined;
|
|
65
77
|
};
|
|
66
78
|
};
|
|
67
|
-
} | {
|
|
68
|
-
output: {
|
|
69
|
-
error: string;
|
|
70
|
-
code?: "invalid_input" | undefined;
|
|
71
|
-
};
|
|
72
|
-
outputFormat: "json";
|
|
73
|
-
status: 400;
|
|
74
|
-
input: {
|
|
75
|
-
query: {
|
|
76
|
-
offset?: string | undefined;
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
79
|
};
|
|
80
80
|
};
|
|
81
81
|
} & {
|
|
82
82
|
"/discover": {
|
|
83
83
|
$post: {
|
|
84
84
|
output: {
|
|
85
|
+
scope: "host-default-account";
|
|
86
|
+
runners: {
|
|
87
|
+
status: "connected" | "disconnected" | "not-installed" | "unknown";
|
|
88
|
+
enabled?: boolean | undefined;
|
|
89
|
+
hint?: string | undefined;
|
|
90
|
+
authFailureId?: string | undefined;
|
|
91
|
+
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
92
|
+
}[];
|
|
93
|
+
} | {
|
|
85
94
|
tasks: {
|
|
86
95
|
id: string;
|
|
87
96
|
title: string;
|
|
@@ -93,15 +102,6 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
93
102
|
reason?: string | undefined;
|
|
94
103
|
}[];
|
|
95
104
|
nextOffset?: number | undefined;
|
|
96
|
-
} | {
|
|
97
|
-
scope: "host-default-account";
|
|
98
|
-
runners: {
|
|
99
|
-
status: "connected" | "disconnected" | "not-installed" | "unknown";
|
|
100
|
-
enabled?: boolean | undefined;
|
|
101
|
-
hint?: string | undefined;
|
|
102
|
-
authFailureId?: string | undefined;
|
|
103
|
-
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
104
|
-
}[];
|
|
105
105
|
} | {
|
|
106
106
|
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
107
107
|
models: {
|
|
@@ -221,13 +221,13 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
221
221
|
status: 200;
|
|
222
222
|
input: {
|
|
223
223
|
json: {
|
|
224
|
-
requestIds: string[];
|
|
225
|
-
mode?: "all" | "any" | "one" | undefined;
|
|
226
|
-
timeoutSeconds?: number | undefined;
|
|
227
|
-
} | {
|
|
228
224
|
workerIds: string[];
|
|
229
225
|
timeoutSeconds?: number | undefined;
|
|
230
226
|
mode?: "all" | "any" | "one" | undefined;
|
|
227
|
+
} | {
|
|
228
|
+
requestIds: string[];
|
|
229
|
+
mode?: "all" | "any" | "one" | undefined;
|
|
230
|
+
timeoutSeconds?: number | undefined;
|
|
231
231
|
} | {
|
|
232
232
|
peerIds: string[];
|
|
233
233
|
timeoutSeconds?: number | undefined;
|
|
@@ -613,6 +613,18 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
613
613
|
} & {
|
|
614
614
|
"/:workerId": {
|
|
615
615
|
$get: {
|
|
616
|
+
output: {
|
|
617
|
+
error: string;
|
|
618
|
+
code?: "invalid_input" | undefined;
|
|
619
|
+
};
|
|
620
|
+
outputFormat: "json";
|
|
621
|
+
status: 400;
|
|
622
|
+
input: {
|
|
623
|
+
param: {
|
|
624
|
+
workerId: string;
|
|
625
|
+
};
|
|
626
|
+
};
|
|
627
|
+
} | {
|
|
616
628
|
output: {
|
|
617
629
|
workerId: string;
|
|
618
630
|
parentRunId: string;
|
|
@@ -716,7 +728,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
716
728
|
workerId: string;
|
|
717
729
|
};
|
|
718
730
|
};
|
|
719
|
-
}
|
|
731
|
+
};
|
|
732
|
+
};
|
|
733
|
+
} & {
|
|
734
|
+
"/:workerId/collect": {
|
|
735
|
+
$post: {
|
|
720
736
|
output: {
|
|
721
737
|
error: string;
|
|
722
738
|
code?: "invalid_input" | undefined;
|
|
@@ -727,12 +743,10 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
727
743
|
param: {
|
|
728
744
|
workerId: string;
|
|
729
745
|
};
|
|
746
|
+
} & {
|
|
747
|
+
json: Record<string, never>;
|
|
730
748
|
};
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
} & {
|
|
734
|
-
"/:workerId/collect": {
|
|
735
|
-
$post: {
|
|
749
|
+
} | {
|
|
736
750
|
output: {
|
|
737
751
|
workerId: string;
|
|
738
752
|
parentRunId: string;
|
|
@@ -834,7 +848,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
834
848
|
} & {
|
|
835
849
|
json: Record<string, never>;
|
|
836
850
|
};
|
|
837
|
-
}
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
} & {
|
|
854
|
+
"/:workerId/steer": {
|
|
855
|
+
$post: {
|
|
838
856
|
output: {
|
|
839
857
|
error: string;
|
|
840
858
|
code?: "invalid_input" | undefined;
|
|
@@ -846,13 +864,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
846
864
|
workerId: string;
|
|
847
865
|
};
|
|
848
866
|
} & {
|
|
849
|
-
json:
|
|
867
|
+
json: {
|
|
868
|
+
text: string;
|
|
869
|
+
};
|
|
850
870
|
};
|
|
851
|
-
}
|
|
852
|
-
};
|
|
853
|
-
} & {
|
|
854
|
-
"/:workerId/steer": {
|
|
855
|
-
$post: {
|
|
871
|
+
} | {
|
|
856
872
|
output: {
|
|
857
873
|
workerId: string;
|
|
858
874
|
state: "delivered" | "queued";
|
|
@@ -868,7 +884,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
868
884
|
text: string;
|
|
869
885
|
};
|
|
870
886
|
};
|
|
871
|
-
}
|
|
887
|
+
};
|
|
888
|
+
};
|
|
889
|
+
} & {
|
|
890
|
+
"/:workerId/stop": {
|
|
891
|
+
$post: {
|
|
872
892
|
output: {
|
|
873
893
|
error: string;
|
|
874
894
|
code?: "invalid_input" | undefined;
|
|
@@ -880,15 +900,9 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
880
900
|
workerId: string;
|
|
881
901
|
};
|
|
882
902
|
} & {
|
|
883
|
-
json:
|
|
884
|
-
text: string;
|
|
885
|
-
};
|
|
903
|
+
json: Record<string, never>;
|
|
886
904
|
};
|
|
887
|
-
}
|
|
888
|
-
};
|
|
889
|
-
} & {
|
|
890
|
-
"/:workerId/stop": {
|
|
891
|
-
$post: {
|
|
905
|
+
} | {
|
|
892
906
|
output: {
|
|
893
907
|
workerId: string;
|
|
894
908
|
state: "stopping" | "terminated";
|
|
@@ -902,7 +916,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
902
916
|
} & {
|
|
903
917
|
json: Record<string, never>;
|
|
904
918
|
};
|
|
905
|
-
}
|
|
919
|
+
};
|
|
920
|
+
};
|
|
921
|
+
} & {
|
|
922
|
+
"/:workerId/destroy": {
|
|
923
|
+
$post: {
|
|
906
924
|
output: {
|
|
907
925
|
error: string;
|
|
908
926
|
code?: "invalid_input" | undefined;
|
|
@@ -916,11 +934,7 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
916
934
|
} & {
|
|
917
935
|
json: Record<string, never>;
|
|
918
936
|
};
|
|
919
|
-
}
|
|
920
|
-
};
|
|
921
|
-
} & {
|
|
922
|
-
"/:workerId/destroy": {
|
|
923
|
-
$post: {
|
|
937
|
+
} | {
|
|
924
938
|
output: {
|
|
925
939
|
workerId: string;
|
|
926
940
|
state: "complete" | "incomplete";
|
|
@@ -943,20 +957,6 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
943
957
|
} & {
|
|
944
958
|
json: Record<string, never>;
|
|
945
959
|
};
|
|
946
|
-
} | {
|
|
947
|
-
output: {
|
|
948
|
-
error: string;
|
|
949
|
-
code?: "invalid_input" | undefined;
|
|
950
|
-
};
|
|
951
|
-
outputFormat: "json";
|
|
952
|
-
status: 400;
|
|
953
|
-
input: {
|
|
954
|
-
param: {
|
|
955
|
-
workerId: string;
|
|
956
|
-
};
|
|
957
|
-
} & {
|
|
958
|
-
json: Record<string, never>;
|
|
959
|
-
};
|
|
960
960
|
} | {
|
|
961
961
|
output: {
|
|
962
962
|
workerId: string;
|
|
@@ -986,13 +986,11 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
986
986
|
"/:workerId/diff": {
|
|
987
987
|
$get: {
|
|
988
988
|
output: {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
diff: string;
|
|
992
|
-
truncated: boolean;
|
|
989
|
+
error: string;
|
|
990
|
+
code?: "invalid_input" | undefined;
|
|
993
991
|
};
|
|
994
992
|
outputFormat: "json";
|
|
995
|
-
status:
|
|
993
|
+
status: 400;
|
|
996
994
|
input: {
|
|
997
995
|
param: {
|
|
998
996
|
workerId: string;
|
|
@@ -1000,11 +998,13 @@ export declare function createDelegationRoutes(service: DelegationService, crede
|
|
|
1000
998
|
};
|
|
1001
999
|
} | {
|
|
1002
1000
|
output: {
|
|
1003
|
-
|
|
1004
|
-
|
|
1001
|
+
workerId: string;
|
|
1002
|
+
baselineSha: string;
|
|
1003
|
+
diff: string;
|
|
1004
|
+
truncated: boolean;
|
|
1005
1005
|
};
|
|
1006
1006
|
outputFormat: "json";
|
|
1007
|
-
status:
|
|
1007
|
+
status: 200;
|
|
1008
1008
|
input: {
|
|
1009
1009
|
param: {
|
|
1010
1010
|
workerId: string;
|
|
@@ -57,6 +57,15 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
57
57
|
"/discover": {
|
|
58
58
|
$post: {
|
|
59
59
|
output: {
|
|
60
|
+
scope: "host-default-account";
|
|
61
|
+
runners: {
|
|
62
|
+
status: "connected" | "disconnected" | "not-installed" | "unknown";
|
|
63
|
+
enabled?: boolean | undefined;
|
|
64
|
+
hint?: string | undefined;
|
|
65
|
+
authFailureId?: string | undefined;
|
|
66
|
+
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
67
|
+
}[];
|
|
68
|
+
} | {
|
|
60
69
|
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
61
70
|
models: {
|
|
62
71
|
id: string;
|
|
@@ -67,15 +76,6 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
67
76
|
source: "cache" | "live" | "unavailable";
|
|
68
77
|
stale: boolean;
|
|
69
78
|
reason?: string | undefined;
|
|
70
|
-
} | {
|
|
71
|
-
scope: "host-default-account";
|
|
72
|
-
runners: {
|
|
73
|
-
status: "connected" | "disconnected" | "not-installed" | "unknown";
|
|
74
|
-
enabled?: boolean | undefined;
|
|
75
|
-
hint?: string | undefined;
|
|
76
|
-
authFailureId?: string | undefined;
|
|
77
|
-
runner: "claude" | "codex" | "cursor" | "omp" | "opencode" | "pi";
|
|
78
|
-
}[];
|
|
79
79
|
} | {
|
|
80
80
|
tasks: {
|
|
81
81
|
id: string;
|
|
@@ -196,13 +196,13 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
196
196
|
status: 200;
|
|
197
197
|
input: {
|
|
198
198
|
json: {
|
|
199
|
-
workerIds: string[];
|
|
200
|
-
timeoutSeconds?: number | undefined;
|
|
201
|
-
mode?: "all" | "any" | "one" | undefined;
|
|
202
|
-
} | {
|
|
203
199
|
requestIds: string[];
|
|
204
200
|
mode?: "all" | "any" | "one" | undefined;
|
|
205
201
|
timeoutSeconds?: number | undefined;
|
|
202
|
+
} | {
|
|
203
|
+
workerIds: string[];
|
|
204
|
+
timeoutSeconds?: number | undefined;
|
|
205
|
+
mode?: "all" | "any" | "one" | undefined;
|
|
206
206
|
} | {
|
|
207
207
|
peerIds: string[];
|
|
208
208
|
timeoutSeconds?: number | undefined;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type IdentityFileStore } from './identity-file-store.ts';
|
|
2
|
+
/** Protected ACLs through the native helper (ADR 0032); a replace overwrites in place, atomically. */
|
|
3
|
+
export declare const windowsIdentityFileStore: IdentityFileStore;
|
|
4
|
+
/** Called by each process entry that reaches `workspace.ts`; installs the Windows store on a Windows host only. */
|
|
5
|
+
export declare function installWindowsIdentityStore(platform?: NodeJS.Platform): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { installIdentityFileStore } from './identity-file-store.js';
|
|
2
|
+
import { windowsIdentityDirectory, windowsReadIdentity, windowsWriteIdentity } from './windows-workspace-identity.js';
|
|
3
|
+
/** Protected ACLs through the native helper (ADR 0032); a replace overwrites in place, atomically. */
|
|
4
|
+
export const windowsIdentityFileStore = {
|
|
5
|
+
directory: async (path, create) => { windowsIdentityDirectory(path, create); },
|
|
6
|
+
read: async (path, cap, privateParent) => windowsReadIdentity(path, cap, privateParent),
|
|
7
|
+
write: async (path, content, privateParent) => { windowsWriteIdentity(path, content, false, privateParent); },
|
|
8
|
+
replace: async (path, content) => { windowsWriteIdentity(path, content, true); },
|
|
9
|
+
};
|
|
10
|
+
/** Called by each process entry that reaches `workspace.ts`; installs the Windows store on a Windows host only. */
|
|
11
|
+
export function installWindowsIdentityStore(platform = process.platform) {
|
|
12
|
+
if (platform === 'win32')
|
|
13
|
+
installIdentityFileStore(windowsIdentityFileStore);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=windows-identity-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-identity-store.js","sourceRoot":"","sources":["../../src/delegation/windows-identity-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAA0B,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEtH,sGAAsG;AACtG,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,wBAAwB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC9E,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC;IACvF,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,GAAG,oBAAoB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC7G,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,oBAAoB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;CACjF,CAAC;AAEF,mHAAmH;AACnH,MAAM,UAAU,2BAA2B,CAAC,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IACtF,IAAI,QAAQ,KAAK,OAAO;QAAE,wBAAwB,CAAC,wBAAwB,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { projectPaths, fallbackProjectWriteError } from '../project-paths.js';
|
|
2
2
|
import { inspectGeneration } from './process-liveness.js';
|
|
3
3
|
import { waitForTestAppWatcher, withIdleTestApp } from './idle-test-app.js';
|
|
4
|
-
import {
|
|
4
|
+
import { identityFileStore } from './identity-file-store.js';
|
|
5
|
+
import { entryExists as exists } from './entry-exists.js';
|
|
5
6
|
import { execFile } from 'node:child_process';
|
|
6
7
|
import { createHash, randomUUID } from 'node:crypto';
|
|
7
8
|
import { constants } from 'node:fs';
|
|
8
|
-
import {
|
|
9
|
+
import { mkdtemp, open, readdir, realpath, rm } from 'node:fs/promises';
|
|
9
10
|
import { tmpdir } from 'node:os';
|
|
10
11
|
import { dirname, join, normalize } from 'node:path';
|
|
11
12
|
import { z } from 'zod';
|
|
@@ -17,8 +18,6 @@ import { resolveTaskDiffBase } from '../git-diff-base.js';
|
|
|
17
18
|
import { isSafeGitRef } from '../git-refs.js';
|
|
18
19
|
import { DelegationPolicyError } from './policy.js';
|
|
19
20
|
const RECEIPT_CAP = 16_384;
|
|
20
|
-
// Filesystem primitives belong to the host that loaded this module.
|
|
21
|
-
const windowsIdentities = process.platform === 'win32';
|
|
22
21
|
// Identify owned branches by tip and reflog contents, not inode identity.
|
|
23
22
|
// Keep file/logFile fields for older strict checkpoint readers.
|
|
24
23
|
const fileIdentitySchema = z.object({ dev: z.number(), ino: z.number(), birthtimeMs: z.number() }).strict();
|
|
@@ -67,22 +66,7 @@ async function writeCleanup(path, value, assertCurrent) {
|
|
|
67
66
|
}
|
|
68
67
|
async function replaceIdentityFile(path, content, assertCurrent) {
|
|
69
68
|
assertCurrent?.();
|
|
70
|
-
|
|
71
|
-
windowsWriteIdentity(path, content, true);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
if (await exists(path))
|
|
75
|
-
await readIdentityFile(path, RECEIPT_CAP);
|
|
76
|
-
assertCurrent?.();
|
|
77
|
-
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
78
|
-
await writeIdentityFile(temporary, content);
|
|
79
|
-
try {
|
|
80
|
-
assertCurrent?.();
|
|
81
|
-
await rename(temporary, path);
|
|
82
|
-
}
|
|
83
|
-
finally {
|
|
84
|
-
await rm(temporary, { force: true });
|
|
85
|
-
}
|
|
69
|
+
await identityFileStore().replace(path, content, RECEIPT_CAP, assertCurrent);
|
|
86
70
|
}
|
|
87
71
|
function git(cwd, args, index, maxBuffer = 32 * 1024 * 1024) {
|
|
88
72
|
return new Promise((done) => {
|
|
@@ -104,13 +88,6 @@ async function checkedGit(cwd, args, index) {
|
|
|
104
88
|
export async function gitCommonDir(cwd) {
|
|
105
89
|
return realpath(await checkedGit(cwd, ['rev-parse', '--path-format=absolute', '--git-common-dir']));
|
|
106
90
|
}
|
|
107
|
-
async function exists(path) {
|
|
108
|
-
return lstat(path).then(() => true, (error) => {
|
|
109
|
-
if (error.code === 'ENOENT')
|
|
110
|
-
return false;
|
|
111
|
-
throw error;
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
91
|
/** Reads only committed state in the server-known parent cwd; never flushes its edits. */
|
|
115
92
|
export async function resolveWorkerBaseline(repoRoot, parentCwd, baseline) {
|
|
116
93
|
try {
|
|
@@ -164,21 +141,7 @@ async function receiptLocation(repoRoot, workspace, create = false) {
|
|
|
164
141
|
}
|
|
165
142
|
async function receiptDirectory(repoRoot, create) {
|
|
166
143
|
const dir = join(await gitCommonDir(repoRoot), 'cezar-owned-workspaces');
|
|
167
|
-
|
|
168
|
-
windowsIdentityDirectory(dir, create);
|
|
169
|
-
return dir;
|
|
170
|
-
}
|
|
171
|
-
if (create)
|
|
172
|
-
await mkdir(dir, { mode: 0o700 }).catch((error) => {
|
|
173
|
-
if (error.code !== 'EEXIST')
|
|
174
|
-
throw error;
|
|
175
|
-
});
|
|
176
|
-
if (await exists(dir)) {
|
|
177
|
-
const info = await lstat(dir);
|
|
178
|
-
if (!info.isDirectory() || info.isSymbolicLink() || await realpath(dir) !== dir || (info.mode & 0o077) !== 0) {
|
|
179
|
-
throw new Error('Unsafe owned workspace receipt directory');
|
|
180
|
-
}
|
|
181
|
-
}
|
|
144
|
+
await identityFileStore().directory(dir, create);
|
|
182
145
|
return dir;
|
|
183
146
|
}
|
|
184
147
|
/** The receipt and cleanup checkpoint files in the repository's shared receipt directory, checked
|
|
@@ -197,40 +160,11 @@ export function readOwnedWorkspaceRecord(path) {
|
|
|
197
160
|
export function replaceOwnedWorkspaceRecord(path, content) {
|
|
198
161
|
return replaceIdentityFile(path, content);
|
|
199
162
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return windowsReadIdentity(path, cap, privateParent);
|
|
203
|
-
const info = await lstat(path);
|
|
204
|
-
if (!info.isFile() || info.isSymbolicLink())
|
|
205
|
-
throw new Error('Unsafe owned workspace identity file');
|
|
206
|
-
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
207
|
-
try {
|
|
208
|
-
const opened = await file.stat();
|
|
209
|
-
if (!opened.isFile() || opened.size > cap || (opened.mode & 0o077) !== 0)
|
|
210
|
-
throw new Error('Unsafe owned workspace identity file');
|
|
211
|
-
const buffer = Buffer.alloc(cap + 1);
|
|
212
|
-
const { bytesRead } = await file.read(buffer, 0, buffer.length, 0);
|
|
213
|
-
if (bytesRead > cap)
|
|
214
|
-
throw new Error('Oversized owned workspace identity file');
|
|
215
|
-
return buffer.subarray(0, bytesRead).toString('utf8');
|
|
216
|
-
}
|
|
217
|
-
finally {
|
|
218
|
-
await file.close();
|
|
219
|
-
}
|
|
163
|
+
function readIdentityFile(path, cap, privateParent = true) {
|
|
164
|
+
return identityFileStore().read(path, cap, privateParent);
|
|
220
165
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
windowsWriteIdentity(path, content, false, privateParent);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const file = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
227
|
-
try {
|
|
228
|
-
await file.writeFile(content);
|
|
229
|
-
await file.sync();
|
|
230
|
-
}
|
|
231
|
-
finally {
|
|
232
|
-
await file.close();
|
|
233
|
-
}
|
|
166
|
+
function writeIdentityFile(path, content, privateParent = true) {
|
|
167
|
+
return identityFileStore().write(path, content, privateParent);
|
|
234
168
|
}
|
|
235
169
|
async function readReceipt(path) {
|
|
236
170
|
if (!await exists(path))
|