sentinelayer-cli 0.46.5 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -3
- package/package.json +12 -7
- package/skills/omar-gate-setup/SKILL.md +103 -0
- package/skills/senti-agent-identity/SKILL.md +80 -0
- package/skills/senti-judge/SKILL.md +139 -0
- package/skills/senti-room-notifications/SKILL.md +73 -0
- package/skills/senti-room-notifications/listen-wrapper.cjs +150 -0
- package/skills/senti-room-notifications/package.json +1 -0
- package/skills/senti-room-notifications/test-classifier.js +109 -0
- package/skills/senti-room-notifications/test-receipt.js +54 -0
- package/skills/sentinelayer-cli/SKILL.md +222 -0
- package/src/agents/devtestbot/runner.js +22 -11
- package/src/agents/devtestbot/tool.js +24 -11
- package/src/agents/jules/fix-cycle.js +7 -1
- package/src/agents/jules/tools/runtime-audit.js +17 -12
- package/src/agents/shared-tools/dispatch-core.js +10 -5
- package/src/ai/aidenid.js +4 -2
- package/src/ai/domain-target-store.js +11 -5
- package/src/ai/identity-store.js +11 -5
- package/src/ai/site-store.js +8 -4
- package/src/audit/orchestrator.js +21 -14
- package/src/audit/package.js +6 -4
- package/src/audit/persona-loop.js +7 -0
- package/src/audit/replay.js +4 -2
- package/src/auth/gate.js +32 -1
- package/src/auth/session-store.js +37 -0
- package/src/board/evidence-resolvers.js +3 -4
- package/src/cli.js +23 -3
- package/src/commands/ai/identity-lifecycle.js +30 -26
- package/src/commands/ai/provision-governance.js +32 -24
- package/src/commands/ai/shared.js +6 -4
- package/src/commands/audit.js +14 -12
- package/src/commands/board.js +2 -2
- package/src/commands/chat.js +8 -6
- package/src/commands/judge.js +125 -0
- package/src/commands/legacy-args.js +1 -0
- package/src/commands/mcp.js +45 -52
- package/src/commands/omargate.js +2 -1
- package/src/commands/plugin.js +11 -3
- package/src/commands/review.js +9 -4
- package/src/commands/scan.js +7 -7
- package/src/commands/session.js +516 -30
- package/src/commands/skills.js +45 -0
- package/src/commands/watch.js +9 -7
- package/src/config/output-filesystem.js +156 -0
- package/src/config/schema.js +4 -2
- package/src/config/service.js +40 -4
- package/src/cost/history.js +15 -9
- package/src/daemon/artifact-lineage.js +15 -12
- package/src/daemon/assignment-ledger.js +31 -25
- package/src/daemon/ast-drift.js +7 -3
- package/src/daemon/budget-governor.js +26 -20
- package/src/daemon/error-worker.js +28 -22
- package/src/daemon/fix-cycle.js +5 -4
- package/src/daemon/hybrid-mapper.js +19 -16
- package/src/daemon/ingest-refresh.js +4 -0
- package/src/daemon/jira-lifecycle.js +21 -17
- package/src/daemon/operator-control.js +18 -15
- package/src/daemon/reliability-lane.js +18 -15
- package/src/daemon/scope-engine.js +12 -8
- package/src/daemon/watchdog.js +15 -12
- package/src/engram/build-state.js +24 -3
- package/src/engram/capability-index.js +367 -0
- package/src/engram/compile-graph.js +1063 -0
- package/src/engram/contracts/action-receipt.js +82 -0
- package/src/engram/contracts/capability-index.js +259 -0
- package/src/engram/contracts/capability.js +377 -0
- package/src/engram/contracts/content-hash.js +8 -0
- package/src/engram/contracts/evidence.js +258 -0
- package/src/engram/contracts/graph.js +594 -0
- package/src/engram/contracts/identity.js +8 -0
- package/src/engram/contracts/index.js +149 -0
- package/src/engram/contracts/media-asset.js +85 -0
- package/src/engram/contracts/money.js +249 -0
- package/src/engram/contracts/source-snapshot.js +57 -0
- package/src/engram/contracts/task-context-pack.js +114 -0
- package/src/engram/contracts/temporal-segment.js +72 -0
- package/src/engram/contracts/versions.js +96 -0
- package/src/engram/extract-html.js +692 -0
- package/src/engram/graph-store.js +877 -0
- package/src/engram/index.js +98 -14
- package/src/engram/ingest-site.js +132 -0
- package/src/engram/live-state.js +1180 -0
- package/src/engram/namespace.js +34 -1
- package/src/engram/retrieve-site.js +753 -0
- package/src/engram/safe-reader.js +597 -0
- package/src/engram/source-intake.js +251 -0
- package/src/engram/store.js +227 -9
- package/src/ingest/engine.js +21 -28
- package/src/judge/verdict.js +305 -0
- package/src/legacy-cli.js +96 -19
- package/src/mcp/bridge-inputs.js +25 -4
- package/src/mcp/cli-command-tools.js +70 -0
- package/src/mcp/registry.js +17 -13
- package/src/mcp/session-stdio-server.js +297 -19
- package/src/memory/blackboard.js +5 -4
- package/src/net/gh-api-path.js +35 -9
- package/src/net/test-egress-guard.js +16 -4
- package/src/plugin/manifest.js +12 -8
- package/src/review/ai-review.js +110 -10
- package/src/review/investor-dd-devtestbot.js +17 -6
- package/src/review/investor-dd-orchestrator.js +21 -13
- package/src/review/local-review.js +26 -16
- package/src/review/omargate-cache.js +5 -5
- package/src/review/omargate-orchestrator.js +89 -17
- package/src/review/replay.js +9 -4
- package/src/review/report.js +22 -13
- package/src/review/typesafe-severity.js +201 -0
- package/src/session/admission-auth.js +34 -7
- package/src/session/admission.js +110 -15
- package/src/session/attachment-summary.js +77 -0
- package/src/session/edit-summary.js +19 -0
- package/src/session/invitations.js +65 -1
- package/src/session/mentions.js +17 -9
- package/src/session/message-edits.js +5 -4
- package/src/session/preview.js +10 -2
- package/src/session/recap.js +3 -2
- package/src/session/room-files.js +519 -0
- package/src/session/route-classes.js +22 -8
- package/src/session/setup-guides.js +4 -0
- package/src/session/standup.js +192 -0
- package/src/session/sync.js +229 -10
- package/src/session/tickets.js +41 -0
- package/src/session/transcript.js +2 -1
- package/src/session/wake/resolve-target.js +7 -3
- package/src/skills/listener-runtime.cjs +92 -0
- package/src/skills/service.js +207 -0
- package/src/swarm/factory.js +5 -5
- package/src/swarm/pentest.js +9 -9
- package/src/swarm/report.js +4 -4
- package/src/swarm/runtime.js +15 -12
- package/src/swarm/scenario-dsl.js +7 -5
- package/src/telemetry/ledger.js +16 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fsp from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
import { bindOutputFileSystem, requireOutputFileSystem } from "../config/output-filesystem.js";
|
|
4
5
|
import { ASSIGNMENT_STATUSES, resolveAssignmentLedgerStorage, listAssignments } from "./assignment-ledger.js";
|
|
5
6
|
import { DAEMON_BUDGET_LIFECYCLE_STATES, listBudgetStates } from "./budget-governor.js";
|
|
6
7
|
import { WORK_ITEM_STATUSES, listErrorQueue, resolveErrorDaemonStorage } from "./error-worker.js";
|
|
@@ -82,14 +83,16 @@ function loadJsonFile(filePath, defaultFactory) {
|
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
async function writeJsonFile(filePath, payload = {}) {
|
|
86
|
-
|
|
87
|
-
await
|
|
86
|
+
async function writeJsonFile(filePath, payload = {}, outputFs) {
|
|
87
|
+
requireOutputFileSystem(outputFs);
|
|
88
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
89
|
+
await outputFs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8");
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
async function appendJsonLine(filePath, payload = {}) {
|
|
91
|
-
|
|
92
|
-
await
|
|
92
|
+
async function appendJsonLine(filePath, payload = {}, outputFs) {
|
|
93
|
+
requireOutputFileSystem(outputFs);
|
|
94
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
95
|
+
await outputFs.appendFile(filePath, `${JSON.stringify(payload)}\n`, "utf-8");
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
function resolveBudgetHealthColor(budgetLifecycleState = "") {
|
|
@@ -271,12 +274,12 @@ export async function resolveOperatorControlStorage({
|
|
|
271
274
|
env,
|
|
272
275
|
homeDir,
|
|
273
276
|
});
|
|
274
|
-
return {
|
|
277
|
+
return bindOutputFileSystem({
|
|
275
278
|
...daemonStorage,
|
|
276
279
|
operatorStatePath: path.join(daemonStorage.baseDir, "operator-control-state.json"),
|
|
277
280
|
operatorEventsPath: path.join(daemonStorage.baseDir, "operator-events.ndjson"),
|
|
278
281
|
operatorSnapshotsDir: path.join(daemonStorage.baseDir, "operator-snapshots"),
|
|
279
|
-
};
|
|
282
|
+
}, daemonStorage.outputFs);
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
export async function buildOperatorControlSnapshot({
|
|
@@ -427,8 +430,8 @@ export async function buildOperatorControlSnapshot({
|
|
|
427
430
|
workItems: rows,
|
|
428
431
|
agentRoster,
|
|
429
432
|
};
|
|
430
|
-
await
|
|
431
|
-
await writeJsonFile(runPath, snapshot);
|
|
433
|
+
await storage.outputFs.mkdir(storage.operatorSnapshotsDir, { recursive: true });
|
|
434
|
+
await writeJsonFile(runPath, snapshot, storage.outputFs);
|
|
432
435
|
|
|
433
436
|
const nextControlState = normalizeControlState(
|
|
434
437
|
{
|
|
@@ -442,7 +445,7 @@ export async function buildOperatorControlSnapshot({
|
|
|
442
445
|
normalizedNow
|
|
443
446
|
);
|
|
444
447
|
await Promise.all([
|
|
445
|
-
writeJsonFile(storage.operatorStatePath, nextControlState),
|
|
448
|
+
writeJsonFile(storage.operatorStatePath, nextControlState, storage.outputFs),
|
|
446
449
|
appendJsonLine(storage.operatorEventsPath, {
|
|
447
450
|
timestamp: normalizedNow,
|
|
448
451
|
eventType: "operator_snapshot",
|
|
@@ -452,7 +455,7 @@ export async function buildOperatorControlSnapshot({
|
|
|
452
455
|
activeAgents: snapshot.summary.activeAgents,
|
|
453
456
|
statusCounts: statusSummary.statusCounts,
|
|
454
457
|
healthCounts: statusSummary.healthCounts,
|
|
455
|
-
}),
|
|
458
|
+
}, storage.outputFs),
|
|
456
459
|
]);
|
|
457
460
|
|
|
458
461
|
return {
|
|
@@ -606,8 +609,8 @@ export async function applyOperatorStopControl({
|
|
|
606
609
|
}
|
|
607
610
|
|
|
608
611
|
await Promise.all([
|
|
609
|
-
writeJsonFile(storage.queuePath, queue),
|
|
610
|
-
writeJsonFile(assignmentStorage.ledgerPath, ledger),
|
|
612
|
+
writeJsonFile(storage.queuePath, queue, storage.outputFs),
|
|
613
|
+
writeJsonFile(assignmentStorage.ledgerPath, ledger, assignmentStorage.outputFs),
|
|
611
614
|
appendJsonLine(storage.operatorEventsPath, {
|
|
612
615
|
timestamp: normalizedNow,
|
|
613
616
|
eventType: "operator_stop",
|
|
@@ -618,7 +621,7 @@ export async function applyOperatorStopControl({
|
|
|
618
621
|
reason: normalizedReason,
|
|
619
622
|
jiraIssueKey,
|
|
620
623
|
jiraCommented,
|
|
621
|
-
}),
|
|
624
|
+
}, storage.outputFs),
|
|
622
625
|
]);
|
|
623
626
|
|
|
624
627
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fsp from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
import { bindOutputFileSystem, requireOutputFileSystem } from "../config/output-filesystem.js";
|
|
4
5
|
import { appendAdminErrorEvent, resolveErrorDaemonStorage, runErrorDaemonWorker } from "./error-worker.js";
|
|
5
6
|
|
|
6
7
|
const RELIABILITY_SCHEMA_VERSION = "1.0.0";
|
|
@@ -142,14 +143,16 @@ async function readJsonFile(filePath, defaultFactory) {
|
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
async function writeJsonFile(filePath, payload = {}) {
|
|
146
|
-
|
|
147
|
-
await
|
|
146
|
+
async function writeJsonFile(filePath, payload = {}, outputFs) {
|
|
147
|
+
requireOutputFileSystem(outputFs);
|
|
148
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
149
|
+
await outputFs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8");
|
|
148
150
|
}
|
|
149
151
|
|
|
150
|
-
async function appendJsonLine(filePath, payload = {}) {
|
|
151
|
-
|
|
152
|
-
await
|
|
152
|
+
async function appendJsonLine(filePath, payload = {}, outputFs) {
|
|
153
|
+
requireOutputFileSystem(outputFs);
|
|
154
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
155
|
+
await outputFs.appendFile(filePath, `${JSON.stringify(payload)}\n`, "utf-8");
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
async function listRunArtifacts(runsDir, outputRoot) {
|
|
@@ -197,14 +200,14 @@ export async function resolveReliabilityLaneStorage({
|
|
|
197
200
|
homeDir,
|
|
198
201
|
});
|
|
199
202
|
const reliabilityDir = path.join(daemonStorage.baseDir, "reliability");
|
|
200
|
-
return {
|
|
203
|
+
return bindOutputFileSystem({
|
|
201
204
|
...daemonStorage,
|
|
202
205
|
reliabilityDir,
|
|
203
206
|
configPath: path.join(reliabilityDir, "lane-config.json"),
|
|
204
207
|
billboardPath: path.join(reliabilityDir, "maintenance-billboard.json"),
|
|
205
208
|
eventsPath: path.join(reliabilityDir, "reliability-events.ndjson"),
|
|
206
209
|
runsDir: path.join(reliabilityDir, "runs"),
|
|
207
|
-
};
|
|
210
|
+
}, daemonStorage.outputFs);
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
export async function setMaintenanceBillboard({
|
|
@@ -249,7 +252,7 @@ export async function setMaintenanceBillboard({
|
|
|
249
252
|
};
|
|
250
253
|
|
|
251
254
|
await Promise.all([
|
|
252
|
-
writeJsonFile(storage.billboardPath, next),
|
|
255
|
+
writeJsonFile(storage.billboardPath, next, storage.outputFs),
|
|
253
256
|
appendJsonLine(storage.eventsPath, {
|
|
254
257
|
timestamp: normalizedNow,
|
|
255
258
|
eventType: "maintenance_update",
|
|
@@ -258,7 +261,7 @@ export async function setMaintenanceBillboard({
|
|
|
258
261
|
actor: normalizedActor,
|
|
259
262
|
reason: normalizedReason,
|
|
260
263
|
message: next.message,
|
|
261
|
-
}),
|
|
264
|
+
}, storage.outputFs),
|
|
262
265
|
]);
|
|
263
266
|
|
|
264
267
|
return {
|
|
@@ -439,11 +442,11 @@ export async function runReliabilityLane({
|
|
|
439
442
|
: null,
|
|
440
443
|
};
|
|
441
444
|
|
|
442
|
-
await
|
|
445
|
+
await storage.outputFs.mkdir(storage.runsDir, { recursive: true });
|
|
443
446
|
await Promise.all([
|
|
444
|
-
writeJsonFile(storage.configPath, config),
|
|
445
|
-
writeJsonFile(storage.billboardPath, billboard),
|
|
446
|
-
writeJsonFile(runPath, runPayload),
|
|
447
|
+
writeJsonFile(storage.configPath, config, storage.outputFs),
|
|
448
|
+
writeJsonFile(storage.billboardPath, billboard, storage.outputFs),
|
|
449
|
+
writeJsonFile(runPath, runPayload, storage.outputFs),
|
|
447
450
|
appendJsonLine(storage.eventsPath, {
|
|
448
451
|
timestamp: normalizedNow,
|
|
449
452
|
eventType: "reliability_run",
|
|
@@ -454,7 +457,7 @@ export async function runReliabilityLane({
|
|
|
454
457
|
checkCount: checkResults.length,
|
|
455
458
|
failureCount: failureResults.length,
|
|
456
459
|
maintenanceEnabled: billboard.enabled,
|
|
457
|
-
}),
|
|
460
|
+
}, storage.outputFs),
|
|
458
461
|
]);
|
|
459
462
|
|
|
460
463
|
return {
|
|
@@ -3,7 +3,8 @@ import fsp from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { bindOutputFileSystem, requireOutputFileSystem } from "../config/output-filesystem.js";
|
|
7
|
+
import { resolveOutputContext } from "../config/service.js";
|
|
7
8
|
import { createAgentEvent } from "../events/schema.js";
|
|
8
9
|
import { collectCodebaseIngest } from "../ingest/engine.js";
|
|
9
10
|
import { appendToStream } from "../session/stream.js";
|
|
@@ -707,31 +708,33 @@ export async function resolveScopeEngineStorage({
|
|
|
707
708
|
env,
|
|
708
709
|
homeDir,
|
|
709
710
|
} = {}) {
|
|
710
|
-
const outputRoot = await
|
|
711
|
+
const { outputRoot, outputFs } = await resolveOutputContext({
|
|
711
712
|
cwd: path.resolve(String(targetPath || ".")),
|
|
712
713
|
outputDirOverride: outputDir,
|
|
713
714
|
env,
|
|
714
715
|
homeDir,
|
|
715
716
|
});
|
|
717
|
+
requireOutputFileSystem(outputFs);
|
|
716
718
|
const observabilityRoot = path.join(outputRoot, "observability");
|
|
717
719
|
const baseDir = path.join(observabilityRoot, "scope-engine");
|
|
718
|
-
return {
|
|
720
|
+
return bindOutputFileSystem({
|
|
719
721
|
outputRoot,
|
|
720
722
|
observabilityRoot,
|
|
721
723
|
baseDir,
|
|
722
724
|
runsDir: path.join(baseDir, "runs"),
|
|
723
|
-
};
|
|
725
|
+
}, outputFs);
|
|
724
726
|
}
|
|
725
727
|
|
|
726
728
|
async function writeScopeEnvelopeArtifact(storage, workItemId, envelope, nowIso) {
|
|
729
|
+
requireOutputFileSystem(storage.outputFs);
|
|
727
730
|
const artifactPath = path.join(
|
|
728
731
|
storage.observabilityRoot,
|
|
729
732
|
buildDayKey(nowIso),
|
|
730
733
|
normalizeString(workItemId),
|
|
731
734
|
"scope_envelope.json"
|
|
732
735
|
);
|
|
733
|
-
await
|
|
734
|
-
await
|
|
736
|
+
await storage.outputFs.mkdir(path.dirname(artifactPath), { recursive: true });
|
|
737
|
+
await storage.outputFs.writeFile(artifactPath, `${JSON.stringify(envelope, null, 2)}\n`, "utf-8");
|
|
735
738
|
return artifactPath;
|
|
736
739
|
}
|
|
737
740
|
|
|
@@ -740,9 +743,10 @@ function buildRunMetadataPath(storage, runId) {
|
|
|
740
743
|
}
|
|
741
744
|
|
|
742
745
|
async function persistRunMetadata(storage, payload) {
|
|
746
|
+
requireOutputFileSystem(storage.outputFs);
|
|
743
747
|
const runPath = buildRunMetadataPath(storage, payload.runId);
|
|
744
|
-
await
|
|
745
|
-
await
|
|
748
|
+
await storage.outputFs.mkdir(path.dirname(runPath), { recursive: true });
|
|
749
|
+
await storage.outputFs.writeFile(runPath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8");
|
|
746
750
|
return runPath;
|
|
747
751
|
}
|
|
748
752
|
|
package/src/daemon/watchdog.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fsp from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
import { bindOutputFileSystem, requireOutputFileSystem } from "../config/output-filesystem.js";
|
|
4
5
|
import { loadConfig } from "../config/service.js";
|
|
5
6
|
import { listAssignments, resolveAssignmentLedgerStorage } from "./assignment-ledger.js";
|
|
6
7
|
import { listBudgetStates } from "./budget-governor.js";
|
|
@@ -302,14 +303,16 @@ async function readJsonFile(filePath, defaultFactory) {
|
|
|
302
303
|
}
|
|
303
304
|
}
|
|
304
305
|
|
|
305
|
-
async function writeJsonFile(filePath, payload) {
|
|
306
|
-
|
|
307
|
-
await
|
|
306
|
+
async function writeJsonFile(filePath, payload, outputFs) {
|
|
307
|
+
requireOutputFileSystem(outputFs);
|
|
308
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
309
|
+
await outputFs.writeFile(filePath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8");
|
|
308
310
|
}
|
|
309
311
|
|
|
310
|
-
async function appendEvent(filePath, payload) {
|
|
311
|
-
|
|
312
|
-
await
|
|
312
|
+
async function appendEvent(filePath, payload, outputFs) {
|
|
313
|
+
requireOutputFileSystem(outputFs);
|
|
314
|
+
await outputFs.mkdir(path.dirname(filePath), { recursive: true });
|
|
315
|
+
await outputFs.appendFile(filePath, `${JSON.stringify(payload)}\n`, "utf-8");
|
|
313
316
|
}
|
|
314
317
|
|
|
315
318
|
function buildRunId(nowIso, count) {
|
|
@@ -756,12 +759,12 @@ export async function resolveWatchdogStorage({
|
|
|
756
759
|
env,
|
|
757
760
|
homeDir,
|
|
758
761
|
});
|
|
759
|
-
return {
|
|
762
|
+
return bindOutputFileSystem({
|
|
760
763
|
...daemonStorage,
|
|
761
764
|
watchdogStatePath: path.join(daemonStorage.baseDir, "watchdog-state.json"),
|
|
762
765
|
watchdogEventsPath: path.join(daemonStorage.baseDir, "watchdog-events.ndjson"),
|
|
763
766
|
watchdogRunsDir: path.join(daemonStorage.baseDir, "watchdog-runs"),
|
|
764
|
-
};
|
|
767
|
+
}, daemonStorage.outputFs);
|
|
765
768
|
}
|
|
766
769
|
|
|
767
770
|
export async function runWatchdogTick({
|
|
@@ -879,7 +882,7 @@ export async function runWatchdogTick({
|
|
|
879
882
|
normalizedNow
|
|
880
883
|
);
|
|
881
884
|
|
|
882
|
-
await
|
|
885
|
+
await storage.outputFs.mkdir(storage.watchdogRunsDir, { recursive: true });
|
|
883
886
|
const runId = nextState.lastRunId;
|
|
884
887
|
const runPath = path.join(storage.watchdogRunsDir, `${runId}.json`);
|
|
885
888
|
const runPayload = {
|
|
@@ -913,8 +916,8 @@ export async function runWatchdogTick({
|
|
|
913
916
|
};
|
|
914
917
|
|
|
915
918
|
await Promise.all([
|
|
916
|
-
writeJsonFile(runPath, runPayload),
|
|
917
|
-
writeJsonFile(storage.watchdogStatePath, nextState),
|
|
919
|
+
writeJsonFile(runPath, runPayload, storage.outputFs),
|
|
920
|
+
writeJsonFile(storage.watchdogStatePath, nextState, storage.outputFs),
|
|
918
921
|
appendEvent(storage.watchdogEventsPath, {
|
|
919
922
|
timestamp: normalizedNow,
|
|
920
923
|
eventType: "watchdog_tick",
|
|
@@ -925,7 +928,7 @@ export async function runWatchdogTick({
|
|
|
925
928
|
notificationCount: notifications.length,
|
|
926
929
|
sentNotificationCount: notifications.filter((item) => item.sent).length,
|
|
927
930
|
failedNotificationCount: notifications.filter((item) => !item.sent && !item.dryRun).length,
|
|
928
|
-
}),
|
|
931
|
+
}, storage.outputFs),
|
|
929
932
|
]);
|
|
930
933
|
|
|
931
934
|
return {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
import fsp from "node:fs/promises";
|
|
29
29
|
import path from "node:path";
|
|
30
30
|
|
|
31
|
-
import { namespaceDir } from "./store.js";
|
|
31
|
+
import { namespaceDir, ensureNamespace, resolveNamespaceDir, verifyNamespace } from "./store.js";
|
|
32
32
|
|
|
33
33
|
export const BUILD_STATES = Object.freeze({
|
|
34
34
|
ABSENT: "absent",
|
|
@@ -63,13 +63,32 @@ async function writeAtomic(file, value) {
|
|
|
63
63
|
await fsp.rename(tmp, file);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Resolve and verify the namespace directory for read-only build-state access.
|
|
68
|
+
* Uses resolveNamespaceDir (legacy migration) but NEVER creates a directory
|
|
69
|
+
* or sidecar on reads. Returns the dir path or null when absent.
|
|
70
|
+
*/
|
|
71
|
+
async function resolveForRead(root, namespace, legacyLossyDirs) {
|
|
72
|
+
const dir = await resolveNamespaceDir(root, namespace, legacyLossyDirs);
|
|
73
|
+
try {
|
|
74
|
+
await fsp.access(dir);
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
await verifyNamespace(dir, namespace);
|
|
79
|
+
return dir;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function createBuildState({ storeRoot, legacyLossyDirs = "refuse" } = {}) {
|
|
67
83
|
const root = path.resolve(String(storeRoot || "."));
|
|
68
84
|
|
|
69
85
|
async function read(namespace) {
|
|
86
|
+
const dir = await resolveForRead(root, namespace, legacyLossyDirs);
|
|
87
|
+
if (!dir) return { state: BUILD_STATES.ABSENT };
|
|
88
|
+
|
|
70
89
|
let raw;
|
|
71
90
|
try {
|
|
72
|
-
raw = await fsp.readFile(
|
|
91
|
+
raw = await fsp.readFile(path.join(dir, STATE_FILE), "utf-8");
|
|
73
92
|
} catch (error) {
|
|
74
93
|
if (error && error.code === "ENOENT") return { state: BUILD_STATES.ABSENT };
|
|
75
94
|
throw error;
|
|
@@ -106,6 +125,8 @@ export function createBuildState({ storeRoot } = {}) {
|
|
|
106
125
|
|
|
107
126
|
/** Mark a build STARTED. Must be called before the first chunk is written. */
|
|
108
127
|
async begin(namespace, { docDigest = null, expectedChunks = null, startedAt } = {}) {
|
|
128
|
+
const dir = await resolveNamespaceDir(root, namespace, legacyLossyDirs);
|
|
129
|
+
await ensureNamespace(dir, namespace);
|
|
109
130
|
const record = {
|
|
110
131
|
state: BUILD_STATES.BUILDING,
|
|
111
132
|
namespace: namespace.raw,
|