sentinelayer-cli 0.8.0 → 0.8.2
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 +23 -2
- package/package.json +4 -4
- package/src/agents/ai-governance/index.js +12 -0
- package/src/agents/ai-governance/tools/base.js +171 -0
- package/src/agents/ai-governance/tools/eval-regression.js +47 -0
- package/src/agents/ai-governance/tools/hitl-audit.js +81 -0
- package/src/agents/ai-governance/tools/index.js +52 -0
- package/src/agents/ai-governance/tools/prompt-drift.js +42 -0
- package/src/agents/ai-governance/tools/provenance-check.js +69 -0
- package/src/agents/backend/index.js +12 -0
- package/src/agents/backend/tools/base.js +189 -0
- package/src/agents/backend/tools/circuit-breaker-check.js +123 -0
- package/src/agents/backend/tools/idempotency-audit.js +105 -0
- package/src/agents/backend/tools/index.js +87 -0
- package/src/agents/backend/tools/retry-audit.js +132 -0
- package/src/agents/backend/tools/timeout-audit.js +144 -0
- package/src/agents/code-quality/index.js +12 -0
- package/src/agents/code-quality/tools/base.js +159 -0
- package/src/agents/code-quality/tools/complexity-measure.js +197 -0
- package/src/agents/code-quality/tools/coupling-analysis.js +81 -0
- package/src/agents/code-quality/tools/cycle-detect.js +49 -0
- package/src/agents/code-quality/tools/dep-graph.js +196 -0
- package/src/agents/code-quality/tools/index.js +89 -0
- package/src/agents/data-layer/index.js +12 -0
- package/src/agents/data-layer/tools/base.js +181 -0
- package/src/agents/data-layer/tools/index-audit.js +165 -0
- package/src/agents/data-layer/tools/index.js +83 -0
- package/src/agents/data-layer/tools/migration-scan.js +135 -0
- package/src/agents/data-layer/tools/query-explain.js +120 -0
- package/src/agents/data-layer/tools/tenancy-scan.js +166 -0
- package/src/agents/documentation/index.js +12 -0
- package/src/agents/documentation/tools/api-diff.js +91 -0
- package/src/agents/documentation/tools/base.js +151 -0
- package/src/agents/documentation/tools/dead-link-check.js +58 -0
- package/src/agents/documentation/tools/docstring-coverage.js +78 -0
- package/src/agents/documentation/tools/index.js +52 -0
- package/src/agents/documentation/tools/readme-freshness.js +61 -0
- package/src/agents/envelope/fix-cycle.js +45 -0
- package/src/agents/envelope/index.js +31 -0
- package/src/agents/envelope/loop.js +150 -0
- package/src/agents/envelope/pulse.js +18 -0
- package/src/agents/envelope/stream.js +40 -0
- package/src/agents/infrastructure/index.js +12 -0
- package/src/agents/infrastructure/tools/base.js +171 -0
- package/src/agents/infrastructure/tools/checkov-run.js +32 -0
- package/src/agents/infrastructure/tools/drift-detect.js +59 -0
- package/src/agents/infrastructure/tools/iam-least-priv-check.js +78 -0
- package/src/agents/infrastructure/tools/index.js +52 -0
- package/src/agents/infrastructure/tools/tflint-run.js +31 -0
- package/src/agents/jules/loop.js +7 -4
- package/src/agents/jules/swarm/sub-agent.js +5 -1
- package/src/agents/jules/tools/auth-audit.js +10 -1
- package/src/agents/mode.js +113 -0
- package/src/agents/observability/index.js +12 -0
- package/src/agents/observability/tools/alert-audit.js +39 -0
- package/src/agents/observability/tools/base.js +181 -0
- package/src/agents/observability/tools/dashboard-gap.js +42 -0
- package/src/agents/observability/tools/index.js +54 -0
- package/src/agents/observability/tools/log-schema-check.js +74 -0
- package/src/agents/observability/tools/span-coverage.js +74 -0
- package/src/agents/persona-visuals.js +38 -0
- package/src/agents/release/index.js +12 -0
- package/src/agents/release/tools/base.js +181 -0
- package/src/agents/release/tools/changelog-diff.js +86 -0
- package/src/agents/release/tools/feature-flag-audit.js +126 -0
- package/src/agents/release/tools/index.js +61 -0
- package/src/agents/release/tools/rollback-verify.js +129 -0
- package/src/agents/release/tools/semver-check.js +109 -0
- package/src/agents/reliability/index.js +12 -0
- package/src/agents/reliability/tools/backpressure-check.js +129 -0
- package/src/agents/reliability/tools/base.js +181 -0
- package/src/agents/reliability/tools/chaos-probe.js +109 -0
- package/src/agents/reliability/tools/graceful-degradation-check.js +114 -0
- package/src/agents/reliability/tools/health-check-audit.js +111 -0
- package/src/agents/reliability/tools/index.js +87 -0
- package/src/agents/run-persona.js +109 -0
- package/src/agents/security/index.js +12 -0
- package/src/agents/security/tools/authz-audit.js +134 -0
- package/src/agents/security/tools/base.js +190 -0
- package/src/agents/security/tools/crypto-review.js +175 -0
- package/src/agents/security/tools/index.js +97 -0
- package/src/agents/security/tools/sast-scan.js +175 -0
- package/src/agents/security/tools/secrets-scan.js +216 -0
- package/src/agents/supply-chain/index.js +12 -0
- package/src/agents/supply-chain/tools/attestation-check.js +42 -0
- package/src/agents/supply-chain/tools/base.js +151 -0
- package/src/agents/supply-chain/tools/index.js +52 -0
- package/src/agents/supply-chain/tools/lockfile-integrity.js +73 -0
- package/src/agents/supply-chain/tools/package-verify.js +56 -0
- package/src/agents/supply-chain/tools/sbom-diff.js +34 -0
- package/src/agents/testing/index.js +12 -0
- package/src/agents/testing/tools/base.js +202 -0
- package/src/agents/testing/tools/coverage-gap.js +144 -0
- package/src/agents/testing/tools/flake-detect.js +125 -0
- package/src/agents/testing/tools/index.js +85 -0
- package/src/agents/testing/tools/mutation-test.js +143 -0
- package/src/agents/testing/tools/snapshot-diff.js +103 -0
- package/src/auth/gate.js +65 -37
- package/src/cli.js +1 -1
- package/src/commands/chat.js +3 -10
- package/src/commands/legacy-args.js +10 -0
- package/src/commands/omargate.js +36 -2
- package/src/commands/persona.js +46 -1
- package/src/commands/scan.js +3 -10
- package/src/commands/session.js +654 -6
- package/src/commands/spec.js +3 -10
- package/src/coord/events-log.js +141 -0
- package/src/coord/handshake.js +719 -0
- package/src/coord/index.js +35 -0
- package/src/coord/paths.js +84 -0
- package/src/coord/priority.js +62 -0
- package/src/coord/tarjan.js +157 -0
- package/src/cost/tokenizer.js +160 -0
- package/src/cost/tracker.js +61 -0
- package/src/daemon/artifact-lineage.js +362 -0
- package/src/daemon/assignment-ledger.js +117 -0
- package/src/daemon/ast-drift.js +496 -0
- package/src/daemon/ingest-refresh.js +69 -2
- package/src/ingest/engine.js +15 -0
- package/src/ingest/ownership.js +380 -0
- package/src/legacy-cli.js +68 -1
- package/src/orchestrator/kai-chen.js +126 -0
- package/src/review/ai-review.js +3 -10
- package/src/review/compliance-pack.js +389 -0
- package/src/review/investor-dd-config.js +54 -0
- package/src/review/investor-dd-file-loop.js +303 -0
- package/src/review/investor-dd-file-router.js +406 -0
- package/src/review/investor-dd-html-report.js +233 -0
- package/src/review/investor-dd-notification.js +120 -0
- package/src/review/investor-dd-orchestrator.js +405 -0
- package/src/review/investor-dd-persona-runner.js +275 -0
- package/src/review/live-validator.js +253 -0
- package/src/review/omargate-orchestrator.js +90 -2
- package/src/review/persona-prompts.js +244 -56
- package/src/review/reconciliation-rules.js +329 -0
- package/src/review/reproducibility-chain.js +136 -0
- package/src/review/scan-modes.js +102 -3
- package/src/session/agent-registry.js +7 -0
- package/src/session/analytics.js +479 -0
- package/src/session/daemon.js +609 -14
- package/src/session/file-locks.js +666 -0
- package/src/session/paths.js +4 -0
- package/src/session/recap.js +567 -0
- package/src/session/redact.js +82 -0
- package/src/session/runtime-bridge.js +24 -1
- package/src/session/scoring.js +406 -0
- package/src/session/setup-guides.js +304 -0
- package/src/session/store.js +318 -2
- package/src/session/stream.js +9 -1
- package/src/session/sync.js +753 -0
- package/src/session/tasks.js +1054 -0
- package/src/session/templates.js +188 -0
- package/src/swarm/runtime.js +1 -8
package/src/commands/spec.js
CHANGED
|
@@ -13,6 +13,7 @@ import { loadConfig } from "../config/service.js";
|
|
|
13
13
|
import { evaluateBudget } from "../cost/budget.js";
|
|
14
14
|
import { appendCostEntry, summarizeCostHistory } from "../cost/history.js";
|
|
15
15
|
import { estimateModelCost } from "../cost/tracker.js";
|
|
16
|
+
import { estimateTokens } from "../cost/tokenizer.js";
|
|
16
17
|
import { formatIngestResolutionNotice, resolveCodebaseIngest } from "../ingest/engine.js";
|
|
17
18
|
import {
|
|
18
19
|
buildLineDiff,
|
|
@@ -145,14 +146,6 @@ async function detectSessionActive(targetPath) {
|
|
|
145
146
|
return false;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
function estimateTokenCount(text) {
|
|
149
|
-
const normalized = String(text || "");
|
|
150
|
-
if (!normalized) {
|
|
151
|
-
return 0;
|
|
152
|
-
}
|
|
153
|
-
return Math.max(1, Math.ceil(normalized.length / 4));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
149
|
function resolveConfiguredApiKey(provider, resolvedConfig = {}) {
|
|
157
150
|
const normalizedProvider = String(provider || "").trim().toLowerCase();
|
|
158
151
|
if (normalizedProvider === "openai") {
|
|
@@ -295,8 +288,8 @@ async function maybeEnhanceSpecWithAi({
|
|
|
295
288
|
const normalizedText = String(result.text || "").trim();
|
|
296
289
|
const enhancedMarkdown = normalizedText || baseSpecMarkdown;
|
|
297
290
|
|
|
298
|
-
const inputTokens =
|
|
299
|
-
const outputTokens =
|
|
291
|
+
const inputTokens = estimateTokens(prompt, { model: result.model });
|
|
292
|
+
const outputTokens = estimateTokens(enhancedMarkdown, { model: result.model });
|
|
300
293
|
const modelCost = maybeEstimateModelCost({
|
|
301
294
|
modelId: result.model,
|
|
302
295
|
inputTokens,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Append-only event log for the handshake primitive (#A9, spec §5.6).
|
|
2
|
+
//
|
|
3
|
+
// Every state transition — lock_granted, lock_denied, lock_renewed,
|
|
4
|
+
// lock_preempted, lock_released, lock_expired, deadlock_broken, wait_recorded
|
|
5
|
+
// — is written to .sentinel/events.jsonl. The log is the source of truth
|
|
6
|
+
// for replay / audit; callers should never mutate it in place.
|
|
7
|
+
//
|
|
8
|
+
// We serialize writes with a directory-mkdir mutex so concurrent personas on
|
|
9
|
+
// the same filesystem (workers + Omar Gate runner) don't interleave bytes.
|
|
10
|
+
|
|
11
|
+
import fsp from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import process from "node:process";
|
|
14
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
resolveEventsLockPath,
|
|
18
|
+
resolveEventsPath,
|
|
19
|
+
resolveSentinelDir,
|
|
20
|
+
} from "./paths.js";
|
|
21
|
+
|
|
22
|
+
const EVENTS_LOCK_TIMEOUT_MS = 5000;
|
|
23
|
+
const EVENTS_LOCK_STALE_MS = 30_000;
|
|
24
|
+
const EVENTS_LOCK_POLL_MS = 25;
|
|
25
|
+
|
|
26
|
+
const KNOWN_EVENT_TYPES = new Set([
|
|
27
|
+
"lock_granted",
|
|
28
|
+
"lock_renewed",
|
|
29
|
+
"lock_denied",
|
|
30
|
+
"lock_preempted",
|
|
31
|
+
"lock_released",
|
|
32
|
+
"lock_expired",
|
|
33
|
+
"wait_recorded",
|
|
34
|
+
"wait_cleared",
|
|
35
|
+
"deadlock_broken",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
async function acquireEventsLock(
|
|
39
|
+
lockPath,
|
|
40
|
+
{ timeoutMs = EVENTS_LOCK_TIMEOUT_MS, staleMs = EVENTS_LOCK_STALE_MS, pollMs = EVENTS_LOCK_POLL_MS } = {}
|
|
41
|
+
) {
|
|
42
|
+
const start = Date.now();
|
|
43
|
+
while (true) {
|
|
44
|
+
try {
|
|
45
|
+
await fsp.mkdir(lockPath);
|
|
46
|
+
return;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
const code = err && typeof err === "object" ? err.code : "";
|
|
49
|
+
if (code !== "EEXIST" && code !== "EPERM" && code !== "EACCES") {
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const stat = await fsp.stat(lockPath);
|
|
54
|
+
const ageMs = Date.now() - Number(stat.mtimeMs || 0);
|
|
55
|
+
if (Number.isFinite(ageMs) && ageMs > staleMs) {
|
|
56
|
+
await fsp.rm(lockPath, { recursive: true, force: true });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Stat race — loop back.
|
|
61
|
+
}
|
|
62
|
+
if (Date.now() - start >= timeoutMs) {
|
|
63
|
+
throw new Error("Timed out waiting for .sentinel/events.jsonl lock.");
|
|
64
|
+
}
|
|
65
|
+
await sleep(pollMs);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function releaseEventsLock(lockPath) {
|
|
71
|
+
await fsp.rm(lockPath, { recursive: true, force: true }).catch(() => {});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function stripUndefined(record) {
|
|
75
|
+
const out = {};
|
|
76
|
+
for (const [key, value] of Object.entries(record || {})) {
|
|
77
|
+
if (value !== undefined) {
|
|
78
|
+
out[key] = value;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function appendEvent(event, { targetPath = process.cwd() } = {}) {
|
|
85
|
+
const type = String(event?.type || "").trim();
|
|
86
|
+
if (!type) {
|
|
87
|
+
throw new Error("event.type is required.");
|
|
88
|
+
}
|
|
89
|
+
if (!KNOWN_EVENT_TYPES.has(type)) {
|
|
90
|
+
throw new Error(`Unknown handshake event type: ${type}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sentinelDir = resolveSentinelDir({ targetPath });
|
|
94
|
+
await fsp.mkdir(sentinelDir, { recursive: true });
|
|
95
|
+
|
|
96
|
+
const record = stripUndefined({
|
|
97
|
+
schemaVersion: "1.0.0",
|
|
98
|
+
type,
|
|
99
|
+
ts: event.ts || new Date().toISOString(),
|
|
100
|
+
...event,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const eventsPath = resolveEventsPath({ targetPath });
|
|
104
|
+
const lockPath = resolveEventsLockPath({ targetPath });
|
|
105
|
+
|
|
106
|
+
await acquireEventsLock(lockPath);
|
|
107
|
+
try {
|
|
108
|
+
await fsp.appendFile(eventsPath, `${JSON.stringify(record)}\n`, "utf-8");
|
|
109
|
+
} finally {
|
|
110
|
+
await releaseEventsLock(lockPath);
|
|
111
|
+
}
|
|
112
|
+
return record;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function readEvents({ targetPath = process.cwd() } = {}) {
|
|
116
|
+
const eventsPath = resolveEventsPath({ targetPath });
|
|
117
|
+
let raw;
|
|
118
|
+
try {
|
|
119
|
+
raw = await fsp.readFile(eventsPath, "utf-8");
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err && typeof err === "object" && err.code === "ENOENT") {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
const events = [];
|
|
127
|
+
for (const line of raw.split("\n")) {
|
|
128
|
+
const trimmed = line.trim();
|
|
129
|
+
if (!trimmed) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
events.push(JSON.parse(trimmed));
|
|
134
|
+
} catch {
|
|
135
|
+
// Corrupt row — skip rather than fail the caller.
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return events;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { KNOWN_EVENT_TYPES };
|