stitchkit 0.105.0 → 0.105.1
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 +29 -0
- package/dist/entrypoints/agent-runtime/coding-tools.js +3 -3
- package/dist/entrypoints/agent-runtime/sandbox.js +3 -3
- package/dist/entrypoints/application/directory-inbox.js +3 -3
- package/dist/entrypoints/cli/publish.js +4 -4
- package/dist/entrypoints/cli.js +3 -3
- package/dist/entrypoints/files/packaging.js +10 -4
- package/dist/entrypoints/files.js +3 -3
- package/dist/entrypoints/process.js +1 -1
- package/dist/entrypoints/server.js +3 -3
- package/dist/entrypoints/telegram.js +2 -2
- package/dist/entrypoints/tools.js +3 -3
- package/dist/files/native-packaging.d.ts.map +1 -1
- package/dist/{index-2rc6jd9n.js → index-1ptj98e0.js} +1 -1
- package/dist/{index-g2vfg7ak.js → index-5c26631f.js} +33 -10
- package/dist/{index-ef8gdaq0.js → index-cazts87s.js} +1 -1
- package/dist/{index-szybbezc.js → index-drs41arz.js} +1 -1
- package/dist/{index-cq59agna.js → index-j4zh647a.js} +9 -1
- package/dist/{index-wqmvtnkp.js → index-w8etpm8j.js} +1 -1
- package/dist/{index-ma963wz7.js → index-y7k2cdgv.js} +2 -2
- package/dist/internal/atomic-staging.d.ts +2 -1
- package/dist/internal/atomic-staging.d.ts.map +1 -1
- package/dist/process/cleanup.d.ts +1 -1
- package/dist/process/cleanup.d.ts.map +1 -1
- package/dist/process/command-lifetime.d.ts +2 -1
- package/dist/process/command-lifetime.d.ts.map +1 -1
- package/dist/process/command-owner.d.ts +1 -0
- package/dist/process/command-owner.d.ts.map +1 -1
- package/dist/process/contract.d.ts +3 -2
- package/dist/process/contract.d.ts.map +1 -1
- package/dist/process/group.d.ts +4 -2
- package/dist/process/group.d.ts.map +1 -1
- package/dist/process/terminate.d.ts +3 -2
- package/dist/process/terminate.d.ts.map +1 -1
- package/llms/files-packaging.txt +2 -0
- package/llms/files.txt +1 -1
- package/llms/process.txt +45 -11
- package/llms-full.txt +48 -12
- package/llms.txt +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,35 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [0.105.1] - 2026-10-06
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `stitchkit/process` — `NativeCommandResult.descendantsStopped` reports that the group still had
|
|
23
|
+
members after the leader exited and that `descendants: 'terminate-after-leader'` stopped them,
|
|
24
|
+
so a helper ended this way is visible in the result instead of only missing afterwards.
|
|
25
|
+
- `stitchkit/files/packaging` — `assetPath` accepts `[hash]`, replaced by the first 16 hex digits
|
|
26
|
+
of the addon's published SHA256, so two installed versions get different companion names
|
|
27
|
+
(`addons/darwin-arm64-[hash].node`); the loader requires exactly that name.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- `stitchkit/files` — `sweepAtomicStaging` returns `[]` for a `directory` that does not exist yet
|
|
32
|
+
instead of throwing `ENOENT`; any other listing failure still throws.
|
|
33
|
+
- `stitchkit/process` — an option `runNativeCommand` does not know is refused by name, and the
|
|
34
|
+
removed `killGraceMs` names its replacement, `stop: { target: 'group', graceMs }`: a spread
|
|
35
|
+
object can carry a key the type never checked.
|
|
36
|
+
|
|
37
|
+
### Documentation
|
|
38
|
+
|
|
39
|
+
- `stitchkit/process` — the 0.105.0 note that a descendant leaving the group with `setsid` is
|
|
40
|
+
unaffected holds only when it has left before the leader exits: `setsid helper &` and
|
|
41
|
+
`nohup helper &` race the leader and are stopped, `setsid -f helper` survives. The native IO
|
|
42
|
+
guide shows the measured forms, how a guardian or worker that holds a child until it exits
|
|
43
|
+
maps onto `runNativeCommand`, and why a child inheriting the terminal stays a plain spawn.
|
|
44
|
+
- `stitchkit/files/packaging` — calling `createNativePackaging` has to stay in the build step;
|
|
45
|
+
importing the leaf from a module that is also bundled is side-effect free.
|
|
46
|
+
|
|
18
47
|
## [0.105.0] - 2026-10-05
|
|
19
48
|
|
|
20
49
|
### ⚠️ Breaking changes
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
AgentCodingToolAuthorizationSchema2,
|
|
8
8
|
AgentCodingToolPathAuthorizationSchema2,
|
|
9
9
|
createAgentCodingTools2
|
|
10
|
-
} from "../../index-
|
|
10
|
+
} from "../../index-y7k2cdgv.js";
|
|
11
11
|
import"../../index-v5ee8ath.js";
|
|
12
|
-
import"../../index-
|
|
13
|
-
import"../../index-
|
|
12
|
+
import"../../index-j4zh647a.js";
|
|
13
|
+
import"../../index-5c26631f.js";
|
|
14
14
|
import"../../index-8ks9b85e.js";
|
|
15
15
|
import"../../index-gxm9rc97.js";
|
|
16
16
|
import"../../index-yvfk3y36.js";
|
|
@@ -9,9 +9,9 @@ import"../../index-r393tnfp.js";
|
|
|
9
9
|
import"../../index-rpzewktb.js";
|
|
10
10
|
import {
|
|
11
11
|
createAgentCodingTools2
|
|
12
|
-
} from "../../index-
|
|
12
|
+
} from "../../index-y7k2cdgv.js";
|
|
13
13
|
import"../../index-v5ee8ath.js";
|
|
14
|
-
import"../../index-
|
|
14
|
+
import"../../index-j4zh647a.js";
|
|
15
15
|
import {
|
|
16
16
|
COMMAND_CLEANUP_TIMEOUT_MS,
|
|
17
17
|
NativeCommandError2,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
nativeCommandOwner,
|
|
20
20
|
terminateOwnedGroup,
|
|
21
21
|
startNativeCommand
|
|
22
|
-
} from "../../index-
|
|
22
|
+
} from "../../index-5c26631f.js";
|
|
23
23
|
import"../../index-gxm9rc97.js";
|
|
24
24
|
import {
|
|
25
25
|
MAX_TIMER_MS
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
renewEntry,
|
|
11
11
|
forgetMissing
|
|
12
12
|
} from "../../index-msfpyy2f.js";
|
|
13
|
-
import"../../index-
|
|
13
|
+
import"../../index-j4zh647a.js";
|
|
14
14
|
import {
|
|
15
15
|
backoffDelay
|
|
16
16
|
} from "../../index-g6a3na27.js";
|
|
@@ -19,7 +19,7 @@ import"../../index-azx12jgv.js";
|
|
|
19
19
|
import"../../index-v5ee8ath.js";
|
|
20
20
|
import {
|
|
21
21
|
createFileStateStore2
|
|
22
|
-
} from "../../index-
|
|
22
|
+
} from "../../index-1ptj98e0.js";
|
|
23
23
|
import {
|
|
24
24
|
defineManagedResource2
|
|
25
25
|
} from "../../index-50ejfz75.js";
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
} from "../../index-m616f0yz.js";
|
|
38
38
|
import {
|
|
39
39
|
writeAtomicFileData
|
|
40
|
-
} from "../../index-
|
|
40
|
+
} from "../../index-cazts87s.js";
|
|
41
41
|
import {
|
|
42
42
|
closeAfter,
|
|
43
43
|
publishAtomicFile
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import"../../index-xqhede6x.js";
|
|
2
|
-
import"../../index-
|
|
2
|
+
import"../../index-j4zh647a.js";
|
|
3
3
|
import {
|
|
4
4
|
ManagedFileError2,
|
|
5
5
|
createManagedFileBoundary2
|
|
6
|
-
} from "../../index-
|
|
6
|
+
} from "../../index-w8etpm8j.js";
|
|
7
7
|
import"../../index-dsnjzb62.js";
|
|
8
8
|
import"../../index-azx12jgv.js";
|
|
9
9
|
import"../../index-v5ee8ath.js";
|
|
@@ -20,13 +20,13 @@ import {
|
|
|
20
20
|
gzipCliAsset,
|
|
21
21
|
decodeCliAsset,
|
|
22
22
|
compareCliVersions2
|
|
23
|
-
} from "../../index-
|
|
23
|
+
} from "../../index-drs41arz.js";
|
|
24
24
|
import {
|
|
25
25
|
withExclusiveLock2
|
|
26
26
|
} from "../../index-4vsby8n8.js";
|
|
27
27
|
import {
|
|
28
28
|
writeFileAtomic2
|
|
29
|
-
} from "../../index-
|
|
29
|
+
} from "../../index-cazts87s.js";
|
|
30
30
|
import {
|
|
31
31
|
AtomicFilePublicationError2,
|
|
32
32
|
assertDirectoryDurability,
|
package/dist/entrypoints/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
pollUntilDone2,
|
|
17
17
|
createCli2
|
|
18
18
|
} from "../index-ksfagmyz.js";
|
|
19
|
-
import"../index-
|
|
19
|
+
import"../index-j4zh647a.js";
|
|
20
20
|
import {
|
|
21
21
|
AppError2
|
|
22
22
|
} from "../index-j9gxbztg.js";
|
|
@@ -45,10 +45,10 @@ import {
|
|
|
45
45
|
checkCliUpdate2,
|
|
46
46
|
applyCliUpdate2,
|
|
47
47
|
rollbackCliUpdate2
|
|
48
|
-
} from "../index-
|
|
48
|
+
} from "../index-drs41arz.js";
|
|
49
49
|
import {
|
|
50
50
|
writeFileAtomicSync2
|
|
51
|
-
} from "../index-
|
|
51
|
+
} from "../index-cazts87s.js";
|
|
52
52
|
import"../index-pz3y6b6g.js";
|
|
53
53
|
import"../index-yvfk3y36.js";
|
|
54
54
|
import {
|
|
@@ -65,17 +65,20 @@ var CommonOptions = {
|
|
|
65
65
|
platform: PlatformSchema,
|
|
66
66
|
entryPath: RelativePathSchema.refine((value) => !value.includes("[") && !value.includes("]"), "Expected a fixed entry path without Bun naming templates")
|
|
67
67
|
};
|
|
68
|
+
var ASSET_HASH_TOKEN = "[hash]";
|
|
69
|
+
var ASSET_HASH_LENGTH = 16;
|
|
70
|
+
var AssetPathSchema = RelativePathSchema.refine((value) => !/[[\]]/.test(value.replaceAll(ASSET_HASH_TOKEN, "")), "Expected an addon path whose only template is [hash]");
|
|
68
71
|
var SingleOptionsSchema = z2.object({
|
|
69
72
|
...CommonOptions,
|
|
70
73
|
architecture: z2.string().min(1),
|
|
71
74
|
delivery: z2.enum(["companion", "embedded"]),
|
|
72
|
-
assetPath:
|
|
75
|
+
assetPath: AssetPathSchema
|
|
73
76
|
});
|
|
74
77
|
var MultipleOptionsSchema = z2.object({
|
|
75
78
|
...CommonOptions,
|
|
76
79
|
architecture: z2.array(z2.string().min(1)).refine((targets) => targets.length > 0),
|
|
77
80
|
delivery: z2.literal("companion"),
|
|
78
|
-
assetPath: z2.record(z2.string().min(1),
|
|
81
|
+
assetPath: z2.record(z2.string().min(1), AssetPathSchema)
|
|
79
82
|
});
|
|
80
83
|
var OptionsSchema = z2.union([SingleOptionsSchema, MultipleOptionsSchema]).check((ctx) => {
|
|
81
84
|
const input = ctx.value;
|
|
@@ -220,13 +223,16 @@ function createNativePackaging(options) {
|
|
|
220
223
|
const specifiers = {};
|
|
221
224
|
const embedded = new Map;
|
|
222
225
|
for (const architecture of architectures) {
|
|
223
|
-
const
|
|
224
|
-
if (!
|
|
226
|
+
const template = typeof input.assetPath === "string" ? input.assetPath : input.assetPath[architecture];
|
|
227
|
+
if (!template)
|
|
225
228
|
throw new Error("Declared architecture has no output path");
|
|
226
229
|
const verified = readVerifiedAsset(root, published.assets[architecture], input.platform, architecture);
|
|
227
230
|
if ("refusal" in verified)
|
|
228
231
|
return verified.refusal;
|
|
229
232
|
const { sourcePath, bytes, size, sha256 } = verified;
|
|
233
|
+
const outputPath = template.replaceAll(ASSET_HASH_TOKEN, sha256.slice(0, ASSET_HASH_LENGTH));
|
|
234
|
+
if (assets.some((asset) => asset.outputPath === outputPath))
|
|
235
|
+
throw new Error("Addons must have distinct output paths");
|
|
230
236
|
if (input.delivery === "embedded")
|
|
231
237
|
embedded.set(sourcePath, new Uint8Array(bytes));
|
|
232
238
|
const outputSpecifier = relative(dirname(input.entryPath), outputPath).split("\\").join("/");
|
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
stagingPath,
|
|
7
7
|
isAtomicStagingName2,
|
|
8
8
|
sweepAtomicStaging2
|
|
9
|
-
} from "../index-
|
|
9
|
+
} from "../index-j4zh647a.js";
|
|
10
10
|
import {
|
|
11
11
|
ManagedFileError2,
|
|
12
12
|
createManagedFileBoundary2
|
|
13
|
-
} from "../index-
|
|
13
|
+
} from "../index-w8etpm8j.js";
|
|
14
14
|
import {
|
|
15
15
|
AppError2
|
|
16
16
|
} from "../index-j9gxbztg.js";
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import {
|
|
25
25
|
writeFileAtomic2,
|
|
26
26
|
writeFileAtomicSync2
|
|
27
|
-
} from "../index-
|
|
27
|
+
} from "../index-cazts87s.js";
|
|
28
28
|
import {
|
|
29
29
|
AtomicFilePublicationError2
|
|
30
30
|
} from "../index-b56nnscm.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import"../index-
|
|
1
|
+
import"../index-j4zh647a.js";
|
|
2
2
|
import"../index-dsnjzb62.js";
|
|
3
3
|
import"../index-azx12jgv.js";
|
|
4
4
|
import"../index-v5ee8ath.js";
|
|
5
5
|
import {
|
|
6
6
|
createFileStateStore2
|
|
7
|
-
} from "../index-
|
|
7
|
+
} from "../index-1ptj98e0.js";
|
|
8
8
|
import {
|
|
9
9
|
AppError2,
|
|
10
10
|
notFound2,
|
|
@@ -96,7 +96,7 @@ import {
|
|
|
96
96
|
isWithinDir2,
|
|
97
97
|
realPathWithinDir
|
|
98
98
|
} from "../index-5cc6r990.js";
|
|
99
|
-
import"../index-
|
|
99
|
+
import"../index-cazts87s.js";
|
|
100
100
|
import {
|
|
101
101
|
DEFAULT_CORS_ALLOW_HEADERS2,
|
|
102
102
|
DEFAULT_CORS_EXPOSE_HEADERS2,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
TELEGRAM_SEND_FAILURE_REASONS2,
|
|
9
9
|
classifyTelegramSendFailure2
|
|
10
10
|
} from "../index-e05cjgtf.js";
|
|
11
|
-
import"../index-
|
|
11
|
+
import"../index-j4zh647a.js";
|
|
12
12
|
import {
|
|
13
13
|
attemptExclusiveLock
|
|
14
14
|
} from "../index-dsnjzb62.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "../index-b0kddvzw.js";
|
|
24
24
|
import {
|
|
25
25
|
writeFileAtomic2
|
|
26
|
-
} from "../index-
|
|
26
|
+
} from "../index-cazts87s.js";
|
|
27
27
|
import {
|
|
28
28
|
MAX_TIMER_MS,
|
|
29
29
|
sleep
|
|
@@ -85,10 +85,10 @@ import {
|
|
|
85
85
|
ManagedFilePathSchema2,
|
|
86
86
|
ManagedFileRefSchema2
|
|
87
87
|
} from "../index-xqhede6x.js";
|
|
88
|
-
import"../index-
|
|
88
|
+
import"../index-j4zh647a.js";
|
|
89
89
|
import {
|
|
90
90
|
ManagedFileError2
|
|
91
|
-
} from "../index-
|
|
91
|
+
} from "../index-w8etpm8j.js";
|
|
92
92
|
import {
|
|
93
93
|
fetchGuarded,
|
|
94
94
|
fetchPinnedDocument,
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
contractOnlyService,
|
|
103
103
|
mediaTypeEssence
|
|
104
104
|
} from "../index-cmzvhhtd.js";
|
|
105
|
-
import"../index-
|
|
105
|
+
import"../index-cazts87s.js";
|
|
106
106
|
import {
|
|
107
107
|
collectToolSurface
|
|
108
108
|
} from "../index-pz3y6b6g.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-packaging.d.ts","sourceRoot":"","sources":["../../src/files/native-packaging.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,QAAA,MAAM,kBAAkB;;;EAA2B,CAAC;AACpD,mGAAmG;AACnG,QAAA,MAAM,cAAc;;EAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"native-packaging.d.ts","sourceRoot":"","sources":["../../src/files/native-packaging.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,QAAA,MAAM,kBAAkB;;;EAA2B,CAAC;AACpD,mGAAmG;AACnG,QAAA,MAAM,cAAc;;EAAqB,CAAC;AAe1C,QAAA,MAAM,mBAAmB;;;;;;;;;;;iBAKvB,CAAC;AACH,QAAA,MAAM,qBAAqB;;;;;;;;iBAOzB,CAAC;AAsCH,QAAA,MAAM,WAAW;;;;;iBAKf,CAAC;AACH,QAAA,MAAM,iBAAiB;;;;;;;;;iBAA2D,CAAC;AAKnF,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAuBjB,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAAI,QAAQ,SAAS,IAAI,GACxF,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GACrC,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACxC;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAAI,QAAQ,SAAS,IAAI,GACtF,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,GACjC,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhC;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,KAAK,EAAE;QACb,MAAM,EAAE;YACN,SAAS,CAAC,EAAE,OAAO,CAAC;YACpB,MAAM,CAAC,EAAE,MAAM,GAAG;gBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YACrC,WAAW,EAAE,MAAM,EAAE,CAAC;SACvB,CAAC;QACF,MAAM,EAAE,CACN,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YACf,IAAI,EAAE,MAAM,CAAC;SACd,KACG;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,GAClC;YAAE,QAAQ,EAAE,UAAU,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GACxC,SAAS,KACV,OAAO,CAAC;QACb,SAAS,EAAE,CACT,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE;YACf,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,MAAM,CAAC;SAClB,KAAK;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,GAAG,SAAS,KAClD,OAAO,CAAC;KACd,KAAK,IAAI,CAAC;CACZ,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,CAAC,QAAQ,SAAS,OAAO,GAAG,KAAK,IAC9D,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAC7B;IACE,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;IACzC,YAAY,EAAE,QAAQ,SAAS,IAAI,GAC/B,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,EAAE,GACpC,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACzC,MAAM,EAAE,qBAAqB,CAAC;CAC/B,CAAC;AAsFN;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CAAC;AAC9F,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,CAAC,IAAI,CAAC,GACpC,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAC/B,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,GACvC,qBAAqB,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -27,6 +27,16 @@ var NativeCommandStopPolicySchema = z.strictObject({
|
|
|
27
27
|
graceMs: z.number().int().nonnegative().max(MAX_COMMAND_STOP_GRACE_MS),
|
|
28
28
|
killOn: z.custom((v) => v instanceof AbortSignal).optional()
|
|
29
29
|
});
|
|
30
|
+
var REMOVED_NATIVE_COMMAND_OPTIONS = {
|
|
31
|
+
killGraceMs: "stop: { target: 'group', graceMs } (removed in 0.105.0)"
|
|
32
|
+
};
|
|
33
|
+
function unknownOptionMessage(keys) {
|
|
34
|
+
return keys.map((key) => {
|
|
35
|
+
const name = String(key);
|
|
36
|
+
const replacement = Object.hasOwn(REMOVED_NATIVE_COMMAND_OPTIONS, name) ? REMOVED_NATIVE_COMMAND_OPTIONS[name] : undefined;
|
|
37
|
+
return replacement === undefined ? `Unknown runNativeCommand option ${name}` : `Unknown runNativeCommand option ${name}; use ${replacement}`;
|
|
38
|
+
}).join("; ");
|
|
39
|
+
}
|
|
30
40
|
var NativeCommandOptionsSchema = z.strictObject({
|
|
31
41
|
executable: z.string().min(1),
|
|
32
42
|
args: z.array(z.string()).default([]),
|
|
@@ -48,6 +58,8 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
48
58
|
}),
|
|
49
59
|
descendants: z.enum(["terminate-after-leader", "leave"]).default("terminate-after-leader"),
|
|
50
60
|
cleanupTimeoutMs: z.number().int().positive().max(30000).default(COMMAND_CLEANUP_TIMEOUT_MS)
|
|
61
|
+
}, {
|
|
62
|
+
error: (issue) => issue.code === "unrecognized_keys" ? unknownOptionMessage(issue.keys) : undefined
|
|
51
63
|
}).check((ctx) => {
|
|
52
64
|
const input = ctx.value;
|
|
53
65
|
if (!input.signal && input.timeoutMs === undefined)
|
|
@@ -72,6 +84,7 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
72
84
|
var NativeCommandResultSchema = z.object({
|
|
73
85
|
exitCode: z.number().int().nullable(),
|
|
74
86
|
signal: z.string().nullable(),
|
|
87
|
+
descendantsStopped: z.boolean(),
|
|
75
88
|
stdout: z.instanceof(Uint8Array),
|
|
76
89
|
stderr: z.instanceof(Uint8Array)
|
|
77
90
|
});
|
|
@@ -158,12 +171,10 @@ async function signalUntilSettled(pid, signal, deadline) {
|
|
|
158
171
|
async function stopCommandGroup(stop) {
|
|
159
172
|
const { pid, policy } = stop;
|
|
160
173
|
const deadline = performance.now() + policy.graceMs + stop.cleanupTimeoutMs;
|
|
161
|
-
if (stop.force || policy.killOn?.aborted)
|
|
162
|
-
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
174
|
+
if (stop.force || policy.killOn?.aborted)
|
|
175
|
+
return signalUntilSettled(pid, "SIGKILL", deadline);
|
|
165
176
|
if (!await signalUntilSettled(pid, policy.signal, deadline))
|
|
166
|
-
return;
|
|
177
|
+
return false;
|
|
167
178
|
const until = performance.now() + policy.graceMs;
|
|
168
179
|
let interval = 10;
|
|
169
180
|
let present = exists(pid);
|
|
@@ -176,14 +187,17 @@ async function stopCommandGroup(stop) {
|
|
|
176
187
|
}
|
|
177
188
|
if (present)
|
|
178
189
|
await signalUntilSettled(pid, "SIGKILL", deadline);
|
|
190
|
+
return true;
|
|
179
191
|
}
|
|
180
192
|
async function stopCommandLeader(stop) {
|
|
181
193
|
const { pid, policy, leader } = stop;
|
|
182
194
|
const deadline = performance.now() + policy.graceMs + stop.cleanupTimeoutMs;
|
|
183
195
|
const running = () => leader.exitCode === null && leader.signalCode === null;
|
|
196
|
+
let signalled = false;
|
|
184
197
|
if (!stop.force && !policy.killOn?.aborted && pid !== undefined && running()) {
|
|
185
198
|
try {
|
|
186
199
|
process.kill(pid, policy.signal);
|
|
200
|
+
signalled = true;
|
|
187
201
|
} catch (error) {
|
|
188
202
|
if (!isErrno(error, "ESRCH"))
|
|
189
203
|
throw error;
|
|
@@ -198,7 +212,7 @@ async function stopCommandLeader(stop) {
|
|
|
198
212
|
policy.killOn?.removeEventListener("abort", end);
|
|
199
213
|
grace.abort();
|
|
200
214
|
}
|
|
201
|
-
await signalUntilSettled(pid, "SIGKILL", deadline);
|
|
215
|
+
return await signalUntilSettled(pid, "SIGKILL", deadline) || signalled;
|
|
202
216
|
}
|
|
203
217
|
function commandCleanupError(cause) {
|
|
204
218
|
return new NativeCommandError2("COMMAND_CLEANUP", "Command cleanup did not complete", {
|
|
@@ -616,8 +630,11 @@ function signalCommandChild(child, input) {
|
|
|
616
630
|
return input.policy.target === "leader" ? stopCommandLeader({ ...stop, leader: child, leaderExit: input.leaderExit }) : stopCommandGroup(stop);
|
|
617
631
|
}
|
|
618
632
|
return Promise.resolve().then(() => {
|
|
619
|
-
if (child.exitCode
|
|
633
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
634
|
+
return false;
|
|
635
|
+
if (!child.kill("SIGKILL"))
|
|
620
636
|
throw new Error("Command leader termination was refused");
|
|
637
|
+
return true;
|
|
621
638
|
});
|
|
622
639
|
}
|
|
623
640
|
async function terminateOwnedGroup(child, closed, cleanupTimeoutMs) {
|
|
@@ -677,7 +694,7 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
677
694
|
});
|
|
678
695
|
const signalOwned = (force = driver?.force) => {
|
|
679
696
|
if (!acquired)
|
|
680
|
-
return Promise.resolve();
|
|
697
|
+
return Promise.resolve(false);
|
|
681
698
|
return signalCommandChild(acquired.child, {
|
|
682
699
|
group: driver?.group !== false,
|
|
683
700
|
policy: options.stop,
|
|
@@ -757,6 +774,7 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
757
774
|
}
|
|
758
775
|
}
|
|
759
776
|
};
|
|
777
|
+
let descendantsStopped = false;
|
|
760
778
|
const settleLeader = async (event) => {
|
|
761
779
|
await settle(event);
|
|
762
780
|
if (controller.signal.aborted)
|
|
@@ -764,7 +782,7 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
764
782
|
if (options.descendants !== "terminate-after-leader" || event.kind !== "exit")
|
|
765
783
|
return;
|
|
766
784
|
try {
|
|
767
|
-
await signalOwned();
|
|
785
|
+
descendantsStopped = await signalOwned();
|
|
768
786
|
} catch (cause) {
|
|
769
787
|
throw commandCleanupError(cause);
|
|
770
788
|
}
|
|
@@ -780,7 +798,12 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
780
798
|
const status = await raceAbort(closed, controller.signal);
|
|
781
799
|
if (spawnFailure !== undefined)
|
|
782
800
|
throw spawnFailure;
|
|
783
|
-
return {
|
|
801
|
+
return {
|
|
802
|
+
...status,
|
|
803
|
+
descendantsStopped,
|
|
804
|
+
stdout: Buffer.concat(stdout),
|
|
805
|
+
stderr: Buffer.concat(stderr)
|
|
806
|
+
};
|
|
784
807
|
} catch (error) {
|
|
785
808
|
controller.abort(error);
|
|
786
809
|
await cleanupNativeCommand({
|
|
@@ -29,7 +29,15 @@ async function sweepAtomicStaging2(options) {
|
|
|
29
29
|
signal?.throwIfAborted();
|
|
30
30
|
const cutoff = Date.now() - olderThanMs;
|
|
31
31
|
const removed = [];
|
|
32
|
-
|
|
32
|
+
let names;
|
|
33
|
+
try {
|
|
34
|
+
names = await readdir(directory);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (isMissing(error))
|
|
37
|
+
return removed;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
for (const name of names) {
|
|
33
41
|
signal?.throwIfAborted();
|
|
34
42
|
if (!isAtomicStagingName2(name))
|
|
35
43
|
continue;
|
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
} from "./index-v5ee8ath.js";
|
|
8
8
|
import {
|
|
9
9
|
stagingName
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-j4zh647a.js";
|
|
11
11
|
import {
|
|
12
12
|
NativeCommandError2,
|
|
13
13
|
CommandStopped,
|
|
14
14
|
startNativeCommand
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-5c26631f.js";
|
|
16
16
|
import {
|
|
17
17
|
probeAgentProcessSandboxOutcome,
|
|
18
18
|
missingSandboxRestrictions2,
|
|
@@ -40,7 +40,8 @@ export interface SweepAtomicStagingOptions {
|
|
|
40
40
|
* Remove the abandoned staging files of atomic writes from one directory and return their
|
|
41
41
|
* names. Only regular files matching {@link isAtomicStagingName} and older than `olderThanMs`
|
|
42
42
|
* are removed; a symlink, a directory or any other entry is left alone, and nothing is
|
|
43
|
-
* followed or recursed into.
|
|
43
|
+
* followed or recursed into. A `directory` that does not exist holds nothing to sweep and
|
|
44
|
+
* yields `[]`; any other listing failure (a file in its place, a denied read) throws.
|
|
44
45
|
*/
|
|
45
46
|
export declare function sweepAtomicStaging(options: SweepAtomicStagingOptions): Promise<string[]>;
|
|
46
47
|
//# sourceMappingURL=atomic-staging.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-staging.d.ts","sourceRoot":"","sources":["../../src/internal/atomic-staging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAaH,mGAAmG;AACnG,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,6CAA6C;AAC7C,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAQD
|
|
1
|
+
{"version":3,"file":"atomic-staging.d.ts","sourceRoot":"","sources":["../../src/internal/atomic-staging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAaH,mGAAmG;AACnG,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,6CAA6C;AAC7C,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAQD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB"}
|
|
@@ -11,7 +11,7 @@ export declare function cleanupNativeCommand(input: {
|
|
|
11
11
|
transport?: NativeCommandTransport;
|
|
12
12
|
settle: (event: NativeCommandSettlement) => Promise<void>;
|
|
13
13
|
event?: NativeCommandSettlement;
|
|
14
|
-
signal: () => Promise<
|
|
14
|
+
signal: () => Promise<unknown>;
|
|
15
15
|
timeoutMs: number;
|
|
16
16
|
}): Promise<void>;
|
|
17
17
|
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/process/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/process/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BhB"}
|
|
@@ -8,12 +8,13 @@ export declare function createCommandLifetime(input: {
|
|
|
8
8
|
result: Promise<NativeCommandResult>;
|
|
9
9
|
controller: AbortController;
|
|
10
10
|
finished: () => boolean;
|
|
11
|
-
signal: () => Promise<
|
|
11
|
+
signal: () => Promise<unknown>;
|
|
12
12
|
cleanupTimeoutMs: number;
|
|
13
13
|
}): {
|
|
14
14
|
result: Promise<{
|
|
15
15
|
exitCode: number | null;
|
|
16
16
|
signal: string | null;
|
|
17
|
+
descendantsStopped: boolean;
|
|
17
18
|
stdout: Uint8Array<ArrayBuffer>;
|
|
18
19
|
stderr: Uint8Array<ArrayBuffer>;
|
|
19
20
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-lifetime.d.ts","sourceRoot":"","sources":["../../src/process/command-lifetime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAG1E,gFAAgF;AAChF,qBAAa,cAAe,SAAQ,YAAY;IAC9C,cAEC;CACF;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrC,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"command-lifetime.d.ts","sourceRoot":"","sources":["../../src/process/command-lifetime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAG1E,gFAAgF;AAChF,qBAAa,cAAe,SAAQ,YAAY;IAC9C,cAEC;CACF;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrC,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;IAKG,MAAM;;;;;;;IACA,SAAS;IAoBT,IAAI;EAKb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;AAMlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,EACzD,MAAM,CAAC,EAAE,yBAAyB
|
|
1
|
+
{"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;AAMlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,EACzD,MAAM,CAAC,EAAE,yBAAyB;;;;;;;;;;EA+LnC"}
|
|
@@ -89,12 +89,13 @@ export type ParsedNativeCommandOptions = z.output<typeof NativeCommandOptionsSch
|
|
|
89
89
|
declare const NativeCommandResultSchema: z.ZodObject<{
|
|
90
90
|
exitCode: z.ZodNullable<z.ZodNumber>;
|
|
91
91
|
signal: z.ZodNullable<z.ZodString>;
|
|
92
|
+
descendantsStopped: z.ZodBoolean;
|
|
92
93
|
stdout: z.ZodInstanceOf<Uint8Array<ArrayBuffer>>;
|
|
93
94
|
stderr: z.ZodInstanceOf<Uint8Array<ArrayBuffer>>;
|
|
94
95
|
}, z.core.$strip>;
|
|
95
96
|
/**
|
|
96
|
-
* Exit code, signal
|
|
97
|
-
* stay empty unless `capture` was set.
|
|
97
|
+
* Exit code, signal, whether descendants were stopped after the leader exited, and captured
|
|
98
|
+
* stdout and stderr bytes of a finished command; the buffers stay empty unless `capture` was set.
|
|
98
99
|
*/
|
|
99
100
|
export type NativeCommandResult = z.infer<typeof NativeCommandResultSchema>;
|
|
100
101
|
declare const NativeCommandLimitReasonSchema: z.ZodEnum<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/process/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,6BAA6B;;;;;;;2BAOjC,CAAC;AACH;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,UAAY,CAAC;AAEnD,QAAA,MAAM,6BAA6B;;;;;;;;;;;;;;;kBAOjC,CAAC;AACH;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,6BAA6B,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/process/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,6BAA6B;;;;;;;2BAOjC,CAAC;AACH;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,UAAY,CAAC;AAEnD,QAAA,MAAM,6BAA6B;;;;;;;;;;;;;;;kBAOjC,CAAC;AACH;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAqB3F,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;gDAqBpB,UAAU,WACR,QAAQ,GAAG,QAAQ,UACpB,WAAW,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uDAKX,uBAAuB,UAAU,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;kBA+CzF,CAAC;AACL;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC9E,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACrF,QAAA,MAAM,yBAAyB;;;;;;iBAU7B,CAAC;AACH;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,QAAA,MAAM,8BAA8B;;;EAAwC,CAAC;AAE7E;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;aAezB,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB;IAdnF,2GAA2G;IAC3G,SAAgB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GAAG,SAAS,CAAC;IAEnF,YACE,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAA;KAAE,EACpF;IACF,YACE,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB,EACjE,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,KAAK,CAAA;KAAE,EAC3C;CAgBH"}
|
package/dist/process/group.d.ts
CHANGED
|
@@ -23,8 +23,9 @@ export interface CommandGroupStop {
|
|
|
23
23
|
* A group still visible after the grace (including members holding a pipe after
|
|
24
24
|
* the leader exited, or Darwin zombies awaiting the reaper) is killed. The probe
|
|
25
25
|
* backs off to 250 ms, so a grace of an hour costs a few thousand probes, not millions.
|
|
26
|
+
* Resolves `true` when the group still had a member to receive the first signal.
|
|
26
27
|
*/
|
|
27
|
-
export declare function stopCommandGroup(stop: CommandGroupStop): Promise<
|
|
28
|
+
export declare function stopCommandGroup(stop: CommandGroupStop): Promise<boolean>;
|
|
28
29
|
/** The leader of a stop with `target: 'leader'`: its exit state and the promise of its exit. */
|
|
29
30
|
export interface CommandLeader {
|
|
30
31
|
readonly pid?: number;
|
|
@@ -38,11 +39,12 @@ export interface CommandLeader {
|
|
|
38
39
|
* The leader's exit ends the grace at once: the rest of the group are processes the leader
|
|
39
40
|
* left behind, and nothing in them was asked to cooperate. A leader that has already
|
|
40
41
|
* exited is not signalled again, because its pid may be reused once it was reaped.
|
|
42
|
+
* Resolves `true` when the leader or a member of its group received a signal.
|
|
41
43
|
*/
|
|
42
44
|
export declare function stopCommandLeader(stop: CommandGroupStop & {
|
|
43
45
|
leader: CommandLeader;
|
|
44
46
|
leaderExit: Promise<unknown>;
|
|
45
|
-
}): Promise<
|
|
47
|
+
}): Promise<boolean>;
|
|
46
48
|
export declare function commandCleanupError(cause: unknown): NativeCommandError;
|
|
47
49
|
export declare function waitForCommandClose<T>(closed: Promise<T>, timeoutMs: number): Promise<T>;
|
|
48
50
|
//# sourceMappingURL=group.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/process/group.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAEpF,+FAA+F;AAC/F,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IAYpE,MAAM;IACN,MAAM;EAIT;AAeD,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CASpF;AAmCD,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED
|
|
1
|
+
{"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/process/group.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAEpF,+FAA+F;AAC/F,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IAYpE,MAAM;IACN,MAAM;EAIT;AAeD,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CASpF;AAmCD,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB/E;AAED,gGAAgG;AAChG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,gBAAgB,GAAG;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GAC/E,OAAO,CAAC,OAAO,CAAC,CAsBlB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAItE;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAMxF"}
|
|
@@ -7,7 +7,8 @@ interface SignalableChild extends CommandLeader {
|
|
|
7
7
|
/**
|
|
8
8
|
* Deliver the stop signals to `child` by its stop policy. A child this package spawned as a
|
|
9
9
|
* group leader is stopped as a group (`target: 'group'`) or leader first (`'leader'`); any
|
|
10
|
-
* other child is only a leader, killed while it still runs.
|
|
10
|
+
* other child is only a leader, killed while it still runs. Resolves `true` when a signal
|
|
11
|
+
* reached a process.
|
|
11
12
|
*/
|
|
12
13
|
export declare function signalCommandChild(child: SignalableChild, input: {
|
|
13
14
|
group: boolean;
|
|
@@ -16,7 +17,7 @@ export declare function signalCommandChild(child: SignalableChild, input: {
|
|
|
16
17
|
leaderExit: Promise<unknown>;
|
|
17
18
|
cleanupTimeoutMs: number;
|
|
18
19
|
force: boolean;
|
|
19
|
-
}): Promise<
|
|
20
|
+
}): Promise<boolean>;
|
|
20
21
|
interface ClosableChild extends SignalableChild {
|
|
21
22
|
readonly stdin: {
|
|
22
23
|
destroy(): unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminate.d.ts","sourceRoot":"","sources":["../../src/process/terminate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,SAAS,CAAC;AAGjB,mFAAmF;AACnF,UAAU,eAAgB,SAAQ,aAAa;IAC7C,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;CAClC;AAED
|
|
1
|
+
{"version":3,"file":"terminate.d.ts","sourceRoot":"","sources":["../../src/process/terminate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,SAAS,CAAC;AAGjB,mFAAmF;AACnF,UAAU,eAAgB,SAAQ,aAAa;IAC7C,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE;IACL,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,6BAA6B,CAAC;IACtC,mFAAmF;IACnF,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;CAChB,GACA,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,UAAU,aAAc,SAAQ,eAAe;IAC7C,QAAQ,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,OAAO,CAAA;KAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE;QAAE,OAAO,IAAI,OAAO,CAAA;KAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE;QAAE,OAAO,IAAI,OAAO,CAAA;KAAE,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,EACxB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAcf"}
|
package/llms/files-packaging.txt
CHANGED
|
@@ -20,6 +20,8 @@ It resolves the installed package's target/version, reads each selected addon on
|
|
|
20
20
|
against the `size` and `sha256` published in the package's `native-assets.json` (`formatVersion: 2`,
|
|
21
21
|
written when Stitchkit is built). Call it once per build and reuse the result.
|
|
22
22
|
`platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit public inputs;
|
|
23
|
+
`assetPath` accepts one template, `[hash]`, replaced by the first 16 hex digits of the addon's
|
|
24
|
+
published SHA256;
|
|
23
25
|
`platform` is the closed set `'darwin'`, and another name is a type error and a schema refusal.
|
|
24
26
|
The result is `ready` with verified assets and a structural Bun plugin, or `unsupported` /
|
|
25
27
|
`missing` / `mismatch` with the safe code `NATIVE_TARGET_UNSUPPORTED`, `NATIVE_ASSET_MISSING` or
|
package/llms/files.txt
CHANGED
|
@@ -31,7 +31,7 @@ available from `stitchkit/contract`.
|
|
|
31
31
|
| `ManagedFileInspectionInput` / `ManagedFileInspection` | _type_ | inspector prefix/name/declared media/signal input and validated metadata-only result |
|
|
32
32
|
| `writeFileAtomic` / `writeFileAtomicSync` / `WriteFileAtomicOptions` | function / _type_ | replace a file atomically: a random staging name created exclusively (never through a planted link), the mode set on the descriptor before the file is visible (default `0o600`, not masked by the umask), `fsync`, rename; a failure leaves the target and no staging file. The asynchronous form keeps the event loop running. A process killed before publication leaves its staging file; sweeping it is the caller's job |
|
|
33
33
|
| `isAtomicStagingName` | function | true for a staging file name of an atomic write of this library (`.stitchkit-<24 lowercase hex>.tmp`, also used by the managed writer and the chunk spool); the form is a stable contract, and changing it is a breaking change ([ADR 0242](../decisions/0242-atomic-staging-name-is-a-public-contract.md)) |
|
|
34
|
-
| `sweepAtomicStaging` / `SweepAtomicStagingOptions` | function / _type_ | remove abandoned staging files from one `directory`: only regular files matching `isAtomicStagingName` and older than the required `olderThanMs`, never following a symlink or entering a subdirectory; stops on `signal`; returns the removed names |
|
|
34
|
+
| `sweepAtomicStaging` / `SweepAtomicStagingOptions` | function / _type_ | remove abandoned staging files from one `directory`: only regular files matching `isAtomicStagingName` and older than the required `olderThanMs`, never following a symlink or entering a subdirectory; stops on `signal`; returns the removed names, `[]` for a `directory` that does not exist |
|
|
35
35
|
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time and nullable kernel process identity); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; the lock is published with its owner already recorded (temporary file plus hard link), so a stalled holder is never displaced; a legacy empty lock file is taken by age only when `ownerlessGraceMs` is a number (default `null`: never; an abandoned empty reclaim guard is taken after 5 000 ms unless a value is set); exact `mode` is independent of umask; shared readers need a common group and traversable directories |
|
|
36
36
|
| `ExclusiveLockError` | class | `LOCK_TIMEOUT` naming the resource and its holder, or `LOCK_ABORTED` with the signal's reason |
|
|
37
37
|
| `createChunkSpool` | function | the server half of a chunked upload: parts on disk under `owner` + client-minted `uploadId`, each with a size+sha256 receipt; idempotent `open` and `put`, the first writer of a part wins across processes, `assemble` in order once every part is in, `sweep` of untouched uploads — [guide](../guide/client.md#chunked-uploads) |
|
package/llms/process.txt
CHANGED
|
@@ -68,7 +68,8 @@ The bytes are staged beside the target under `.stitchkit-<24 lowercase hex>.tmp`
|
|
|
68
68
|
`writeFileAtomic`, `writeFileAtomicSync`, the managed writer and the chunk spool. A process killed
|
|
69
69
|
between the staging and the publication (SIGKILL, OOM, power loss) leaves that file behind, and no
|
|
70
70
|
later write removes it: a random name alone cannot tell an abandoned write from one in flight.
|
|
71
|
-
Removing it is the caller's responsibility
|
|
71
|
+
Removing it is the caller's responsibility. A directory that does not exist yet has nothing to
|
|
72
|
+
sweep and yields `[]`; a file standing where the directory should be, or a denied listing, throws:
|
|
72
73
|
|
|
73
74
|
```ts
|
|
74
75
|
import { isAtomicStagingName, sweepAtomicStaging } from 'stitchkit/files'
|
|
@@ -197,7 +198,7 @@ permanent refusal is kept in the cause. The close of every owned pipe and the le
|
|
|
197
198
|
observed separately, including the absence of a shared `child.close` during teardown. The caller or
|
|
198
199
|
sink cause is kept; a cleanup failure is a `NativeCommandError` with `COMMAND_CLEANUP` and an
|
|
199
200
|
`AggregateError` cause. Even an exited parent does not exclude a helper that holds a pipe. Windows
|
|
200
|
-
refuses with `COMMAND_UNAVAILABLE`; a descendant that
|
|
201
|
+
refuses with `COMMAND_UNAVAILABLE`; a descendant that has left the group on its own with `setsid` is
|
|
201
202
|
outside this capability. This is one-shot execution, not a PTY, a supervisor or a daemon host.
|
|
202
203
|
|
|
203
204
|
### Stopping a command: the `stop` policy
|
|
@@ -252,13 +253,28 @@ successfully:
|
|
|
252
253
|
|
|
253
254
|
| `descendants` | After the leader exits |
|
|
254
255
|
|---|---|
|
|
255
|
-
| `'terminate-after-leader'` (the default) | The group is stopped right after `onLeaderSettled` returns and before the pipes drain: with `target: 'group'` by the same signal, grace, KILL sequence as cancellation; with `target: 'leader'` by KILL at once, since the leader has already exited.
|
|
256
|
+
| `'terminate-after-leader'` (the default) | The group is stopped right after `onLeaderSettled` returns and before the pipes drain: with `target: 'group'` by the same signal, grace, KILL sequence as cancellation; with `target: 'leader'` by KILL at once, since the leader has already exited. A descendant that had already left the group with `setsid` when the leader exited stays out of reach. |
|
|
256
257
|
| `'leave'` | Nothing. A helper started with its stdio detached keeps running. One that inherited stdout or stderr keeps the pipes open, and the command then waits for it until its deadline or abort. |
|
|
257
258
|
|
|
258
259
|
Omitting the option means `'terminate-after-leader'`: a command does not leak the helpers it
|
|
259
|
-
started.
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
started. The result's `descendantsStopped` is `true` when the group still had members after the
|
|
261
|
+
leader exited and they were stopped, so a helper that was ended this way is visible to the caller
|
|
262
|
+
rather than only missing afterwards; under `'leave'` it is always `false`.
|
|
263
|
+
|
|
264
|
+
A real daemon detaches into its own session (`setsid`, as `daemon(3)` does), is no member of the
|
|
265
|
+
group and is unaffected, provided it has left the group **before the leader exits**. Leaving is
|
|
266
|
+
the daemon's own system call, and the group is stopped as soon as the leader's exit is observed,
|
|
267
|
+
so a helper started in the background races the leader:
|
|
268
|
+
|
|
269
|
+
| launched by the leader as | after the leader exits |
|
|
270
|
+
|---|---|
|
|
271
|
+
| `setsid -f helper` (returns once the new session exists) | survives |
|
|
272
|
+
| `setsid helper &`, `(setsid helper &)`, `nohup helper &` | stopped: the leader usually exits before the background job has left the group |
|
|
273
|
+
| any of these under `descendants: 'leave'` | survives |
|
|
274
|
+
|
|
275
|
+
Start a daemon so that the session exists before the leader returns (`setsid -f`, or the
|
|
276
|
+
daemon's own double fork followed by the leader waiting for it), or declare `'leave'`. Declare
|
|
277
|
+
`'leave'` only for a helper that has to outlive the command while staying in its group:
|
|
262
278
|
|
|
263
279
|
```ts
|
|
264
280
|
await runNativeCommand({
|
|
@@ -279,7 +295,17 @@ regular-file read becomes `files.read`; JSON and schema parsing, receipt conflic
|
|
|
279
295
|
and application locks stay with the application. A spawn, drain, capture and cancellation wrapper
|
|
280
296
|
becomes `runNativeCommand`; shell policy, command admission, logging, redaction, the bytes-to-text
|
|
281
297
|
decoder and the operator sink stay with the application. Long signal-only commands stay streaming;
|
|
282
|
-
bounded tar or capture commands get their own explicit limits.
|
|
298
|
+
bounded tar or capture commands get their own explicit limits.
|
|
299
|
+
|
|
300
|
+
A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
|
|
301
|
+
passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`; it reads the
|
|
302
|
+
exit code in `onLeaderSettled`, before the pipes drain, and stderr through `onOutput` or `capture`
|
|
303
|
+
with `maxOutputBytes`, and `cleanupTimeoutMs` bounds the drain (`COMMAND_CLEANUP` when a holder
|
|
304
|
+
keeps the pipe past it). A worker whose whole group must stop on abort is the default
|
|
305
|
+
`target: 'group'`. A child that inherits the caller's terminal is outside this capability: every
|
|
306
|
+
command runs in a group of its own, and a background group that reads the terminal is stopped
|
|
307
|
+
by the kernel (`SIGTTIN`), so an interactive re-execution stays a plain spawn in the caller's
|
|
308
|
+
group. Importing one leaf does not make
|
|
283
309
|
installing the whole npm package smaller; choose a dependency after measuring packed size and its
|
|
284
310
|
dependency closure.
|
|
285
311
|
|
|
@@ -407,7 +433,11 @@ package was built. A ready asset carries those verified `bytes` with the publish
|
|
|
407
433
|
`sha256`; its Bun-compatible plugin integrates the same bytes with the same lazy native loader.
|
|
408
434
|
Each call reads and hashes the selected addons, so call it once per build and reuse the result.
|
|
409
435
|
The leaf is evolving. It requires no optional peer or Bun ambient declarations for Node imports.
|
|
410
|
-
|
|
436
|
+
Calling it must happen in a process that runs it from its installed package: it locates the
|
|
437
|
+
package's `native-assets.json` beside its own file and throws `Native packaging must run from its
|
|
438
|
+
installed Stitchkit package` anywhere else, such as inside an application's runtime artifact.
|
|
439
|
+
Importing the leaf is side-effect free (it loads no addon and reads no file), so a module that
|
|
440
|
+
both builds and is bundled may import it; only the call has to stay in the build step.
|
|
411
441
|
|
|
412
442
|
```ts
|
|
413
443
|
import { createNativePackaging } from 'stitchkit/files/packaging'
|
|
@@ -434,7 +464,11 @@ for (const asset of native.assets) {
|
|
|
434
464
|
```
|
|
435
465
|
|
|
436
466
|
`entryPath` and `assetPath` are relative paths inside the application's output root, without
|
|
437
|
-
absolute paths, traversal or overlapping file/directory paths. `
|
|
467
|
+
absolute paths, traversal or overlapping file/directory paths. `assetPath` may contain `[hash]`,
|
|
468
|
+
which becomes the first 16 hex digits of that addon's published SHA256: the digest is known before
|
|
469
|
+
the build, so `addons/darwin-arm64-[hash].node` gives two installed versions of the package
|
|
470
|
+
different companion names, and the loader requires exactly that name. It is the only template an
|
|
471
|
+
addon path accepts. `entryPath` is fixed, without
|
|
438
472
|
Bun naming templates such as `[dir]` or `[name]`. Companion JS builds require one entry, no splitting,
|
|
439
473
|
and `naming.entry` exactly matching `entryPath`; the plugin rejects a mismatching layout.
|
|
440
474
|
Choose any application layout; the framework does not prescribe an app directory or installer.
|
|
@@ -536,9 +570,9 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
|
|
|
536
570
|
| Export | Kind | Purpose |
|
|
537
571
|
|---|---|---|
|
|
538
572
|
| `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
|
|
539
|
-
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`) |
|
|
573
|
+
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
|
|
540
574
|
| `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
|
|
541
|
-
| `NativeCommandResult` | type | observed nullable exit code/signal and captured stdout/stderr bytes |
|
|
575
|
+
| `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
|
|
542
576
|
| `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
|
|
543
577
|
|
|
544
578
|
| `NativeCommandSettlement` | type | observed leader `exit` or terminal `error`, including synchronous native launch failure; `onLeaderSettled` runs once before drain, bounded by cleanupTimeoutMs, with a cancellable settlement signal; schema/pre-abort refusal creates no settlement obligation |
|
package/llms-full.txt
CHANGED
|
@@ -8210,7 +8210,8 @@ The bytes are staged beside the target under `.stitchkit-<24 lowercase hex>.tmp`
|
|
|
8210
8210
|
`writeFileAtomic`, `writeFileAtomicSync`, the managed writer and the chunk spool. A process killed
|
|
8211
8211
|
between the staging and the publication (SIGKILL, OOM, power loss) leaves that file behind, and no
|
|
8212
8212
|
later write removes it: a random name alone cannot tell an abandoned write from one in flight.
|
|
8213
|
-
Removing it is the caller's responsibility
|
|
8213
|
+
Removing it is the caller's responsibility. A directory that does not exist yet has nothing to
|
|
8214
|
+
sweep and yields `[]`; a file standing where the directory should be, or a denied listing, throws:
|
|
8214
8215
|
|
|
8215
8216
|
```ts
|
|
8216
8217
|
import { isAtomicStagingName, sweepAtomicStaging } from 'stitchkit/files'
|
|
@@ -8339,7 +8340,7 @@ permanent refusal is kept in the cause. The close of every owned pipe and the le
|
|
|
8339
8340
|
observed separately, including the absence of a shared `child.close` during teardown. The caller or
|
|
8340
8341
|
sink cause is kept; a cleanup failure is a `NativeCommandError` with `COMMAND_CLEANUP` and an
|
|
8341
8342
|
`AggregateError` cause. Even an exited parent does not exclude a helper that holds a pipe. Windows
|
|
8342
|
-
refuses with `COMMAND_UNAVAILABLE`; a descendant that
|
|
8343
|
+
refuses with `COMMAND_UNAVAILABLE`; a descendant that has left the group on its own with `setsid` is
|
|
8343
8344
|
outside this capability. This is one-shot execution, not a PTY, a supervisor or a daemon host.
|
|
8344
8345
|
|
|
8345
8346
|
### Stopping a command: the `stop` policy
|
|
@@ -8394,13 +8395,28 @@ successfully:
|
|
|
8394
8395
|
|
|
8395
8396
|
| `descendants` | After the leader exits |
|
|
8396
8397
|
|---|---|
|
|
8397
|
-
| `'terminate-after-leader'` (the default) | The group is stopped right after `onLeaderSettled` returns and before the pipes drain: with `target: 'group'` by the same signal, grace, KILL sequence as cancellation; with `target: 'leader'` by KILL at once, since the leader has already exited.
|
|
8398
|
+
| `'terminate-after-leader'` (the default) | The group is stopped right after `onLeaderSettled` returns and before the pipes drain: with `target: 'group'` by the same signal, grace, KILL sequence as cancellation; with `target: 'leader'` by KILL at once, since the leader has already exited. A descendant that had already left the group with `setsid` when the leader exited stays out of reach. |
|
|
8398
8399
|
| `'leave'` | Nothing. A helper started with its stdio detached keeps running. One that inherited stdout or stderr keeps the pipes open, and the command then waits for it until its deadline or abort. |
|
|
8399
8400
|
|
|
8400
8401
|
Omitting the option means `'terminate-after-leader'`: a command does not leak the helpers it
|
|
8401
|
-
started.
|
|
8402
|
-
|
|
8403
|
-
|
|
8402
|
+
started. The result's `descendantsStopped` is `true` when the group still had members after the
|
|
8403
|
+
leader exited and they were stopped, so a helper that was ended this way is visible to the caller
|
|
8404
|
+
rather than only missing afterwards; under `'leave'` it is always `false`.
|
|
8405
|
+
|
|
8406
|
+
A real daemon detaches into its own session (`setsid`, as `daemon(3)` does), is no member of the
|
|
8407
|
+
group and is unaffected, provided it has left the group **before the leader exits**. Leaving is
|
|
8408
|
+
the daemon's own system call, and the group is stopped as soon as the leader's exit is observed,
|
|
8409
|
+
so a helper started in the background races the leader:
|
|
8410
|
+
|
|
8411
|
+
| launched by the leader as | after the leader exits |
|
|
8412
|
+
|---|---|
|
|
8413
|
+
| `setsid -f helper` (returns once the new session exists) | survives |
|
|
8414
|
+
| `setsid helper &`, `(setsid helper &)`, `nohup helper &` | stopped: the leader usually exits before the background job has left the group |
|
|
8415
|
+
| any of these under `descendants: 'leave'` | survives |
|
|
8416
|
+
|
|
8417
|
+
Start a daemon so that the session exists before the leader returns (`setsid -f`, or the
|
|
8418
|
+
daemon's own double fork followed by the leader waiting for it), or declare `'leave'`. Declare
|
|
8419
|
+
`'leave'` only for a helper that has to outlive the command while staying in its group:
|
|
8404
8420
|
|
|
8405
8421
|
```ts
|
|
8406
8422
|
await runNativeCommand({
|
|
@@ -8421,7 +8437,17 @@ regular-file read becomes `files.read`; JSON and schema parsing, receipt conflic
|
|
|
8421
8437
|
and application locks stay with the application. A spawn, drain, capture and cancellation wrapper
|
|
8422
8438
|
becomes `runNativeCommand`; shell policy, command admission, logging, redaction, the bytes-to-text
|
|
8423
8439
|
decoder and the operator sink stay with the application. Long signal-only commands stay streaming;
|
|
8424
|
-
bounded tar or capture commands get their own explicit limits.
|
|
8440
|
+
bounded tar or capture commands get their own explicit limits.
|
|
8441
|
+
|
|
8442
|
+
A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
|
|
8443
|
+
passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`; it reads the
|
|
8444
|
+
exit code in `onLeaderSettled`, before the pipes drain, and stderr through `onOutput` or `capture`
|
|
8445
|
+
with `maxOutputBytes`, and `cleanupTimeoutMs` bounds the drain (`COMMAND_CLEANUP` when a holder
|
|
8446
|
+
keeps the pipe past it). A worker whose whole group must stop on abort is the default
|
|
8447
|
+
`target: 'group'`. A child that inherits the caller's terminal is outside this capability: every
|
|
8448
|
+
command runs in a group of its own, and a background group that reads the terminal is stopped
|
|
8449
|
+
by the kernel (`SIGTTIN`), so an interactive re-execution stays a plain spawn in the caller's
|
|
8450
|
+
group. Importing one leaf does not make
|
|
8425
8451
|
installing the whole npm package smaller; choose a dependency after measuring packed size and its
|
|
8426
8452
|
dependency closure.
|
|
8427
8453
|
|
|
@@ -8549,7 +8575,11 @@ package was built. A ready asset carries those verified `bytes` with the publish
|
|
|
8549
8575
|
`sha256`; its Bun-compatible plugin integrates the same bytes with the same lazy native loader.
|
|
8550
8576
|
Each call reads and hashes the selected addons, so call it once per build and reuse the result.
|
|
8551
8577
|
The leaf is evolving. It requires no optional peer or Bun ambient declarations for Node imports.
|
|
8552
|
-
|
|
8578
|
+
Calling it must happen in a process that runs it from its installed package: it locates the
|
|
8579
|
+
package's `native-assets.json` beside its own file and throws `Native packaging must run from its
|
|
8580
|
+
installed Stitchkit package` anywhere else, such as inside an application's runtime artifact.
|
|
8581
|
+
Importing the leaf is side-effect free (it loads no addon and reads no file), so a module that
|
|
8582
|
+
both builds and is bundled may import it; only the call has to stay in the build step.
|
|
8553
8583
|
|
|
8554
8584
|
```ts
|
|
8555
8585
|
import { createNativePackaging } from 'stitchkit/files/packaging'
|
|
@@ -8576,7 +8606,11 @@ for (const asset of native.assets) {
|
|
|
8576
8606
|
```
|
|
8577
8607
|
|
|
8578
8608
|
`entryPath` and `assetPath` are relative paths inside the application's output root, without
|
|
8579
|
-
absolute paths, traversal or overlapping file/directory paths. `
|
|
8609
|
+
absolute paths, traversal or overlapping file/directory paths. `assetPath` may contain `[hash]`,
|
|
8610
|
+
which becomes the first 16 hex digits of that addon's published SHA256: the digest is known before
|
|
8611
|
+
the build, so `addons/darwin-arm64-[hash].node` gives two installed versions of the package
|
|
8612
|
+
different companion names, and the loader requires exactly that name. It is the only template an
|
|
8613
|
+
addon path accepts. `entryPath` is fixed, without
|
|
8580
8614
|
Bun naming templates such as `[dir]` or `[name]`. Companion JS builds require one entry, no splitting,
|
|
8581
8615
|
and `naming.entry` exactly matching `entryPath`; the plugin rejects a mismatching layout.
|
|
8582
8616
|
Choose any application layout; the framework does not prescribe an app directory or installer.
|
|
@@ -22039,7 +22073,7 @@ available from `stitchkit/contract`.
|
|
|
22039
22073
|
| `ManagedFileInspectionInput` / `ManagedFileInspection` | _type_ | inspector prefix/name/declared media/signal input and validated metadata-only result |
|
|
22040
22074
|
| `writeFileAtomic` / `writeFileAtomicSync` / `WriteFileAtomicOptions` | function / _type_ | replace a file atomically: a random staging name created exclusively (never through a planted link), the mode set on the descriptor before the file is visible (default `0o600`, not masked by the umask), `fsync`, rename; a failure leaves the target and no staging file. The asynchronous form keeps the event loop running. A process killed before publication leaves its staging file; sweeping it is the caller's job |
|
|
22041
22075
|
| `isAtomicStagingName` | function | true for a staging file name of an atomic write of this library (`.stitchkit-<24 lowercase hex>.tmp`, also used by the managed writer and the chunk spool); the form is a stable contract, and changing it is a breaking change ([ADR 0242](../decisions/0242-atomic-staging-name-is-a-public-contract.md)) |
|
|
22042
|
-
| `sweepAtomicStaging` / `SweepAtomicStagingOptions` | function / _type_ | remove abandoned staging files from one `directory`: only regular files matching `isAtomicStagingName` and older than the required `olderThanMs`, never following a symlink or entering a subdirectory; stops on `signal`; returns the removed names |
|
|
22076
|
+
| `sweepAtomicStaging` / `SweepAtomicStagingOptions` | function / _type_ | remove abandoned staging files from one `directory`: only regular files matching `isAtomicStagingName` and older than the required `olderThanMs`, never following a symlink or entering a subdirectory; stops on `signal`; returns the removed names, `[]` for a `directory` that does not exist |
|
|
22043
22077
|
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time and nullable kernel process identity); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; the lock is published with its owner already recorded (temporary file plus hard link), so a stalled holder is never displaced; a legacy empty lock file is taken by age only when `ownerlessGraceMs` is a number (default `null`: never; an abandoned empty reclaim guard is taken after 5 000 ms unless a value is set); exact `mode` is independent of umask; shared readers need a common group and traversable directories |
|
|
22044
22078
|
| `ExclusiveLockError` | class | `LOCK_TIMEOUT` naming the resource and its holder, or `LOCK_ABORTED` with the signal's reason |
|
|
22045
22079
|
| `createChunkSpool` | function | the server half of a chunked upload: parts on disk under `owner` + client-minted `uploadId`, each with a size+sha256 receipt; idempotent `open` and `put`, the first writer of a part wins across processes, `assemble` in order once every part is in, `sweep` of untouched uploads — [guide](../guide/client.md#chunked-uploads) |
|
|
@@ -22608,9 +22642,9 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
|
|
|
22608
22642
|
| Export | Kind | Purpose |
|
|
22609
22643
|
|---|---|---|
|
|
22610
22644
|
| `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
|
|
22611
|
-
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`) |
|
|
22645
|
+
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
|
|
22612
22646
|
| `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
|
|
22613
|
-
| `NativeCommandResult` | type | observed nullable exit code/signal and captured stdout/stderr bytes |
|
|
22647
|
+
| `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
|
|
22614
22648
|
| `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
|
|
22615
22649
|
|
|
22616
22650
|
| `NativeCommandSettlement` | type | observed leader `exit` or terminal `error`, including synchronous native launch failure; `onLeaderSettled` runs once before drain, bounded by cleanupTimeoutMs, with a cancellable settlement signal; schema/pre-abort refusal creates no settlement obligation |
|
|
@@ -22626,6 +22660,8 @@ It resolves the installed package's target/version, reads each selected addon on
|
|
|
22626
22660
|
against the `size` and `sha256` published in the package's `native-assets.json` (`formatVersion: 2`,
|
|
22627
22661
|
written when Stitchkit is built). Call it once per build and reuse the result.
|
|
22628
22662
|
`platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit public inputs;
|
|
22663
|
+
`assetPath` accepts one template, `[hash]`, replaced by the first 16 hex digits of the addon's
|
|
22664
|
+
published SHA256;
|
|
22629
22665
|
`platform` is the closed set `'darwin'`, and another name is a type error and a schema refusal.
|
|
22630
22666
|
The result is `ready` with verified assets and a structural Bun plugin, or `unsupported` /
|
|
22631
22667
|
`missing` / `mismatch` with the safe code `NATIVE_TARGET_UNSUPPORTED`, `NATIVE_ASSET_MISSING` or
|
package/llms.txt
CHANGED
|
@@ -56,8 +56,8 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
56
56
|
- **stitchkit/node**: [llms/node.txt](llms/node.txt) 3.1 KB
|
|
57
57
|
- **stitchkit/agent-runtime/react**: [llms/agent-runtime-react.txt](llms/agent-runtime-react.txt) 1.0 KB
|
|
58
58
|
- **stitchkit/agent-runtime/realtime**: [llms/agent-runtime-realtime.txt](llms/agent-runtime-realtime.txt) 2.6 KB
|
|
59
|
-
- **stitchkit/process**: [llms/process.txt](llms/process.txt)
|
|
60
|
-
- **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 2.
|
|
59
|
+
- **stitchkit/process**: [llms/process.txt](llms/process.txt) 35.6 KB
|
|
60
|
+
- **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 2.8 KB
|
|
61
61
|
|
|
62
62
|
## Upgrading slices
|
|
63
63
|
- **Upgrading — how to move across versions**: [llms/upgrading.txt](llms/upgrading.txt) 10.3 KB
|
package/package.json
CHANGED