@sortedyuan/maybecode 0.3.2 → 0.5.0
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/README.md +166 -55
- package/README.zh-CN.md +267 -0
- package/dist/application.d.ts +40 -34
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +290 -170
- package/dist/application.js.map +1 -1
- package/dist/args.d.ts +2 -2
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +50 -27
- package/dist/args.js.map +1 -1
- package/dist/bin.js +82 -71
- package/dist/bin.js.map +4 -4
- package/dist/cli/chunk-3IORPKBL.js +3572 -0
- package/dist/cli/chunk-3IORPKBL.js.map +7 -0
- package/dist/cli/{chunk-LVTRXPDS.js → chunk-4B2Z6KW7.js} +1547 -1536
- package/dist/cli/chunk-4B2Z6KW7.js.map +7 -0
- package/dist/cli/{chunk-JT6VBKOM.js → chunk-4WG6JIJJ.js} +127 -33
- package/dist/cli/{chunk-JT6VBKOM.js.map → chunk-4WG6JIJJ.js.map} +3 -3
- package/dist/cli/{chunk-K5JWPNSY.js → chunk-5SLWALZK.js} +3521 -16164
- package/dist/cli/chunk-5SLWALZK.js.map +7 -0
- package/dist/cli/chunk-MNBYXL5Y.js +132 -0
- package/dist/cli/chunk-MNBYXL5Y.js.map +7 -0
- package/dist/cli/{chunk-F4XRPLUM.js → chunk-SLWLUEHQ.js} +226 -86
- package/dist/cli/chunk-SLWLUEHQ.js.map +7 -0
- package/dist/cli/chunk-UQDZ55LQ.js +199 -0
- package/dist/cli/chunk-UQDZ55LQ.js.map +7 -0
- package/dist/cli/{chunk-7ISOHFS7.js → chunk-WMSG5ZTR.js} +717 -388
- package/dist/cli/chunk-WMSG5ZTR.js.map +7 -0
- package/dist/cli/chunk-WVIRS76R.js +4057 -0
- package/dist/cli/chunk-WVIRS76R.js.map +7 -0
- package/dist/cli/{chunk-HOU5ITUK.js → chunk-XTEMRAQW.js} +1 -1
- package/dist/cli/chunk-XTEMRAQW.js.map +7 -0
- package/dist/cli/chunk-Z3BOPBVU.js +91 -0
- package/dist/cli/chunk-Z3BOPBVU.js.map +7 -0
- package/dist/cli/{configured-WHY3GGAJ.js → configured-ACNM6TRQ.js} +10 -9
- package/dist/cli/{file-type-R2T7TBHI.js → file-type-HLHPV7WC.js} +817 -13
- package/dist/cli/file-type-HLHPV7WC.js.map +7 -0
- package/dist/cli/mcp-auth-XD5U7WCV.js +74 -0
- package/dist/cli/mcp-auth-XD5U7WCV.js.map +7 -0
- package/dist/cli/onboarding-WQWCPYEO.js +530 -0
- package/dist/cli/onboarding-WQWCPYEO.js.map +7 -0
- package/dist/cli/onboarding-check-HRRI5OJ7.js +32 -0
- package/dist/cli/onboarding-check-HRRI5OJ7.js.map +7 -0
- package/dist/cli/{retained-tui-VJ3VX4R3.js → retained-tui-QF5VMYLC.js} +788 -332
- package/dist/cli/retained-tui-QF5VMYLC.js.map +7 -0
- package/dist/cli/{sixel-LWTCM76G.js → sixel-ISZ4FZ3U.js} +37 -37
- package/dist/cli/{sixel-LWTCM76G.js.map → sixel-ISZ4FZ3U.js.map} +1 -1
- package/dist/cli/{team-T7G7PPNN.js → team-O2I5BXHM.js} +7 -6
- package/dist/cli/{team-v2-JGBBQ7FR.js → team-v2-YYO2G7DJ.js} +816 -390
- package/dist/cli/team-v2-YYO2G7DJ.js.map +7 -0
- package/dist/cli/{web-server-FOMNPY7Q.js → web-server-SXMH6FGA.js} +55 -19
- package/dist/cli/web-server-SXMH6FGA.js.map +7 -0
- package/dist/cli/{web-ui-COB6PKC5.js → web-ui-UWQUFE4W.js} +7 -6
- package/dist/config-schema.json +337 -0
- package/dist/configured.d.ts +18 -11
- package/dist/configured.d.ts.map +1 -1
- package/dist/configured.js +213 -390
- package/dist/configured.js.map +1 -1
- package/dist/controller.d.ts +19 -18
- package/dist/controller.d.ts.map +1 -1
- package/dist/delegation-commands.d.ts +1 -1
- package/dist/delegation-commands.d.ts.map +1 -1
- package/dist/delegation-commands.js +8 -8
- package/dist/delegation-commands.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +8 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/fork-picker.d.ts.map +1 -1
- package/dist/fork-picker.js +19 -5
- package/dist/fork-picker.js.map +1 -1
- package/dist/git-request.d.ts +6 -6
- package/dist/git-request.d.ts.map +1 -1
- package/dist/git-request.js +28 -15
- package/dist/git-request.js.map +1 -1
- package/dist/goal-commands.d.ts +1 -1
- package/dist/goal-commands.d.ts.map +1 -1
- package/dist/goal-commands.js +12 -5
- package/dist/goal-commands.js.map +1 -1
- package/dist/index.d.ts +5 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -36
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +2 -7
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +7 -15
- package/dist/instructions.js.map +1 -1
- package/dist/keymap.d.ts +2 -2
- package/dist/keymap.d.ts.map +1 -1
- package/dist/keymap.js +2 -2
- package/dist/keymap.js.map +1 -1
- package/dist/maybecode-config.schema.json +1765 -0
- package/dist/mcp-auth.d.ts +1 -1
- package/dist/mcp-auth.d.ts.map +1 -1
- package/dist/mcp-auth.js +11 -8
- package/dist/mcp-auth.js.map +1 -1
- package/dist/mcp-commands.d.ts.map +1 -1
- package/dist/mcp-commands.js +18 -4
- package/dist/mcp-commands.js.map +1 -1
- package/dist/mcp-interaction-ui.d.ts.map +1 -1
- package/dist/mcp-interaction-ui.js +11 -4
- package/dist/mcp-interaction-ui.js.map +1 -1
- package/dist/media-history.d.ts +1 -1
- package/dist/media-history.d.ts.map +1 -1
- package/dist/media-history.js +8 -2
- package/dist/media-history.js.map +1 -1
- package/dist/model-picker.d.ts.map +1 -1
- package/dist/model-picker.js +10 -11
- package/dist/model-picker.js.map +1 -1
- package/dist/model-transition.d.ts +11 -0
- package/dist/model-transition.d.ts.map +1 -0
- package/dist/model-transition.js +48 -0
- package/dist/model-transition.js.map +1 -0
- package/dist/model.d.ts +2 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +8 -4
- package/dist/model.js.map +1 -1
- package/dist/onboarding-check.d.ts +3 -0
- package/dist/onboarding-check.d.ts.map +1 -0
- package/dist/onboarding-check.js +22 -0
- package/dist/onboarding-check.js.map +1 -0
- package/dist/onboarding.d.ts +6 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/onboarding.js +463 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/plugins/application.d.ts +6 -4
- package/dist/plugins/application.d.ts.map +1 -1
- package/dist/plugins/application.js +106 -52
- package/dist/plugins/application.js.map +1 -1
- package/dist/plugins/instructions.d.ts +1 -1
- package/dist/plugins/instructions.d.ts.map +1 -1
- package/dist/plugins/instructions.js +24 -11
- package/dist/plugins/instructions.js.map +1 -1
- package/dist/plugins/resources.d.ts +2 -2
- package/dist/plugins/resources.d.ts.map +1 -1
- package/dist/plugins/resources.js +22 -12
- package/dist/plugins/resources.js.map +1 -1
- package/dist/policy.d.ts +1 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +59 -11
- package/dist/policy.js.map +1 -1
- package/dist/run.d.ts +2 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +38 -33
- package/dist/run.js.map +1 -1
- package/dist/runtime-instructions.d.ts +1 -1
- package/dist/runtime-instructions.d.ts.map +1 -1
- package/dist/runtime-instructions.js +15 -7
- package/dist/runtime-instructions.js.map +1 -1
- package/dist/session-navigation.d.ts +6 -0
- package/dist/session-navigation.d.ts.map +1 -0
- package/dist/session-navigation.js +64 -0
- package/dist/session-navigation.js.map +1 -0
- package/dist/session-picker.d.ts +1 -1
- package/dist/session-picker.d.ts.map +1 -1
- package/dist/session-picker.js +23 -32
- package/dist/session-picker.js.map +1 -1
- package/dist/settings.d.ts +718 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +14 -0
- package/dist/settings.js.map +1 -0
- package/dist/skills.d.ts +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +10 -12
- package/dist/skills.js.map +1 -1
- package/dist/slash-commands.d.ts +2 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +149 -67
- package/dist/slash-commands.js.map +1 -1
- package/dist/team-execution.d.ts +10 -0
- package/dist/team-execution.d.ts.map +1 -0
- package/dist/team-execution.js +29 -0
- package/dist/team-execution.js.map +1 -0
- package/dist/team-patches.d.ts.map +1 -1
- package/dist/team-patches.js +149 -52
- package/dist/team-patches.js.map +1 -1
- package/dist/team-plan.d.ts +2 -2
- package/dist/team-plan.d.ts.map +1 -1
- package/dist/team-plan.js +115 -34
- package/dist/team-plan.js.map +1 -1
- package/dist/team-recovery.d.ts +1 -1
- package/dist/team-recovery.d.ts.map +1 -1
- package/dist/team-recovery.js +40 -10
- package/dist/team-recovery.js.map +1 -1
- package/dist/team-v2.d.ts.map +1 -1
- package/dist/team-v2.js +335 -104
- package/dist/team-v2.js.map +1 -1
- package/dist/team-verification.d.ts +4 -2
- package/dist/team-verification.d.ts.map +1 -1
- package/dist/team-verification.js +300 -97
- package/dist/team-verification.js.map +1 -1
- package/dist/team.d.ts +2 -2
- package/dist/team.d.ts.map +1 -1
- package/dist/team.js +172 -62
- package/dist/team.js.map +1 -1
- package/dist/terminal-web.d.ts +1 -0
- package/dist/terminal-web.d.ts.map +1 -1
- package/dist/terminal-web.js +28 -10
- package/dist/terminal-web.js.map +1 -1
- package/dist/ui/actions.d.ts.map +1 -1
- package/dist/ui/actions.js.map +1 -1
- package/dist/ui/retained-tui.d.ts.map +1 -1
- package/dist/ui/retained-tui.js +231 -173
- package/dist/ui/retained-tui.js.map +1 -1
- package/dist/ui/{prototype-view.d.ts → terminal-view.d.ts} +7 -7
- package/dist/ui/terminal-view.d.ts.map +1 -0
- package/dist/ui/{prototype-view.js → terminal-view.js} +185 -98
- package/dist/ui/terminal-view.js.map +1 -0
- package/dist/web-commands.d.ts.map +1 -1
- package/dist/web-commands.js +160 -57
- package/dist/web-commands.js.map +1 -1
- package/dist/web-extension.d.ts.map +1 -1
- package/dist/web-extension.js +14 -4
- package/dist/web-extension.js.map +1 -1
- package/dist/web-server.d.ts.map +1 -1
- package/dist/web-server.js +2 -1
- package/dist/web-server.js.map +1 -1
- package/dist/web-ui.d.ts.map +1 -1
- package/dist/web-ui.js +167 -40
- package/dist/web-ui.js.map +1 -1
- package/dist/workspace-configuration.d.ts +7 -0
- package/dist/workspace-configuration.d.ts.map +1 -0
- package/dist/workspace-configuration.js +134 -0
- package/dist/workspace-configuration.js.map +1 -0
- package/dist/workspace-state.d.ts +20 -0
- package/dist/workspace-state.d.ts.map +1 -0
- package/dist/workspace-state.js +2 -0
- package/dist/workspace-state.js.map +1 -0
- package/dist/workspace.d.ts +26 -43
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +261 -323
- package/dist/workspace.js.map +1 -1
- package/package.json +21 -31
- package/dist/cli/chunk-7ISOHFS7.js.map +0 -7
- package/dist/cli/chunk-F4XRPLUM.js.map +0 -7
- package/dist/cli/chunk-H7SNBFO4.js +0 -5522
- package/dist/cli/chunk-H7SNBFO4.js.map +0 -7
- package/dist/cli/chunk-HOU5ITUK.js.map +0 -7
- package/dist/cli/chunk-K5JWPNSY.js.map +0 -7
- package/dist/cli/chunk-LVTRXPDS.js.map +0 -7
- package/dist/cli/chunk-VAZMCNBB.js +0 -686
- package/dist/cli/chunk-VAZMCNBB.js.map +0 -7
- package/dist/cli/chunk-WOFEI42C.js +0 -7820
- package/dist/cli/chunk-WOFEI42C.js.map +0 -7
- package/dist/cli/file-type-R2T7TBHI.js.map +0 -7
- package/dist/cli/mcp-auth-UNRHSIKJ.js +0 -63
- package/dist/cli/mcp-auth-UNRHSIKJ.js.map +0 -7
- package/dist/cli/retained-tui-VJ3VX4R3.js.map +0 -7
- package/dist/cli/team-v2-JGBBQ7FR.js.map +0 -7
- package/dist/cli/tui-SA74DKMA.js +0 -1705
- package/dist/cli/tui-SA74DKMA.js.map +0 -7
- package/dist/cli/web-server-FOMNPY7Q.js.map +0 -7
- package/dist/delegation.d.ts +0 -2
- package/dist/delegation.d.ts.map +0 -1
- package/dist/delegation.js +0 -2
- package/dist/delegation.js.map +0 -1
- package/dist/history-memory.d.ts +0 -2
- package/dist/history-memory.d.ts.map +0 -1
- package/dist/history-memory.js +0 -2
- package/dist/history-memory.js.map +0 -1
- package/dist/subagent-budget.d.ts +0 -2
- package/dist/subagent-budget.d.ts.map +0 -1
- package/dist/subagent-budget.js +0 -2
- package/dist/subagent-budget.js.map +0 -1
- package/dist/subagent-files.d.ts +0 -2
- package/dist/subagent-files.d.ts.map +0 -1
- package/dist/subagent-files.js +0 -2
- package/dist/subagent-files.js.map +0 -1
- package/dist/subagent-host.d.ts +0 -2
- package/dist/subagent-host.d.ts.map +0 -1
- package/dist/subagent-host.js +0 -2
- package/dist/subagent-host.js.map +0 -1
- package/dist/subagent-instructions.d.ts +0 -2
- package/dist/subagent-instructions.d.ts.map +0 -1
- package/dist/subagent-instructions.js +0 -2
- package/dist/subagent-instructions.js.map +0 -1
- package/dist/subagents.d.ts +0 -2
- package/dist/subagents.d.ts.map +0 -1
- package/dist/subagents.js +0 -2
- package/dist/subagents.js.map +0 -1
- package/dist/summarizer.d.ts +0 -2
- package/dist/summarizer.d.ts.map +0 -1
- package/dist/summarizer.js +0 -2
- package/dist/summarizer.js.map +0 -1
- package/dist/tui.d.ts +0 -7
- package/dist/tui.d.ts.map +0 -1
- package/dist/tui.js +0 -1109
- package/dist/tui.js.map +0 -1
- package/dist/ui/prototype-view.d.ts.map +0 -1
- package/dist/ui/prototype-view.js.map +0 -1
- /package/dist/cli/{configured-WHY3GGAJ.js.map → configured-ACNM6TRQ.js.map} +0 -0
- /package/dist/cli/{team-T7G7PPNN.js.map → team-O2I5BXHM.js.map} +0 -0
- /package/dist/cli/{web-ui-COB6PKC5.js.map → web-ui-UWQUFE4W.js.map} +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { acquireFileLock,
|
|
1
|
+
import { acquireFileLock, hasErrorCode } from "@sortedyuan/may/storage";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
3
|
import { constants } from "node:fs";
|
|
5
4
|
import { lstat, mkdir, open, readdir, realpath } from "node:fs/promises";
|
|
6
5
|
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
7
6
|
import { isDeepStrictEqual } from "node:util";
|
|
8
|
-
import { AsyncStateSerializer } from "@sortedyuan/
|
|
7
|
+
import { AsyncStateSerializer } from "@sortedyuan/may/core";
|
|
8
|
+
import { openCodingExecutionEnvironment } from "@sortedyuan/coding-tools";
|
|
9
9
|
const maxJournalBytes = 16_777_216;
|
|
10
10
|
/** Host evidence and deterministic checks; a model report can never grant acceptance. */
|
|
11
11
|
export class TeamVerificationStore {
|
|
12
12
|
file;
|
|
13
13
|
lock;
|
|
14
|
-
lockPath;
|
|
15
14
|
checks;
|
|
15
|
+
executionFor;
|
|
16
16
|
serial = new AsyncStateSerializer();
|
|
17
17
|
reports = [];
|
|
18
18
|
results = new Map();
|
|
@@ -21,11 +21,11 @@ export class TeamVerificationStore {
|
|
|
21
21
|
failed = false;
|
|
22
22
|
closing;
|
|
23
23
|
active = new Set();
|
|
24
|
-
constructor(file, lock,
|
|
24
|
+
constructor(file, lock, checks, executionFor) {
|
|
25
25
|
this.file = file;
|
|
26
26
|
this.lock = lock;
|
|
27
|
-
this.lockPath = lockPath;
|
|
28
27
|
this.checks = checks;
|
|
28
|
+
this.executionFor = executionFor;
|
|
29
29
|
}
|
|
30
30
|
static async open(options) {
|
|
31
31
|
const checks = parseTeamChecks(options.checks ?? []);
|
|
@@ -33,12 +33,9 @@ export class TeamVerificationStore {
|
|
|
33
33
|
if ((await lstat(options.directory)).isSymbolicLink())
|
|
34
34
|
throw new Error("Verification directory must not be a symbolic link");
|
|
35
35
|
const path = join(await realpath(options.directory), "verification.jsonl");
|
|
36
|
-
const
|
|
37
|
-
const lock = await acquireFileLock(lockPath);
|
|
36
|
+
const lock = await acquireFileLock(`${path}.lock`);
|
|
38
37
|
let file;
|
|
39
38
|
try {
|
|
40
|
-
await lock.writeFile(JSON.stringify({ pid: process.pid }));
|
|
41
|
-
await lock.sync();
|
|
42
39
|
await rejectLinkIfPresent(path);
|
|
43
40
|
file = await open(path, constants.O_CREAT | constants.O_APPEND | constants.O_RDWR | noFollow(), 0o600);
|
|
44
41
|
const { entries, committed, size } = await readJournal(file);
|
|
@@ -53,26 +50,38 @@ export class TeamVerificationStore {
|
|
|
53
50
|
await repair.close();
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
|
-
const store = new TeamVerificationStore(file, lock,
|
|
53
|
+
const store = new TeamVerificationStore(file, lock, checks, options.executionFor);
|
|
57
54
|
store.size = committed;
|
|
58
55
|
for (const entry of entries) {
|
|
59
56
|
store.apply(entry.event);
|
|
60
57
|
store.sequence = entry.sequence;
|
|
61
58
|
}
|
|
62
|
-
if (entries.length &&
|
|
59
|
+
if (entries.length &&
|
|
60
|
+
!isDeepStrictEqual(entries[0].event.checks, checks))
|
|
63
61
|
throw new Error("Verification checks changed on resume");
|
|
64
62
|
if (!entries.length)
|
|
65
63
|
await store.append({ type: "config", checks });
|
|
66
64
|
// No command, test, or other effect is replayed during recovery.
|
|
67
65
|
for (const result of store.results.values())
|
|
68
66
|
if (result.status === "pending") {
|
|
69
|
-
await store.append({
|
|
67
|
+
await store.append({
|
|
68
|
+
type: "check",
|
|
69
|
+
result: {
|
|
70
|
+
...result,
|
|
71
|
+
status: "unknown",
|
|
72
|
+
detail: "Interrupted check; inspect effects and reconcile before a new command.",
|
|
73
|
+
},
|
|
74
|
+
});
|
|
70
75
|
}
|
|
71
76
|
return store;
|
|
72
77
|
}
|
|
73
78
|
catch (error) {
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
try {
|
|
80
|
+
await file?.close();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await lock.release();
|
|
84
|
+
}
|
|
76
85
|
throw error;
|
|
77
86
|
}
|
|
78
87
|
}
|
|
@@ -85,7 +94,7 @@ export class TeamVerificationStore {
|
|
|
85
94
|
file = await open(path, constants.O_RDONLY | noFollow());
|
|
86
95
|
}
|
|
87
96
|
catch (error) {
|
|
88
|
-
if (
|
|
97
|
+
if (hasErrorCode(error, "ENOENT"))
|
|
89
98
|
return { reports: [], checks: [] };
|
|
90
99
|
throw error;
|
|
91
100
|
}
|
|
@@ -105,7 +114,12 @@ export class TeamVerificationStore {
|
|
|
105
114
|
await file.close();
|
|
106
115
|
}
|
|
107
116
|
}
|
|
108
|
-
snapshot() {
|
|
117
|
+
snapshot() {
|
|
118
|
+
return this.serial.run(() => {
|
|
119
|
+
this.assertOpen();
|
|
120
|
+
return structuredClone({ reports: this.reports, checks: [...this.results.values()] });
|
|
121
|
+
});
|
|
122
|
+
}
|
|
109
123
|
forTask(execution, workspace, options = {}) {
|
|
110
124
|
const identity = taskIdentity(execution);
|
|
111
125
|
const submit = (commandId, report) => this.submit(identity, commandId, report, workspace);
|
|
@@ -115,23 +129,75 @@ export class TeamVerificationStore {
|
|
|
115
129
|
throw new Error("Check is not configured for this task");
|
|
116
130
|
return this.runCheck(commandId, spec, workspace, { ...options, ...extra, execution });
|
|
117
131
|
};
|
|
118
|
-
const tools = () => [
|
|
119
|
-
|
|
132
|
+
const tools = () => [
|
|
133
|
+
{
|
|
134
|
+
name: "submit_report",
|
|
135
|
+
permissionVersion: "team-verification-v1",
|
|
120
136
|
description: "Store a structured report and file/line evidence. The host validates evidence bytes, not claim correctness. This never grants acceptance.",
|
|
121
|
-
inputSchema: {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
inputSchema: {
|
|
138
|
+
type: "object",
|
|
139
|
+
additionalProperties: false,
|
|
140
|
+
required: ["summary", "claims"],
|
|
141
|
+
properties: {
|
|
142
|
+
summary: { type: "string" },
|
|
143
|
+
claims: {
|
|
144
|
+
type: "array",
|
|
145
|
+
items: {
|
|
146
|
+
type: "object",
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
required: ["text", "kind"],
|
|
149
|
+
properties: {
|
|
150
|
+
text: { type: "string" },
|
|
151
|
+
kind: { type: "string", enum: ["finding", "proposal"] },
|
|
152
|
+
evidence: {
|
|
153
|
+
type: "array",
|
|
154
|
+
items: {
|
|
155
|
+
type: "object",
|
|
156
|
+
additionalProperties: false,
|
|
157
|
+
required: ["path", "startLine", "endLine"],
|
|
158
|
+
properties: {
|
|
159
|
+
path: { type: "string" },
|
|
160
|
+
startLine: { type: "integer" },
|
|
161
|
+
endLine: { type: "integer" },
|
|
162
|
+
quote: { type: "string" },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
126
171
|
parse: parseTeamReport,
|
|
127
|
-
async execute(input, call) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
172
|
+
async execute(input, call) {
|
|
173
|
+
call.signal.throwIfAborted();
|
|
174
|
+
return submit(hash(call.idempotencyKey), input);
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "run_check",
|
|
179
|
+
permissionVersion: "team-verification-v1",
|
|
180
|
+
description: `Run one exact host-configured check by id; no model-supplied commands or arguments. Available: ${this.checks
|
|
181
|
+
.filter((entry) => entry.taskId === identity.taskId)
|
|
182
|
+
.map((entry) => entry.id)
|
|
183
|
+
.join(", ") || "none"}. Command checks require explicit host authorization and are not sandboxed.`,
|
|
184
|
+
inputSchema: {
|
|
185
|
+
type: "object",
|
|
186
|
+
additionalProperties: false,
|
|
187
|
+
required: ["id"],
|
|
188
|
+
properties: { id: { type: "string" } },
|
|
189
|
+
},
|
|
190
|
+
parse(value) {
|
|
191
|
+
const input = fields(value, ["id"]);
|
|
192
|
+
identifier(input.id, "check id");
|
|
193
|
+
return { id: input.id };
|
|
194
|
+
},
|
|
195
|
+
async execute(input, call) {
|
|
196
|
+
call.signal.throwIfAborted();
|
|
197
|
+
return runCheck(hash(call.idempotencyKey), input.id, { signal: call.signal });
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
];
|
|
135
201
|
return { submit, runCheck, tools };
|
|
136
202
|
}
|
|
137
203
|
runCheck(commandId, input, workspace, options = {}) {
|
|
@@ -166,34 +232,56 @@ export class TeamVerificationStore {
|
|
|
166
232
|
const fingerprint = await workspaceFingerprint(workspace);
|
|
167
233
|
const state = await this.snapshot();
|
|
168
234
|
const identity = execution ? taskIdentity(execution) : undefined;
|
|
169
|
-
const report = state.reports
|
|
170
|
-
|
|
171
|
-
|
|
235
|
+
const report = state.reports
|
|
236
|
+
.filter((entry) => entry.taskId === taskId && (!identity || sameIdentity(entry, identity)))
|
|
237
|
+
.at(-1);
|
|
238
|
+
const checks = this.checks
|
|
239
|
+
.filter((spec) => spec.taskId === taskId)
|
|
240
|
+
.map((spec) => {
|
|
241
|
+
const result = state.checks
|
|
242
|
+
.filter((entry) => entry.spec.id === spec.id &&
|
|
243
|
+
(!identity || entry.dispatchId === undefined || sameIdentity(entry, identity)))
|
|
244
|
+
.at(-1);
|
|
172
245
|
if (!result)
|
|
173
246
|
return { id: spec.id, status: "missing" };
|
|
174
247
|
const stale = result.workspaceFingerprint !== fingerprint || result.afterFingerprint !== fingerprint;
|
|
175
|
-
return {
|
|
248
|
+
return {
|
|
249
|
+
id: spec.id,
|
|
250
|
+
status: stale && !["pending", "unknown"].includes(result.status) ? "stale" : result.status,
|
|
251
|
+
commandId: result.commandId,
|
|
252
|
+
...(result.detail ? { detail: result.detail } : {}),
|
|
253
|
+
};
|
|
176
254
|
});
|
|
177
255
|
const currentReport = report?.workspaceFingerprint === fingerprint;
|
|
178
256
|
const badEvidence = currentReport && report.evidence.some((item) => !item.valid);
|
|
179
|
-
const status = badEvidence || checks.some((item) => item.status === "failed" || item.status === "cancelled")
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
:
|
|
184
|
-
|
|
257
|
+
const status = badEvidence || checks.some((item) => item.status === "failed" || item.status === "cancelled")
|
|
258
|
+
? "failed"
|
|
259
|
+
: currentReport && checks.length > 0 && checks.every((item) => item.status === "passed")
|
|
260
|
+
? "passed"
|
|
261
|
+
: "unverified";
|
|
262
|
+
return {
|
|
263
|
+
status,
|
|
264
|
+
workspaceFingerprint: fingerprint,
|
|
265
|
+
checks,
|
|
266
|
+
...(report ? { report } : {}),
|
|
267
|
+
detail: status === "passed"
|
|
268
|
+
? "Configured checks passed for these exact workspace bytes. Evidence locations are valid; claim logic and untested behavior remain unverified."
|
|
269
|
+
: status === "failed"
|
|
270
|
+
? "A configured check or submitted evidence failed. Execution completion does not imply acceptance."
|
|
271
|
+
: "A current structured report and all configured checks are required. Missing, stale, interrupted, or absent checks cannot grant acceptance.",
|
|
272
|
+
};
|
|
185
273
|
}
|
|
186
274
|
close() {
|
|
187
|
-
return this.closing ??= (async () => {
|
|
275
|
+
return (this.closing ??= (async () => {
|
|
188
276
|
await Promise.allSettled([...this.active]);
|
|
189
277
|
await this.serial.close();
|
|
190
278
|
try {
|
|
191
279
|
await this.file.close();
|
|
192
280
|
}
|
|
193
281
|
finally {
|
|
194
|
-
await
|
|
282
|
+
await this.lock.release();
|
|
195
283
|
}
|
|
196
|
-
})();
|
|
284
|
+
})());
|
|
197
285
|
}
|
|
198
286
|
async submit(identity, commandId, input, workspace) {
|
|
199
287
|
identifier(commandId, "report command id");
|
|
@@ -218,15 +306,28 @@ export class TeamVerificationStore {
|
|
|
218
306
|
if (lines.at(-1) === "")
|
|
219
307
|
lines.pop();
|
|
220
308
|
const excerpt = lines.slice(item.startLine - 1, item.endLine).join("\n");
|
|
221
|
-
const valid = item.endLine <= lines.length &&
|
|
222
|
-
|
|
223
|
-
|
|
309
|
+
const valid = item.endLine <= lines.length &&
|
|
310
|
+
(item.quote === undefined || excerpt.includes(item.quote.replace(/\r\n/gu, "\n")));
|
|
311
|
+
evidence.push({
|
|
312
|
+
path: item.path,
|
|
313
|
+
startLine: item.startLine,
|
|
314
|
+
endLine: item.endLine,
|
|
315
|
+
sha256: hash(bytes),
|
|
316
|
+
valid,
|
|
317
|
+
...(!valid ? { detail: "Line range or quote does not match the file" } : {}),
|
|
318
|
+
});
|
|
224
319
|
}
|
|
225
320
|
catch (error) {
|
|
226
|
-
evidence.push({
|
|
321
|
+
evidence.push({
|
|
322
|
+
path: item.path,
|
|
323
|
+
startLine: item.startLine,
|
|
324
|
+
endLine: item.endLine,
|
|
325
|
+
valid: false,
|
|
326
|
+
detail: message(error),
|
|
327
|
+
});
|
|
227
328
|
}
|
|
228
329
|
}
|
|
229
|
-
if (await workspaceFingerprint(workspace) !== fingerprint)
|
|
330
|
+
if ((await workspaceFingerprint(workspace)) !== fingerprint)
|
|
230
331
|
throw new Error("Workspace changed while validating report evidence");
|
|
231
332
|
const stored = { ...identity, commandId, report, workspaceFingerprint: fingerprint, evidence };
|
|
232
333
|
await this.write({ type: "report", report: stored });
|
|
@@ -258,7 +359,13 @@ export class TeamVerificationStore {
|
|
|
258
359
|
if (spec.type === "command" && options.allowCommands !== true)
|
|
259
360
|
throw new Error("Command checks require explicit --allow-checks authorization");
|
|
260
361
|
options.signal?.throwIfAborted();
|
|
261
|
-
const result = {
|
|
362
|
+
const result = {
|
|
363
|
+
...identity,
|
|
364
|
+
commandId,
|
|
365
|
+
spec,
|
|
366
|
+
workspaceFingerprint: await workspaceFingerprint(workspace),
|
|
367
|
+
status: "pending",
|
|
368
|
+
};
|
|
262
369
|
await this.write({ type: "check", result });
|
|
263
370
|
fresh = true;
|
|
264
371
|
return result;
|
|
@@ -268,12 +375,15 @@ export class TeamVerificationStore {
|
|
|
268
375
|
let outcome;
|
|
269
376
|
try {
|
|
270
377
|
if (spec.type === "command")
|
|
271
|
-
outcome = await runCommand(spec, workspace, options.signal);
|
|
378
|
+
outcome = await runCommand(spec, workspace, options.signal, this.executionFor);
|
|
272
379
|
else {
|
|
273
380
|
options.signal?.throwIfAborted();
|
|
274
381
|
const bytes = await readWorkspaceFile(workspace, spec.path);
|
|
275
382
|
const passed = spec.type === "file-sha256" ? hash(bytes) === spec.sha256 : bytes.toString("utf8").includes(spec.text);
|
|
276
|
-
outcome = {
|
|
383
|
+
outcome = {
|
|
384
|
+
status: passed ? "passed" : "failed",
|
|
385
|
+
detail: passed ? "Exact configured file check passed" : "Configured file predicate did not match",
|
|
386
|
+
};
|
|
277
387
|
}
|
|
278
388
|
}
|
|
279
389
|
catch (error) {
|
|
@@ -284,13 +394,19 @@ export class TeamVerificationStore {
|
|
|
284
394
|
afterFingerprint = await workspaceFingerprint(workspace);
|
|
285
395
|
}
|
|
286
396
|
catch (error) {
|
|
287
|
-
outcome = {
|
|
397
|
+
outcome = {
|
|
398
|
+
...outcome,
|
|
399
|
+
status: spec.type === "command" ? "unknown" : "failed",
|
|
400
|
+
detail: `Cannot inspect workspace after check: ${message(error)}`,
|
|
401
|
+
};
|
|
288
402
|
}
|
|
289
403
|
const result = { ...pending, ...outcome, ...(afterFingerprint ? { afterFingerprint } : {}) };
|
|
290
404
|
await this.append({ type: "check", result });
|
|
291
405
|
return structuredClone(result);
|
|
292
406
|
}
|
|
293
|
-
append(event) {
|
|
407
|
+
append(event) {
|
|
408
|
+
return this.serial.run(() => this.write(event));
|
|
409
|
+
}
|
|
294
410
|
async write(event) {
|
|
295
411
|
this.assertOpen();
|
|
296
412
|
const line = `${JSON.stringify({ sequence: this.sequence + 1, event })}\n`;
|
|
@@ -315,11 +431,24 @@ export class TeamVerificationStore {
|
|
|
315
431
|
if (event.type === "check")
|
|
316
432
|
this.results.set(event.result.commandId, event.result);
|
|
317
433
|
}
|
|
318
|
-
assertOpen() {
|
|
319
|
-
|
|
434
|
+
assertOpen() {
|
|
435
|
+
if (this.failed)
|
|
436
|
+
throw new Error("Verification write outcome unknown; close and inspect before continuing");
|
|
437
|
+
}
|
|
320
438
|
}
|
|
321
439
|
export function parseTeamCheck(value) {
|
|
322
|
-
const raw = fields(value, [
|
|
440
|
+
const raw = fields(value, [
|
|
441
|
+
"id",
|
|
442
|
+
"taskId",
|
|
443
|
+
"type",
|
|
444
|
+
"path",
|
|
445
|
+
"text",
|
|
446
|
+
"sha256",
|
|
447
|
+
"command",
|
|
448
|
+
"args",
|
|
449
|
+
"timeoutMs",
|
|
450
|
+
"maxOutputBytes",
|
|
451
|
+
]);
|
|
323
452
|
identifier(raw.id, "check id");
|
|
324
453
|
identifier(raw.taskId, "check taskId");
|
|
325
454
|
if (raw.type === "file-contains") {
|
|
@@ -336,7 +465,10 @@ export function parseTeamCheck(value) {
|
|
|
336
465
|
else if (raw.type === "command") {
|
|
337
466
|
fields(raw, ["id", "taskId", "type", "command", "args", "timeoutMs", "maxOutputBytes"]);
|
|
338
467
|
boundedString(raw.command, "check command", 4096);
|
|
339
|
-
if (/[\u0000\r\n]/u.test(raw.command) ||
|
|
468
|
+
if (/[\u0000\r\n]/u.test(raw.command) ||
|
|
469
|
+
!Array.isArray(raw.args) ||
|
|
470
|
+
raw.args.length > 64 ||
|
|
471
|
+
raw.args.some((arg) => typeof arg !== "string" || arg.length > 8192 || arg.includes("\0")))
|
|
340
472
|
throw new Error("Invalid check command arguments");
|
|
341
473
|
if (raw.timeoutMs !== undefined)
|
|
342
474
|
integer(raw.timeoutMs, 1, 120000, "check timeoutMs");
|
|
@@ -455,39 +587,78 @@ async function readWorkspaceFile(directory, path) {
|
|
|
455
587
|
await file.close();
|
|
456
588
|
}
|
|
457
589
|
}
|
|
458
|
-
async function runCommand(spec, workspace, signal) {
|
|
590
|
+
async function runCommand(spec, workspace, signal, executionFor) {
|
|
591
|
+
const environment = executionFor
|
|
592
|
+
? await executionFor(workspace)
|
|
593
|
+
: await openCodingExecutionEnvironment({ workspace, isolation: { mode: "host" } });
|
|
594
|
+
try {
|
|
595
|
+
return await runEnvironmentCommand(spec, workspace, environment, signal);
|
|
596
|
+
}
|
|
597
|
+
finally {
|
|
598
|
+
if (!executionFor)
|
|
599
|
+
await environment.close();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
async function runEnvironmentCommand(spec, workspace, environment, signal) {
|
|
459
603
|
signal?.throwIfAborted();
|
|
460
604
|
if (process.platform === "win32" && /\.(?:cmd|bat)$/iu.test(spec.command))
|
|
461
|
-
return {
|
|
605
|
+
return {
|
|
606
|
+
status: "failed",
|
|
607
|
+
detail: "Command checks execute native programs directly. Use node.exe with the package manager JavaScript entry point, not .cmd/.bat.",
|
|
608
|
+
};
|
|
462
609
|
const cwd = await realpath(workspace);
|
|
463
610
|
const env = {};
|
|
464
611
|
// No inherited API keys, proxy tokens, NODE_OPTIONS, package hooks, or user home config.
|
|
465
|
-
for (const key of [
|
|
466
|
-
|
|
612
|
+
for (const key of [
|
|
613
|
+
"PATH",
|
|
614
|
+
"Path",
|
|
615
|
+
"PATHEXT",
|
|
616
|
+
"SystemRoot",
|
|
617
|
+
"WINDIR",
|
|
618
|
+
"COMSPEC",
|
|
619
|
+
"TEMP",
|
|
620
|
+
"TMP",
|
|
621
|
+
"TMPDIR",
|
|
622
|
+
"LANG",
|
|
623
|
+
"LC_ALL",
|
|
624
|
+
])
|
|
625
|
+
if (environment.isolation.mode === "host" && process.env[key] !== undefined)
|
|
467
626
|
env[key] = process.env[key];
|
|
468
627
|
env.CI = "1";
|
|
469
|
-
return new Promise((resolveResult) => {
|
|
628
|
+
return new Promise((resolveResult, rejectResult) => {
|
|
629
|
+
const cancellation = new AbortController();
|
|
470
630
|
let output = Buffer.alloc(0);
|
|
471
631
|
let reason;
|
|
472
632
|
let settled = false;
|
|
473
|
-
const child = spawn(spec.command,
|
|
633
|
+
const child = environment.spawn(spec.command, spec.args, {
|
|
634
|
+
cwd,
|
|
635
|
+
env,
|
|
636
|
+
signal: cancellation.signal,
|
|
637
|
+
});
|
|
638
|
+
const stdout = child.stdout;
|
|
639
|
+
const stderr = child.stderr;
|
|
640
|
+
if (!stdout || !stderr) {
|
|
641
|
+
rejectResult(new Error("Execution environment must provide command output pipes"));
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
474
644
|
const finish = (status, exitCode, detail) => {
|
|
475
645
|
if (settled)
|
|
476
646
|
return;
|
|
477
647
|
settled = true;
|
|
478
648
|
clearTimeout(timer);
|
|
479
|
-
clearTimeout(killWait);
|
|
480
649
|
signal?.removeEventListener("abort", abort);
|
|
481
|
-
resolveResult({
|
|
650
|
+
resolveResult({
|
|
651
|
+
status,
|
|
652
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
653
|
+
...(detail ? { detail } : {}),
|
|
654
|
+
output: boundedOutput(output, spec.maxOutputBytes ?? 65536),
|
|
655
|
+
});
|
|
482
656
|
};
|
|
483
|
-
let killWait;
|
|
484
657
|
const stop = (detail) => {
|
|
485
658
|
if (reason)
|
|
486
659
|
return;
|
|
487
660
|
reason = detail;
|
|
488
|
-
|
|
489
|
-
// A descendant may retain inherited pipes. No process-tree or OS isolation guarantee.
|
|
490
|
-
killWait = setTimeout(() => { child.stdout.destroy(); child.stderr.destroy(); finish("unknown", undefined, `${detail}; child effects require inspection`); }, 1000);
|
|
661
|
+
cancellation.abort();
|
|
491
662
|
};
|
|
492
663
|
const abort = () => stop("Check interrupted");
|
|
493
664
|
const timer = setTimeout(() => stop("Check timed out"), spec.timeoutMs ?? 30000);
|
|
@@ -500,8 +671,8 @@ async function runCommand(spec, workspace, signal) {
|
|
|
500
671
|
else
|
|
501
672
|
output = Buffer.concat([output, chunk]);
|
|
502
673
|
};
|
|
503
|
-
|
|
504
|
-
|
|
674
|
+
stdout.on("data", collect);
|
|
675
|
+
stderr.on("data", collect);
|
|
505
676
|
child.on("error", (error) => finish(child.pid === undefined ? "failed" : "unknown", undefined, message(error)));
|
|
506
677
|
child.on("close", (code, terminationSignal) => {
|
|
507
678
|
if (reason || terminationSignal || code === null)
|
|
@@ -561,7 +732,8 @@ async function readJournal(file) {
|
|
|
561
732
|
const result = event.result;
|
|
562
733
|
parseTeamCheck(result.spec);
|
|
563
734
|
validateStored(result);
|
|
564
|
-
if (!isDeepStrictEqual(specs.find((entry) => entry.id === result.spec.id), result.spec) ||
|
|
735
|
+
if (!isDeepStrictEqual(specs.find((entry) => entry.id === result.spec.id), result.spec) ||
|
|
736
|
+
result.taskId !== result.spec.taskId ||
|
|
565
737
|
!["pending", "passed", "failed", "unknown", "cancelled"].includes(result.status) ||
|
|
566
738
|
(result.afterFingerprint !== undefined && !/^[a-f0-9]{64}$/u.test(result.afterFingerprint)))
|
|
567
739
|
throw new Error("Invalid check record");
|
|
@@ -571,8 +743,11 @@ async function readJournal(file) {
|
|
|
571
743
|
throw new Error("Check result has no pending intent");
|
|
572
744
|
}
|
|
573
745
|
else {
|
|
574
|
-
if (!sameIdentity(old, result) ||
|
|
575
|
-
(old.
|
|
746
|
+
if (!sameIdentity(old, result) ||
|
|
747
|
+
!isDeepStrictEqual(old.spec, result.spec) ||
|
|
748
|
+
old.workspaceFingerprint !== result.workspaceFingerprint ||
|
|
749
|
+
(old.status !== "pending" && old.status !== "unknown") ||
|
|
750
|
+
result.status === "pending" ||
|
|
576
751
|
(old.status === "unknown" && (!["failed", "cancelled"].includes(result.status) || !result.reconciliation)))
|
|
577
752
|
throw new Error("Invalid check history transition");
|
|
578
753
|
}
|
|
@@ -591,37 +766,65 @@ function validateStored(value) {
|
|
|
591
766
|
throw new Error("Invalid stored workspace fingerprint");
|
|
592
767
|
}
|
|
593
768
|
function taskIdentity(execution) {
|
|
594
|
-
return {
|
|
769
|
+
return {
|
|
770
|
+
taskId: execution.task.id,
|
|
771
|
+
coordinationId: execution.coordinationId,
|
|
772
|
+
dispatchId: execution.task.dispatchId,
|
|
773
|
+
turn: execution.task.turn ?? 0,
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function sameIdentity(a, b) {
|
|
777
|
+
return (a.taskId === b.taskId && a.coordinationId === b.coordinationId && a.dispatchId === b.dispatchId && a.turn === b.turn);
|
|
595
778
|
}
|
|
596
|
-
function sameIdentity(a, b) { return a.taskId === b.taskId && a.coordinationId === b.coordinationId && a.dispatchId === b.dispatchId && a.turn === b.turn; }
|
|
597
779
|
function fields(value, allowed) {
|
|
598
|
-
if (!value ||
|
|
780
|
+
if (!value ||
|
|
781
|
+
typeof value !== "object" ||
|
|
782
|
+
Array.isArray(value) ||
|
|
783
|
+
Object.keys(value).some((key) => !allowed.includes(key)))
|
|
599
784
|
throw new Error("Invalid verification fields");
|
|
600
785
|
return value;
|
|
601
786
|
}
|
|
602
|
-
function identifier(value, label) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
function
|
|
607
|
-
|
|
787
|
+
function identifier(value, label) {
|
|
788
|
+
if (typeof value !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,255}$/u.test(value))
|
|
789
|
+
throw new Error(`Invalid ${label}`);
|
|
790
|
+
}
|
|
791
|
+
function boundedString(value, label, max) {
|
|
792
|
+
if (typeof value !== "string" || value.length < 1 || Buffer.byteLength(value) > max || value.includes("\0"))
|
|
793
|
+
throw new Error(`Invalid ${label}`);
|
|
794
|
+
}
|
|
795
|
+
function integer(value, min, max, label) {
|
|
796
|
+
if (!Number.isSafeInteger(value) || value < min || value > max)
|
|
797
|
+
throw new Error(`Invalid ${label}`);
|
|
798
|
+
}
|
|
608
799
|
function safeRelative(value) {
|
|
609
800
|
boundedString(value, "workspace relative path", 2048);
|
|
610
|
-
if (isAbsolute(value) ||
|
|
801
|
+
if (isAbsolute(value) ||
|
|
802
|
+
/[:\u0000-\u001f]/u.test(value) ||
|
|
803
|
+
value
|
|
804
|
+
.replace(/\\/gu, "/")
|
|
805
|
+
.split("/")
|
|
806
|
+
.some((part) => !part || part === "." || part === ".."))
|
|
611
807
|
throw new Error("Unsafe workspace relative path");
|
|
612
808
|
}
|
|
613
|
-
async function rejectLinkIfPresent(path) {
|
|
614
|
-
|
|
615
|
-
|
|
809
|
+
async function rejectLinkIfPresent(path) {
|
|
810
|
+
try {
|
|
811
|
+
if ((await lstat(path)).isSymbolicLink())
|
|
812
|
+
throw new Error("Verification file must not be a symbolic link");
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
if (!hasErrorCode(error, "ENOENT"))
|
|
816
|
+
throw error;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function noFollow() {
|
|
820
|
+
return process.platform === "win32" ? 0 : constants.O_NOFOLLOW;
|
|
821
|
+
}
|
|
822
|
+
function hash(value) {
|
|
823
|
+
return createHash("sha256").update(value).digest("hex");
|
|
824
|
+
}
|
|
825
|
+
function message(error) {
|
|
826
|
+
return (error instanceof Error ? error.message : String(error)).slice(0, 2048);
|
|
616
827
|
}
|
|
617
|
-
catch (error) {
|
|
618
|
-
if (!isMissing(error))
|
|
619
|
-
throw error;
|
|
620
|
-
} }
|
|
621
|
-
function isMissing(error) { return error instanceof Error && "code" in error && error.code === "ENOENT"; }
|
|
622
|
-
function noFollow() { return process.platform === "win32" ? 0 : constants.O_NOFOLLOW; }
|
|
623
|
-
function hash(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
624
|
-
function message(error) { return (error instanceof Error ? error.message : String(error)).slice(0, 2048); }
|
|
625
828
|
function boundedOutput(bytes, limit) {
|
|
626
829
|
const text = bytes.toString("utf8");
|
|
627
830
|
if (Buffer.byteLength(text) <= limit)
|