stitchkit 0.94.1 → 0.95.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/CHANGELOG.md +40 -0
- package/dist/agent-runtime/provider-origin.d.ts +7 -0
- package/dist/agent-runtime/provider-origin.d.ts.map +1 -1
- package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
- package/dist/application/process-lifecycle-transitions.d.ts +175 -0
- package/dist/application/process-lifecycle-transitions.d.ts.map +1 -0
- package/dist/application/process-lifecycle.d.ts +3 -131
- package/dist/application/process-lifecycle.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +1 -1
- package/dist/entrypoints/agent-runtime.js +1 -1
- package/dist/entrypoints/application.d.ts +2 -1
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +145 -56
- package/dist/{index-7f68ghdn.js → index-8zja4pkf.js} +23 -1
- package/llms/application.2.txt +5 -5
- package/llms/application.txt +58 -23
- package/llms/stitchkit.txt +3 -3
- package/llms/{upgrading-0.37.0-0.50.0.txt → upgrading-0.37.0-0.53.0.txt} +25 -3
- package/llms/{upgrading-0.53.0-0.67.0.txt → upgrading-0.55.0-0.68.0.txt} +53 -25
- package/llms/{upgrading-0.68.0-0.94.0.txt → upgrading-0.69.0-0.95.0.txt} +45 -53
- package/llms/upgrading.txt +3 -3
- package/llms-full.txt +108 -31
- package/llms.txt +4 -4
- package/package.json +1 -1
|
@@ -1068,21 +1068,28 @@ function notificationOutboxResource(outbox, config = {}) {
|
|
|
1068
1068
|
});
|
|
1069
1069
|
}
|
|
1070
1070
|
// src/application/process-lifecycle.ts
|
|
1071
|
+
import { z as z7 } from "zod";
|
|
1072
|
+
|
|
1073
|
+
// src/application/process-lifecycle-transitions.ts
|
|
1071
1074
|
import { z as z6 } from "zod";
|
|
1072
1075
|
var LifecycleTerminationSchema = z6.enum([
|
|
1073
1076
|
"active",
|
|
1077
|
+
"draining",
|
|
1074
1078
|
"clean",
|
|
1075
1079
|
"forced",
|
|
1080
|
+
"startup-failed",
|
|
1076
1081
|
"hot-reload",
|
|
1077
1082
|
"abnormal"
|
|
1078
1083
|
]);
|
|
1084
|
+
var timestamp = z6.string().datetime({ offset: true });
|
|
1079
1085
|
var LifecycleRunSchema = z6.object({
|
|
1080
1086
|
runId: z6.string().min(1).max(128),
|
|
1081
1087
|
pid: z6.number().int().positive(),
|
|
1082
1088
|
version: z6.string().min(1).max(256),
|
|
1083
|
-
startedAt:
|
|
1084
|
-
readyAt:
|
|
1085
|
-
|
|
1089
|
+
startedAt: timestamp,
|
|
1090
|
+
readyAt: timestamp.nullable(),
|
|
1091
|
+
unavailableAt: timestamp.nullable().default(null),
|
|
1092
|
+
stoppedAt: timestamp.nullable(),
|
|
1086
1093
|
termination: LifecycleTerminationSchema
|
|
1087
1094
|
}).strict();
|
|
1088
1095
|
var LifecycleStateSchema = z6.object({
|
|
@@ -1094,17 +1101,20 @@ var PreviousExitSchema = z6.enum([
|
|
|
1094
1101
|
"hot-reload",
|
|
1095
1102
|
"clean",
|
|
1096
1103
|
"forced",
|
|
1104
|
+
"startup-failed",
|
|
1097
1105
|
"handoff",
|
|
1098
1106
|
"abnormal"
|
|
1099
1107
|
]);
|
|
1100
1108
|
var emptyState = () => ({ schemaVersion: 1, runs: [] });
|
|
1101
1109
|
var epoch = (value) => Date.parse(value);
|
|
1102
1110
|
var elapsed = (later, earlier) => Math.max(0, epoch(later) - epoch(earlier));
|
|
1103
|
-
|
|
1111
|
+
var isOpenRun = (run) => run.termination === "active" || run.termination === "draining";
|
|
1112
|
+
function normalizeLifecycleState(state, retain) {
|
|
1104
1113
|
const parsed = LifecycleStateSchema.parse(state ?? emptyState());
|
|
1105
1114
|
const runs = [...parsed.runs];
|
|
1106
1115
|
for (let index = runs.length - 1;runs.length > retain && index >= 0; index -= 1) {
|
|
1107
|
-
|
|
1116
|
+
const run = runs[index];
|
|
1117
|
+
if (run && !isOpenRun(run))
|
|
1108
1118
|
runs.splice(index, 1);
|
|
1109
1119
|
}
|
|
1110
1120
|
return { schemaVersion: 1, runs: runs.slice(0, retain) };
|
|
@@ -1113,15 +1123,45 @@ var UNKNOWN_VERSION = "unknown";
|
|
|
1113
1123
|
function isVersionChange(previous, next) {
|
|
1114
1124
|
return previous !== UNKNOWN_VERSION && next !== UNKNOWN_VERSION && previous !== next;
|
|
1115
1125
|
}
|
|
1126
|
+
var RetainSchema = z6.number().int().min(1).max(1000);
|
|
1127
|
+
function previousExitOf(previous, run, overlap) {
|
|
1128
|
+
if (!previous)
|
|
1129
|
+
return "first-boot";
|
|
1130
|
+
const ended = previous.termination;
|
|
1131
|
+
if (ended !== "active" && ended !== "draining")
|
|
1132
|
+
return ended;
|
|
1133
|
+
if (previous.pid === run.pid)
|
|
1134
|
+
return "hot-reload";
|
|
1135
|
+
if (isVersionChange(previous.version, run.version) || overlap === "handoff")
|
|
1136
|
+
return "handoff";
|
|
1137
|
+
return previous.readyAt === null ? "startup-failed" : "abnormal";
|
|
1138
|
+
}
|
|
1139
|
+
function closeAbandoned(candidate, previous, previousExit, run, overlap) {
|
|
1140
|
+
if (!isOpenRun(candidate))
|
|
1141
|
+
return candidate;
|
|
1142
|
+
const closed = { ...candidate, stoppedAt: run.startedAt };
|
|
1143
|
+
if (candidate.pid === run.pid)
|
|
1144
|
+
return { ...closed, termination: "hot-reload" };
|
|
1145
|
+
if (overlap === "handoff")
|
|
1146
|
+
return candidate;
|
|
1147
|
+
if (candidate.runId === previous?.runId && previousExit === "handoff")
|
|
1148
|
+
return candidate;
|
|
1149
|
+
return {
|
|
1150
|
+
...closed,
|
|
1151
|
+
termination: candidate.readyAt === null ? "startup-failed" : "abnormal"
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1116
1154
|
function transitionProcessStart(source, input) {
|
|
1117
|
-
const retain =
|
|
1118
|
-
const
|
|
1155
|
+
const retain = RetainSchema.parse(input.retain ?? 20);
|
|
1156
|
+
const overlap = input.sameVersionOverlap ?? "abnormal";
|
|
1157
|
+
const state = normalizeLifecycleState(source, 1000);
|
|
1119
1158
|
const run = LifecycleRunSchema.parse({
|
|
1120
1159
|
runId: input.runId,
|
|
1121
1160
|
pid: input.pid,
|
|
1122
1161
|
version: input.version,
|
|
1123
1162
|
startedAt: input.now,
|
|
1124
1163
|
readyAt: null,
|
|
1164
|
+
unavailableAt: null,
|
|
1125
1165
|
stoppedAt: null,
|
|
1126
1166
|
termination: "active"
|
|
1127
1167
|
});
|
|
@@ -1129,31 +1169,10 @@ function transitionProcessStart(source, input) {
|
|
|
1129
1169
|
throw new Error(`[stitchkit] lifecycle run id already exists: ${run.runId}`);
|
|
1130
1170
|
}
|
|
1131
1171
|
const previous = state.runs[0] ?? null;
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
downtimeMs = elapsed(run.startedAt, previous.stoppedAt);
|
|
1137
|
-
} else if (previous) {
|
|
1138
|
-
if (previous.pid === run.pid)
|
|
1139
|
-
previousExit = "hot-reload";
|
|
1140
|
-
else if (isVersionChange(previous.version, run.version))
|
|
1141
|
-
previousExit = "handoff";
|
|
1142
|
-
else
|
|
1143
|
-
previousExit = input.sameVersionOverlap ?? "abnormal";
|
|
1144
|
-
}
|
|
1145
|
-
const runs = state.runs.map((candidate) => {
|
|
1146
|
-
if (candidate.runId !== previous?.runId || candidate.termination !== "active")
|
|
1147
|
-
return candidate;
|
|
1148
|
-
if (previousExit === "hot-reload") {
|
|
1149
|
-
return { ...candidate, stoppedAt: run.startedAt, termination: "hot-reload" };
|
|
1150
|
-
}
|
|
1151
|
-
if (previousExit === "abnormal") {
|
|
1152
|
-
return { ...candidate, stoppedAt: run.startedAt, termination: "abnormal" };
|
|
1153
|
-
}
|
|
1154
|
-
return candidate;
|
|
1155
|
-
});
|
|
1156
|
-
const next = normalize({ schemaVersion: 1, runs: [run, ...runs] }, retain);
|
|
1172
|
+
const previousExit = previousExitOf(previous, run, overlap);
|
|
1173
|
+
const processGapMs = previous && !isOpenRun(previous) && previous.stoppedAt ? elapsed(run.startedAt, previous.stoppedAt) : null;
|
|
1174
|
+
const runs = state.runs.map((candidate) => closeAbandoned(candidate, previous, previousExit, run, overlap));
|
|
1175
|
+
const next = normalizeLifecycleState({ schemaVersion: 1, runs: [run, ...runs] }, retain);
|
|
1157
1176
|
return {
|
|
1158
1177
|
state: next,
|
|
1159
1178
|
fact: {
|
|
@@ -1167,15 +1186,30 @@ function transitionProcessStart(source, input) {
|
|
|
1167
1186
|
previousPid: previous?.pid ?? null,
|
|
1168
1187
|
previousVersion: previous?.version ?? null,
|
|
1169
1188
|
versionChanged: previous !== null && isVersionChange(previous.version, run.version),
|
|
1170
|
-
|
|
1189
|
+
processGapMs
|
|
1171
1190
|
}
|
|
1172
1191
|
};
|
|
1173
1192
|
}
|
|
1193
|
+
function findOpen(state, input) {
|
|
1194
|
+
return state.runs.find((run) => run.runId === input.runId && run.pid === input.pid && isOpenRun(run));
|
|
1195
|
+
}
|
|
1196
|
+
function unavailability(state, target, readyAt) {
|
|
1197
|
+
const older = state.runs.slice(state.runs.indexOf(target) + 1);
|
|
1198
|
+
const served = older.find((run) => run.readyAt !== null);
|
|
1199
|
+
if (!served)
|
|
1200
|
+
return { downtimeMs: null, unavailableSince: null };
|
|
1201
|
+
if (served.unavailableAt !== null) {
|
|
1202
|
+
return {
|
|
1203
|
+
downtimeMs: elapsed(readyAt, served.unavailableAt),
|
|
1204
|
+
unavailableSince: served.unavailableAt
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
return isOpenRun(served) ? { downtimeMs: 0, unavailableSince: null } : { downtimeMs: null, unavailableSince: null };
|
|
1208
|
+
}
|
|
1174
1209
|
function transitionProcessReady(source, input) {
|
|
1175
|
-
const
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
if (!target) {
|
|
1210
|
+
const state = normalizeLifecycleState(source, input.retain ?? 20);
|
|
1211
|
+
const target = findOpen(state, input);
|
|
1212
|
+
if (target?.termination !== "active") {
|
|
1179
1213
|
return {
|
|
1180
1214
|
state,
|
|
1181
1215
|
fact: {
|
|
@@ -1184,6 +1218,8 @@ function transitionProcessReady(source, input) {
|
|
|
1184
1218
|
pid: input.pid,
|
|
1185
1219
|
readyAt: input.now,
|
|
1186
1220
|
startupMs: 0,
|
|
1221
|
+
downtimeMs: null,
|
|
1222
|
+
unavailableSince: null,
|
|
1187
1223
|
recorded: false
|
|
1188
1224
|
}
|
|
1189
1225
|
};
|
|
@@ -1200,14 +1236,45 @@ function transitionProcessReady(source, input) {
|
|
|
1200
1236
|
pid: target.pid,
|
|
1201
1237
|
readyAt,
|
|
1202
1238
|
startupMs: elapsed(readyAt, target.startedAt),
|
|
1239
|
+
...unavailability(state, target, readyAt),
|
|
1203
1240
|
recorded: target.readyAt === null
|
|
1204
1241
|
}
|
|
1205
1242
|
};
|
|
1206
1243
|
}
|
|
1244
|
+
function transitionProcessDraining(source, input) {
|
|
1245
|
+
const state = normalizeLifecycleState(source, input.retain ?? 20);
|
|
1246
|
+
const target = findOpen(state, input);
|
|
1247
|
+
if (target?.termination !== "active") {
|
|
1248
|
+
return {
|
|
1249
|
+
state,
|
|
1250
|
+
fact: {
|
|
1251
|
+
type: "draining",
|
|
1252
|
+
runId: input.runId,
|
|
1253
|
+
pid: input.pid,
|
|
1254
|
+
unavailableAt: target ? target.unavailableAt : null,
|
|
1255
|
+
recorded: false
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
const unavailableAt = target.readyAt === null ? null : input.now;
|
|
1260
|
+
return {
|
|
1261
|
+
state: {
|
|
1262
|
+
schemaVersion: 1,
|
|
1263
|
+
runs: state.runs.map((run) => run.runId === target.runId ? { ...run, termination: "draining", unavailableAt } : run)
|
|
1264
|
+
},
|
|
1265
|
+
fact: {
|
|
1266
|
+
type: "draining",
|
|
1267
|
+
runId: target.runId,
|
|
1268
|
+
pid: target.pid,
|
|
1269
|
+
unavailableAt,
|
|
1270
|
+
recorded: true
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1207
1274
|
function transitionProcessShutdown(source, input) {
|
|
1208
|
-
const state =
|
|
1209
|
-
const target = state
|
|
1210
|
-
const
|
|
1275
|
+
const state = normalizeLifecycleState(source, input.retain ?? 20);
|
|
1276
|
+
const target = findOpen(state, input);
|
|
1277
|
+
const requested = input.forced ? "forced" : "clean";
|
|
1211
1278
|
if (!target) {
|
|
1212
1279
|
return {
|
|
1213
1280
|
state,
|
|
@@ -1217,15 +1284,17 @@ function transitionProcessShutdown(source, input) {
|
|
|
1217
1284
|
pid: input.pid,
|
|
1218
1285
|
stoppedAt: input.now,
|
|
1219
1286
|
uptimeMs: null,
|
|
1220
|
-
termination,
|
|
1287
|
+
termination: requested,
|
|
1221
1288
|
recorded: false
|
|
1222
1289
|
}
|
|
1223
1290
|
};
|
|
1224
1291
|
}
|
|
1292
|
+
const termination = target.readyAt === null ? "startup-failed" : requested;
|
|
1293
|
+
const unavailableAt = target.unavailableAt ?? (target.readyAt === null ? null : input.now);
|
|
1225
1294
|
return {
|
|
1226
1295
|
state: {
|
|
1227
1296
|
schemaVersion: 1,
|
|
1228
|
-
runs: state.runs.map((run) => run.runId === target.runId ? { ...run, stoppedAt: input.now, termination } : run)
|
|
1297
|
+
runs: state.runs.map((run) => run.runId === target.runId ? { ...run, unavailableAt, stoppedAt: input.now, termination } : run)
|
|
1229
1298
|
},
|
|
1230
1299
|
fact: {
|
|
1231
1300
|
type: "stopped",
|
|
@@ -1238,10 +1307,12 @@ function transitionProcessShutdown(source, input) {
|
|
|
1238
1307
|
}
|
|
1239
1308
|
};
|
|
1240
1309
|
}
|
|
1310
|
+
|
|
1311
|
+
// src/application/process-lifecycle.ts
|
|
1241
1312
|
function createProcessLifecycleLedger(config) {
|
|
1242
1313
|
const clock = config.clock ?? (() => new Date);
|
|
1243
|
-
const pid =
|
|
1244
|
-
const retain =
|
|
1314
|
+
const pid = z7.number().int().positive().parse(config.pid ?? process.pid);
|
|
1315
|
+
const retain = z7.number().int().min(1).max(1000).parse(config.retain ?? 20);
|
|
1245
1316
|
const configuredRunId = config.runId;
|
|
1246
1317
|
const nextRunId = typeof configuredRunId === "function" ? configuredRunId : configuredRunId === undefined ? () => crypto.randomUUID() : () => configuredRunId;
|
|
1247
1318
|
let runId = nextRunId();
|
|
@@ -1285,6 +1356,20 @@ function createProcessLifecycleLedger(config) {
|
|
|
1285
1356
|
publish(fact);
|
|
1286
1357
|
return fact;
|
|
1287
1358
|
},
|
|
1359
|
+
async recordDraining() {
|
|
1360
|
+
const fact = await config.store.update((state) => {
|
|
1361
|
+
const transition = transitionProcessDraining(state, {
|
|
1362
|
+
runId,
|
|
1363
|
+
pid,
|
|
1364
|
+
now: clock().toISOString(),
|
|
1365
|
+
retain
|
|
1366
|
+
});
|
|
1367
|
+
return { state: transition.state, result: transition.fact };
|
|
1368
|
+
});
|
|
1369
|
+
if (fact.recorded)
|
|
1370
|
+
publish(fact);
|
|
1371
|
+
return fact;
|
|
1372
|
+
},
|
|
1288
1373
|
async recordShutdown(input) {
|
|
1289
1374
|
const fact = await config.store.update((state) => {
|
|
1290
1375
|
const transition = transitionProcessShutdown(state, {
|
|
@@ -1301,11 +1386,11 @@ function createProcessLifecycleLedger(config) {
|
|
|
1301
1386
|
return fact;
|
|
1302
1387
|
},
|
|
1303
1388
|
async current() {
|
|
1304
|
-
const state =
|
|
1389
|
+
const state = normalizeLifecycleState(await config.store.read(), retain);
|
|
1305
1390
|
return state.runs.find((run) => run.runId === runId && run.pid === pid) ?? null;
|
|
1306
1391
|
},
|
|
1307
1392
|
async runs() {
|
|
1308
|
-
return
|
|
1393
|
+
return normalizeLifecycleState(await config.store.read(), retain).runs;
|
|
1309
1394
|
},
|
|
1310
1395
|
subscribe(listener) {
|
|
1311
1396
|
listeners.add(listener);
|
|
@@ -1340,6 +1425,9 @@ function lifecycleLedgerResource(ledger, config) {
|
|
|
1340
1425
|
async activate() {
|
|
1341
1426
|
await ledger.recordReady();
|
|
1342
1427
|
},
|
|
1428
|
+
async stopAdmission() {
|
|
1429
|
+
await ledger.recordDraining();
|
|
1430
|
+
},
|
|
1343
1431
|
async close() {
|
|
1344
1432
|
await stop(false);
|
|
1345
1433
|
},
|
|
@@ -1349,27 +1437,27 @@ function lifecycleLedgerResource(ledger, config) {
|
|
|
1349
1437
|
});
|
|
1350
1438
|
}
|
|
1351
1439
|
// src/application/revision-signal.ts
|
|
1352
|
-
import { z as
|
|
1353
|
-
var NonNegativeSafeIntegerSchema =
|
|
1354
|
-
var PositiveSafeIntegerSchema2 =
|
|
1355
|
-
var TimerDelaySchema =
|
|
1356
|
-
var RevisionSignalStateSchema =
|
|
1357
|
-
var RevisionSignalWaitOutcomeSchema =
|
|
1440
|
+
import { z as z8 } from "zod";
|
|
1441
|
+
var NonNegativeSafeIntegerSchema = z8.number().int().nonnegative().safe();
|
|
1442
|
+
var PositiveSafeIntegerSchema2 = z8.number().int().positive().safe();
|
|
1443
|
+
var TimerDelaySchema = z8.number().int().positive().max(2147483647);
|
|
1444
|
+
var RevisionSignalStateSchema = z8.enum(["open", "closed"]);
|
|
1445
|
+
var RevisionSignalWaitOutcomeSchema = z8.enum([
|
|
1358
1446
|
"changed",
|
|
1359
1447
|
"timed-out",
|
|
1360
1448
|
"aborted",
|
|
1361
1449
|
"closed",
|
|
1362
1450
|
"capacity"
|
|
1363
1451
|
]);
|
|
1364
|
-
var RevisionSignalWaitResultSchema =
|
|
1452
|
+
var RevisionSignalWaitResultSchema = z8.object({
|
|
1365
1453
|
outcome: RevisionSignalWaitOutcomeSchema,
|
|
1366
1454
|
revision: NonNegativeSafeIntegerSchema
|
|
1367
1455
|
}).strict().readonly();
|
|
1368
|
-
var RevisionSignalAdvanceResultSchema =
|
|
1369
|
-
outcome:
|
|
1456
|
+
var RevisionSignalAdvanceResultSchema = z8.object({
|
|
1457
|
+
outcome: z8.enum(["advanced", "closed"]),
|
|
1370
1458
|
revision: NonNegativeSafeIntegerSchema
|
|
1371
1459
|
}).strict().readonly();
|
|
1372
|
-
var RevisionSignalSnapshotSchema =
|
|
1460
|
+
var RevisionSignalSnapshotSchema = z8.object({
|
|
1373
1461
|
state: RevisionSignalStateSchema,
|
|
1374
1462
|
revision: NonNegativeSafeIntegerSchema,
|
|
1375
1463
|
pending: NonNegativeSafeIntegerSchema,
|
|
@@ -1919,6 +2007,7 @@ export {
|
|
|
1919
2007
|
transitionProcessStart,
|
|
1920
2008
|
transitionProcessShutdown,
|
|
1921
2009
|
transitionProcessReady,
|
|
2010
|
+
transitionProcessDraining,
|
|
1922
2011
|
sqliteKeyspaceBackend,
|
|
1923
2012
|
readDiagnosticJournalLockDiagnosis,
|
|
1924
2013
|
projectApplicationStatus,
|
|
@@ -1775,6 +1775,27 @@ function markProviderOrigin(error) {
|
|
|
1775
1775
|
function hasProviderOrigin(error) {
|
|
1776
1776
|
return typeof error === "object" && error !== null && providerOrigin.has(error);
|
|
1777
1777
|
}
|
|
1778
|
+
function markProviderStream(stream) {
|
|
1779
|
+
const reader = stream.getReader();
|
|
1780
|
+
return new ReadableStream({
|
|
1781
|
+
async pull(controller) {
|
|
1782
|
+
let read;
|
|
1783
|
+
try {
|
|
1784
|
+
read = await reader.read();
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
controller.error(isOwnInputRefusal(error) ? error : markProviderOrigin(error));
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
if (read.done)
|
|
1790
|
+
controller.close();
|
|
1791
|
+
else
|
|
1792
|
+
controller.enqueue(read.value);
|
|
1793
|
+
},
|
|
1794
|
+
cancel(reason) {
|
|
1795
|
+
return reader.cancel(reason);
|
|
1796
|
+
}
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1778
1799
|
|
|
1779
1800
|
// src/agent-runtime/run-operation-lifecycle.ts
|
|
1780
1801
|
function createAgentRunOperationLifecycle(config) {
|
|
@@ -1840,7 +1861,8 @@ function createAgentRunOperationLifecycle(config) {
|
|
|
1840
1861
|
}
|
|
1841
1862
|
await startModelRequest(callId, step);
|
|
1842
1863
|
try {
|
|
1843
|
-
|
|
1864
|
+
const result = await doStream();
|
|
1865
|
+
return { ...result, stream: markProviderStream(result.stream) };
|
|
1844
1866
|
} catch (error) {
|
|
1845
1867
|
throw isOwnInputRefusal(error) ? error : markProviderOrigin(error);
|
|
1846
1868
|
}
|
package/llms/application.2.txt
CHANGED
|
@@ -290,11 +290,11 @@ cutovers are covered by the executable
|
|
|
290
290
|
| `createApplication` | function | compose a validated resource DAG into one startup, readiness, admission and shutdown state machine |
|
|
291
291
|
| `StateStore` / `StateStoreUpdate` | _type_ | async atomic read/update boundary shared by durable application state machines |
|
|
292
292
|
| `createProcessLifecycleLedger` / `ProcessLifecycleLedger` / `ProcessLifecycleLedgerConfig` | function / _type_ | durable bounded run history and typed fact subscription |
|
|
293
|
-
| `LifecycleRunSchema` / `LifecycleRun` / `LifecycleStateSchema` / `LifecycleState` / `LifecycleTerminationSchema` / `LifecycleTermination` | schema / _type_ | versioned process-run state and
|
|
294
|
-
| `PreviousExitSchema` / `PreviousExit` / `StartFact` / `ReadyFact` / `ShutdownFact` / `ProcessLifecycleFact` | schema / _type_ | first-boot, hot-reload, clean, forced, handoff and abnormal lifecycle facts |
|
|
295
|
-
| `transitionProcessStart` / `transitionProcessReady` / `transitionProcessShutdown` | function | pure idempotent runId+pid-owned transitions |
|
|
296
|
-
| `LifecycleTransition` / `TransitionStartInput` / `
|
|
297
|
-
| `lifecycleLedgerResource` / `LifecycleLedgerResource` / `LifecycleLedgerResourceConfig` | function / _type_ | managed-resource adapter that records start, readiness and shutdown |
|
|
293
|
+
| `LifecycleRunSchema` / `LifecycleRun` / `LifecycleStateSchema` / `LifecycleState` / `LifecycleTerminationSchema` / `LifecycleTermination` | schema / _type_ | versioned process-run state — open (`active`, `draining` with `unavailableAt`) and ended (`clean`, `forced`, `startup-failed`, `hot-reload`, `abnormal`) |
|
|
294
|
+
| `PreviousExitSchema` / `PreviousExit` / `StartFact` / `ReadyFact` / `DrainingFact` / `ShutdownFact` / `ProcessLifecycleFact` | schema / _type_ | first-boot, hot-reload, clean, forced, startup-failed, handoff and abnormal lifecycle facts; `processGapMs` on start, `downtimeMs` (unavailable → ready) on ready |
|
|
295
|
+
| `transitionProcessStart` / `transitionProcessReady` / `transitionProcessDraining` / `transitionProcessShutdown` | function | pure idempotent runId+pid-owned transitions |
|
|
296
|
+
| `LifecycleTransition` / `TransitionStartInput` / `TransitionRunInput` / `TransitionShutdownInput` / `SameVersionOverlap` | _type_ | pure transition inputs (`TransitionRunInput` for ready and draining, extended with `forced` for shutdown), the same-build overlap policy (`abnormal` default / `handoff`) and state+fact result |
|
|
297
|
+
| `lifecycleLedgerResource` / `LifecycleLedgerResource` / `LifecycleLedgerResourceConfig` | function / _type_ | managed-resource adapter that records start, readiness, admission stop (draining) and shutdown |
|
|
298
298
|
| `createNotificationOutbox` / `NotificationOutbox` / `NotificationOutboxConfig` | function / _type_ | bounded at-least-once queue with durable claims, leases, retries and supersede |
|
|
299
299
|
| `NotificationOutboxItem` / `NotificationOutboxReceipt` / `NotificationOutboxState` / `NotificationSend` / `NotificationFailureClassification` / `DroppedNotification` / `EnqueueNotification` | _type_ | versioned queue records, stable send identity and delivery decisions |
|
|
300
300
|
| `notificationOutboxStateSchema` | function | strict persisted-state schema over an application payload schema |
|
package/llms/application.txt
CHANGED
|
@@ -815,39 +815,74 @@ application-owned.
|
|
|
815
815
|
## Durable process facts and owner notifications
|
|
816
816
|
|
|
817
817
|
`createProcessLifecycleLedger` records a bounded versioned list of process runs.
|
|
818
|
-
Start, readiness and shutdown target both `runId` and `pid`, so hot
|
|
819
|
-
PID reuse cannot close the wrong generation.
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
the
|
|
818
|
+
Start, readiness, draining and shutdown target both `runId` and `pid`, so hot
|
|
819
|
+
reload and PID reuse cannot close the wrong generation. `lifecycleLedgerResource`
|
|
820
|
+
drives it from the kernel's phases: `start` records the start, `activate` the
|
|
821
|
+
readiness, `stopAdmission` the drain — the run's `unavailableAt`, the moment it
|
|
822
|
+
stops answering new work — and `close` / `force` the stop. A run that stops
|
|
823
|
+
without ever becoming ready (a failed startup rolls back with `close` only)
|
|
824
|
+
ends as `startup-failed`, not `clean`.
|
|
825
|
+
|
|
826
|
+
A start classifies what happened to the newest run before it, and the
|
|
827
|
+
classification is decided by four facts — whether that run recorded its own
|
|
828
|
+
exit, whether the pid is the same, whether the version changed and whether it
|
|
829
|
+
ever became ready:
|
|
823
830
|
|
|
824
831
|
| newest run | same pid | version | `previousExit` | predecessor's `termination` |
|
|
825
832
|
|---|---|---|---|---|
|
|
826
833
|
| none | — | — | `first-boot` | — |
|
|
827
|
-
| recorded `stoppedAt` | — | — | `clean` / `forced` / `abnormal` as recorded | unchanged |
|
|
828
|
-
| still
|
|
829
|
-
| still
|
|
830
|
-
| still
|
|
834
|
+
| recorded `stoppedAt` | — | — | `clean` / `forced` / `startup-failed` / `abnormal` as recorded | unchanged |
|
|
835
|
+
| still open | yes | — | `hot-reload` | `hot-reload`, closed at the new start |
|
|
836
|
+
| still open | no | changed | `handoff` | stays open; it records its own stop later |
|
|
837
|
+
| still open, was ready | no | same | `abnormal` (default) | `abnormal`, closed at the new start — an upper bound, the crash time is unknown |
|
|
838
|
+
| still open, never ready | no | same | `startup-failed` (default) | `startup-failed`, closed at the new start |
|
|
839
|
+
|
|
840
|
+
Every other open run the start finds was abandoned too and is closed the same
|
|
841
|
+
way — two crashes in a row leave two open runs, and both are closed, not only
|
|
842
|
+
the newest. Open means `active` or `draining`.
|
|
831
843
|
|
|
832
844
|
A version of `unknown` on either side is never a version change, so a dev build
|
|
833
845
|
after a crashed release reads `abnormal`, not `handoff`. `forced` means the
|
|
834
846
|
process itself acknowledged a kill; `abnormal` means a successor found it dead.
|
|
835
847
|
|
|
836
|
-
|
|
848
|
+
### Downtime is the window nobody answered in
|
|
849
|
+
|
|
850
|
+
`ReadyFact.downtimeMs` is `readyAt` of the new run minus `unavailableAt` of the
|
|
851
|
+
last run that served — the predecessor's drain plus the successor's boot. A
|
|
852
|
+
110 s forced drain followed by a 4 s boot is 114 s of downtime; the gap between
|
|
853
|
+
the two processes alone would read 4 s before and after that defect was fixed.
|
|
854
|
+
Runs that never became ready answered nobody, so the count passes them: after a
|
|
855
|
+
failed start it still opens where the last serving run stopped answering. It is
|
|
856
|
+
`0` when that run still answers (a handoff whose predecessor has not drained
|
|
857
|
+
yet) and `null` on first boot and when the end was never timed — a crash or a
|
|
858
|
+
hot reload records no `unavailableAt`. `unavailableSince` names the moment it is
|
|
859
|
+
counted from. The gap between two processes is still there, under its own
|
|
860
|
+
name: `StartFact.processGapMs` is the start minus the predecessor's recorded
|
|
861
|
+
stop.
|
|
862
|
+
|
|
863
|
+
The ledger records what the process says while it can say it. stitchkit never
|
|
864
|
+
calls `process.exit` (ADR 0074), so a stop is recorded on the kernel's `close`
|
|
865
|
+
or `force` path, both awaited. An application that exits the process on its
|
|
866
|
+
own before its shutdown settles loses that last write; the successor then
|
|
867
|
+
finds the run open and closes it as `abnormal`, keeping the `unavailableAt`
|
|
868
|
+
already recorded — which is why the drain moment is written first, at
|
|
869
|
+
`stopAdmission`, and the downtime survives a stop that was never recorded.
|
|
870
|
+
|
|
871
|
+
The `abnormal` default is a choice, and it is the single-process deployment:
|
|
837
872
|
one process per build, a new pid of the same build means the old one stopped
|
|
838
|
-
answering. Where
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
873
|
+
answering. Where processes of **one** build overlap on purpose — a cluster, a
|
|
874
|
+
zero-downtime reload of the same build — pass `sameVersionOverlap: 'handoff'`
|
|
875
|
+
to the ledger, and every open run stays open until it records its own
|
|
876
|
+
shutdown. The cost of that setting is symmetric: a real crash under it is
|
|
877
|
+
reported as a handoff and the dead run stays open in the ledger until
|
|
878
|
+
retention drops it. The list is kept in the order the transitions wrote it —
|
|
879
|
+
every write goes through one atomic update, so that order is the causal one,
|
|
880
|
+
and a successor whose clock lags its predecessor still finds it at the head;
|
|
881
|
+
`startedAt` is data, not the sort key. Retention (`retain`, default 20) drops
|
|
882
|
+
finished runs first and an open one — a live handoff predecessor — only when
|
|
883
|
+
nothing finished is left. Facts are published through the ledger's own
|
|
884
|
+
subscription and resource value; `ApplicationEventSink` remains the strict
|
|
885
|
+
application-state stream.
|
|
851
886
|
|
|
852
887
|
`createNotificationOutbox` is the transport-neutral durable delivery side. It
|
|
853
888
|
persists before send, claims an item with an expiring lease, carries one stable
|
package/llms/stitchkit.txt
CHANGED
|
@@ -76,11 +76,11 @@ own, recorded as an ADR.
|
|
|
76
76
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
77
77
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
78
78
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
79
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
79
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 40 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
80
80
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
81
81
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
82
82
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
83
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 21 of the
|
|
83
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 21 of the 40 minors since 0.56.2, most recently 0.94.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
84
84
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
85
85
|
| `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit |
|
|
86
86
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -90,7 +90,7 @@ own, recorded as an ADR.
|
|
|
90
90
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
91
91
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
92
92
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
93
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in
|
|
93
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 8 of the 40 minors since 0.56.2, most recently 0.95.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
94
94
|
| `stitchkit/application/grammy` | server | evolving | isolated grammY polling and webhook lifecycle adapters |
|
|
95
95
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
96
96
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
@@ -1,14 +1,36 @@
|
|
|
1
|
-
# Upgrading 0.37.0 → 0.
|
|
1
|
+
# Upgrading 0.37.0 → 0.53.0 — stitchkit docs slice
|
|
2
2
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: Guide: Upgrading, 0.37.0 → 0.
|
|
6
|
+
Contains: Guide: Upgrading, 0.37.0 → 0.53.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.37.0 → 0.
|
|
9
|
+
# Guide: Upgrading, 0.37.0 → 0.53.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.53.0
|
|
13
|
+
|
|
14
|
+
### Realtime `emit` returns `boolean` instead of `void`
|
|
15
|
+
|
|
16
|
+
Every **call site** compiles and behaves exactly as before — the return value
|
|
17
|
+
is new information (`true` = accepted by the transport, `false` = dropped
|
|
18
|
+
while the browser client was disconnected), not a behavior change. What breaks
|
|
19
|
+
is **implementing** the interfaces: a test mock or app-side adapter of
|
|
20
|
+
`SocketIOClient` / `RealtimeClient` / `ValidatedRealtimeSocket` /
|
|
21
|
+
`RealtimeServer` whose `emit` returns `void` no longer typechecks.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// before — a void mock satisfied the interface
|
|
25
|
+
const mock: Pick<RealtimeClient<S, C>, 'emit'> = { emit: () => {} }
|
|
26
|
+
// after — report acceptance (true is what a live server-side emit reports)
|
|
27
|
+
const mock: Pick<RealtimeClient<S, C>, 'emit'> = { emit: () => true }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
While migrating, consider replacing hand-rolled `if (client.connected)` guards
|
|
31
|
+
with the new honest surface: check `client.emit(...) === false`, or observe
|
|
32
|
+
drops centrally with `onDroppedEmit`.
|
|
33
|
+
|
|
12
34
|
## Released migration: 0.50.0
|
|
13
35
|
|
|
14
36
|
### The factory's scope union now covers per-endpoint overrides
|