sentinelayer-cli 0.8.11 → 0.9.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/package.json +10 -5
- package/src/agents/devtestbot/config/definition.js +100 -0
- package/src/agents/devtestbot/config/system-prompt.js +92 -0
- package/src/agents/devtestbot/index.js +9 -0
- package/src/agents/devtestbot/runner.js +769 -0
- package/src/agents/devtestbot/tool.js +707 -0
- package/src/agents/jules/stream.js +2 -12
- package/src/audit/orchestrator.js +471 -114
- package/src/audit/persona-loop.js +1342 -0
- package/src/audit/registry.js +58 -2
- package/src/commands/audit.js +42 -1
- package/src/commands/legacy-args.js +32 -1
- package/src/commands/omargate.js +4 -0
- package/src/commands/session.js +417 -89
- package/src/commands/swarm.js +11 -2
- package/src/cost/history.js +41 -21
- package/src/events/schema.js +27 -1
- package/src/guide/generator.js +14 -0
- package/src/legacy-cli.js +110 -18
- package/src/prompt/generator.js +4 -16
- package/src/review/ai-review.js +95 -6
- package/src/review/dd-report-email-client.js +148 -0
- package/src/review/investor-dd-devtestbot.js +599 -0
- package/src/review/investor-dd-orchestrator.js +135 -3
- package/src/review/omargate-cache.js +285 -0
- package/src/review/omargate-orchestrator.js +605 -4
- package/src/review/persona-prompts.js +34 -1
- package/src/review/report.js +189 -4
- package/src/session/coordination-guidance.js +48 -0
- package/src/session/daemon.js +3 -2
- package/src/session/listener.js +236 -0
- package/src/session/senti-naming.js +36 -0
- package/src/session/setup-guides.js +3 -15
- package/src/session/store.js +54 -5
- package/src/session/sync.js +23 -0
- package/src/spec/generator.js +8 -10
- package/src/swarm/registry.js +20 -0
- package/src/swarm/runtime.js +139 -1
package/src/audit/registry.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import fsp from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
+
export const DEFAULT_AUDIT_AGENT_TOOLS = Object.freeze([
|
|
5
|
+
"FileRead",
|
|
6
|
+
"Grep",
|
|
7
|
+
"Glob",
|
|
8
|
+
"Shell",
|
|
9
|
+
"FileEdit",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const TOOL_NAME_ALIASES = Object.freeze({
|
|
13
|
+
read: "FileRead",
|
|
14
|
+
file_read: "FileRead",
|
|
15
|
+
"file-read": "FileRead",
|
|
16
|
+
fileread: "FileRead",
|
|
17
|
+
grep: "Grep",
|
|
18
|
+
glob: "Glob",
|
|
19
|
+
shell: "Shell",
|
|
20
|
+
file_edit: "FileEdit",
|
|
21
|
+
"file-edit": "FileEdit",
|
|
22
|
+
fileedit: "FileEdit",
|
|
23
|
+
dispatch: "Dispatch",
|
|
24
|
+
});
|
|
25
|
+
|
|
4
26
|
const BUILTIN_AUDIT_AGENTS = Object.freeze([
|
|
5
27
|
{
|
|
6
28
|
id: "security",
|
|
@@ -173,16 +195,40 @@ function normalizeString(value) {
|
|
|
173
195
|
return String(value || "").trim();
|
|
174
196
|
}
|
|
175
197
|
|
|
198
|
+
function normalizeToolName(value) {
|
|
199
|
+
const raw = normalizeString(value);
|
|
200
|
+
if (!raw) {
|
|
201
|
+
return "";
|
|
202
|
+
}
|
|
203
|
+
const alias = TOOL_NAME_ALIASES[raw.toLowerCase()];
|
|
204
|
+
if (alias) {
|
|
205
|
+
return alias;
|
|
206
|
+
}
|
|
207
|
+
return raw;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function normalizeAuditAgentTools(tools = [], { useDefaultWhenEmpty = false } = {}) {
|
|
211
|
+
const normalized = Array.isArray(tools)
|
|
212
|
+
? tools.map((item) => normalizeToolName(item)).filter(Boolean)
|
|
213
|
+
: [];
|
|
214
|
+
const unique = [...new Set(normalized)];
|
|
215
|
+
if (unique.length > 0) {
|
|
216
|
+
return unique;
|
|
217
|
+
}
|
|
218
|
+
return useDefaultWhenEmpty ? [...DEFAULT_AUDIT_AGENT_TOOLS] : [];
|
|
219
|
+
}
|
|
220
|
+
|
|
176
221
|
function normalizeAgentId(value) {
|
|
177
222
|
return normalizeString(value).toLowerCase();
|
|
178
223
|
}
|
|
179
224
|
|
|
180
225
|
function normalizeAgentRecord(record = {}) {
|
|
226
|
+
const hasToolOverride = Object.prototype.hasOwnProperty.call(record, "tools");
|
|
181
227
|
return {
|
|
182
228
|
id: normalizeAgentId(record.id),
|
|
183
229
|
persona: normalizeString(record.persona),
|
|
184
230
|
domain: normalizeString(record.domain),
|
|
185
|
-
tools:
|
|
231
|
+
tools: normalizeAuditAgentTools(record.tools, { useDefaultWhenEmpty: !hasToolOverride }),
|
|
186
232
|
permissionMode: normalizeString(record.permissionMode || "plan") || "plan",
|
|
187
233
|
maxTurns: Math.max(1, Math.floor(Number(record.maxTurns || 1))),
|
|
188
234
|
confidenceFloor: Math.max(0, Math.min(1, Number(record.confidenceFloor || 0))),
|
|
@@ -206,6 +252,11 @@ function mergeRegistry(builtinAgents = [], overrideAgents = []) {
|
|
|
206
252
|
continue;
|
|
207
253
|
}
|
|
208
254
|
const existing = byId.get(normalized.id) || {};
|
|
255
|
+
if (!Object.prototype.hasOwnProperty.call(override, "tools")) {
|
|
256
|
+
normalized.tools = Array.isArray(existing.tools) && existing.tools.length > 0
|
|
257
|
+
? [...existing.tools]
|
|
258
|
+
: [...DEFAULT_AUDIT_AGENT_TOOLS];
|
|
259
|
+
}
|
|
209
260
|
byId.set(normalized.id, {
|
|
210
261
|
...existing,
|
|
211
262
|
...normalized,
|
|
@@ -223,7 +274,12 @@ function parseAgentFilter(rawValue) {
|
|
|
223
274
|
}
|
|
224
275
|
|
|
225
276
|
export function listBuiltinAuditAgents() {
|
|
226
|
-
return BUILTIN_AUDIT_AGENTS.map((agent) =>
|
|
277
|
+
return BUILTIN_AUDIT_AGENTS.map((agent) =>
|
|
278
|
+
normalizeAgentRecord({
|
|
279
|
+
...agent,
|
|
280
|
+
tools: DEFAULT_AUDIT_AGENT_TOOLS,
|
|
281
|
+
})
|
|
282
|
+
);
|
|
227
283
|
}
|
|
228
284
|
|
|
229
285
|
export async function loadAuditRegistry({ registryFile = "" } = {}) {
|
package/src/commands/audit.js
CHANGED
|
@@ -26,6 +26,14 @@ function parseMaxParallel(rawValue) {
|
|
|
26
26
|
return Math.floor(normalized);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
function parseIsolationMode(rawValue) {
|
|
30
|
+
const normalized = String(rawValue || "strict").trim().toLowerCase();
|
|
31
|
+
if (normalized === "strict" || normalized === "relaxed") {
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
throw new Error("isolation must be one of: strict, relaxed.");
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
function printAuditSummary(result) {
|
|
30
38
|
console.log(pc.bold("Audit orchestrator complete"));
|
|
31
39
|
console.log(pc.gray(`Run: ${result.runId}`));
|
|
@@ -34,6 +42,11 @@ function printAuditSummary(result) {
|
|
|
34
42
|
if (result.sharedMemory?.artifactPath) {
|
|
35
43
|
console.log(pc.gray(`Shared memory: ${result.sharedMemory.artifactPath}`));
|
|
36
44
|
}
|
|
45
|
+
if (result.omargateReuse?.used) {
|
|
46
|
+
console.log(pc.gray(`Reused OmarGate run: ${result.omargateReuse.runId}`));
|
|
47
|
+
} else if (result.omargateReuse?.requested) {
|
|
48
|
+
console.log(pc.gray(`OmarGate reuse unavailable: ${result.omargateReuse.reason || "not_found"}`));
|
|
49
|
+
}
|
|
37
50
|
if (result.ddPackage?.executiveSummaryPath) {
|
|
38
51
|
console.log(pc.gray(`DD package: ${result.ddPackage.executiveSummaryPath}`));
|
|
39
52
|
}
|
|
@@ -51,6 +64,15 @@ function printAuditSummary(result) {
|
|
|
51
64
|
console.log(`Agents: ${result.agentResults.length}, max_parallel=${result.maxParallel}`);
|
|
52
65
|
}
|
|
53
66
|
|
|
67
|
+
function buildAuditOrchestratorEventHandler(emitStream) {
|
|
68
|
+
if (!emitStream) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return (evt) => {
|
|
72
|
+
console.log(JSON.stringify(evt));
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
54
76
|
export function registerAuditCommand(program, invokeLegacy) {
|
|
55
77
|
const audit = program
|
|
56
78
|
.command("audit")
|
|
@@ -63,9 +85,14 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
63
85
|
.option("--output-dir <path>", "Optional artifact output root override")
|
|
64
86
|
.option("--refresh", "Refresh CODEBASE_INGEST before running audit")
|
|
65
87
|
.option("--dry-run", "Skip deterministic baseline and run orchestration planning only")
|
|
88
|
+
.option("--isolation <mode>", "Persona isolation mode: strict | relaxed", "strict")
|
|
89
|
+
.option("--no-seed-from-deterministic", "Run personas without deterministic baseline or specialist seed findings")
|
|
90
|
+
.option("--reuse-omargate <runId>", "Reuse deterministic findings from an OmarGate run id or latest")
|
|
91
|
+
.option("--stream", "Emit NDJSON agent events to stdout")
|
|
66
92
|
.option("--json", "Emit machine-readable output")
|
|
67
93
|
.action(async (targetPathArg, options, command) => {
|
|
68
94
|
const emitJson = shouldEmitJson(options, command);
|
|
95
|
+
const emitStream = Boolean(options.stream);
|
|
69
96
|
const targetPath = path.resolve(process.cwd(), String(options.path || targetPathArg || "."));
|
|
70
97
|
const registry = await loadAuditRegistry({
|
|
71
98
|
registryFile: options.registryFile,
|
|
@@ -85,6 +112,10 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
85
112
|
outputDir: options.outputDir,
|
|
86
113
|
dryRun: Boolean(options.dryRun),
|
|
87
114
|
refreshIngest: Boolean(options.refresh),
|
|
115
|
+
isolation: parseIsolationMode(options.isolation),
|
|
116
|
+
seedFromDeterministic: options.seedFromDeterministic !== false,
|
|
117
|
+
reuseOmarGate: options.reuseOmargate,
|
|
118
|
+
onEvent: buildAuditOrchestratorEventHandler(emitStream),
|
|
88
119
|
});
|
|
89
120
|
|
|
90
121
|
const payload = {
|
|
@@ -99,6 +130,11 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
99
130
|
registryFile: registry.registryFile,
|
|
100
131
|
selectedAgents: result.selectedAgents,
|
|
101
132
|
maxParallel: result.maxParallel,
|
|
133
|
+
isolation: result.isolation,
|
|
134
|
+
seedFromDeterministic: result.seedFromDeterministic !== false,
|
|
135
|
+
omargateReuse: result.omargateReuse || null,
|
|
136
|
+
reusedOmarGateRunId: result.omargateReuse?.used ? result.omargateReuse.runId : "",
|
|
137
|
+
reusedOmarGateDeterministicPath: result.omargateReuse?.used ? result.omargateReuse.artifactPath : "",
|
|
102
138
|
summary: result.summary,
|
|
103
139
|
agentCount: result.agentResults.length,
|
|
104
140
|
sharedMemoryPath: result.sharedMemory?.artifactPath || "",
|
|
@@ -112,7 +148,7 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
112
148
|
|
|
113
149
|
if (emitJson) {
|
|
114
150
|
console.log(JSON.stringify(payload, null, 2));
|
|
115
|
-
} else {
|
|
151
|
+
} else if (!emitStream) {
|
|
116
152
|
printAuditSummary(result);
|
|
117
153
|
}
|
|
118
154
|
|
|
@@ -211,6 +247,8 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
211
247
|
outputDir: options.outputDir,
|
|
212
248
|
dryRun: Boolean(baseReport.dryRun),
|
|
213
249
|
refreshIngest: Boolean(options.refresh),
|
|
250
|
+
isolation: baseReport.isolation || "strict",
|
|
251
|
+
seedFromDeterministic: baseReport.seedFromDeterministic !== false,
|
|
214
252
|
});
|
|
215
253
|
|
|
216
254
|
const comparison = await writeAuditComparisonArtifact({
|
|
@@ -231,6 +269,8 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
231
269
|
deterministicEquivalent: comparison.comparison.deterministicEquivalent,
|
|
232
270
|
addedCount: comparison.comparison.addedCount,
|
|
233
271
|
removedCount: comparison.comparison.removedCount,
|
|
272
|
+
isolation: replayResult.isolation,
|
|
273
|
+
seedFromDeterministic: replayResult.seedFromDeterministic !== false,
|
|
234
274
|
ingestRefresh: replayResult.ingest?.refresh || null,
|
|
235
275
|
};
|
|
236
276
|
|
|
@@ -717,6 +757,7 @@ export function registerAuditCommand(program, invokeLegacy) {
|
|
|
717
757
|
.description("Compatibility mode: run legacy local readiness + policy audit")
|
|
718
758
|
.option("--path <path>", "Target repository path")
|
|
719
759
|
.option("--output-dir <path>", "Artifact root for report output")
|
|
760
|
+
.option("--reuse-omargate <runId>", "Reuse deterministic findings from an OmarGate run id or latest")
|
|
720
761
|
.option("--json", "Emit machine-readable output")
|
|
721
762
|
.action(async (options, command) => {
|
|
722
763
|
const legacyArgs = buildLegacyArgs(["/audit"], {
|
|
@@ -20,12 +20,24 @@ function appendOutputDirFlag(args, maybeOutputDir) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function appendPassthroughFlag(args, flagName, maybeValue) {
|
|
23
|
-
const value =
|
|
23
|
+
const value = maybeValue === undefined || maybeValue === null ? "" : String(maybeValue).trim();
|
|
24
24
|
if (value) {
|
|
25
25
|
args.push(flagName, value);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
function appendBooleanFlag(args, flagName, maybeValue) {
|
|
30
|
+
if (Boolean(maybeValue)) {
|
|
31
|
+
args.push(flagName);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function appendNegatedBooleanFlag(args, flagName, maybeValue) {
|
|
36
|
+
if (maybeValue === false) {
|
|
37
|
+
args.push(flagName);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
export function buildLegacyArgs(baseArgs, { commandOptions = {}, command } = {}) {
|
|
30
42
|
const args = [...baseArgs];
|
|
31
43
|
appendPathFlag(args, commandOptions.path);
|
|
@@ -33,6 +45,25 @@ export function buildLegacyArgs(baseArgs, { commandOptions = {}, command } = {})
|
|
|
33
45
|
if (wantsJsonOutput(commandOptions, command)) {
|
|
34
46
|
args.push("--json");
|
|
35
47
|
}
|
|
48
|
+
appendNegatedBooleanFlag(args, "--no-ai", commandOptions.ai);
|
|
49
|
+
appendBooleanFlag(args, "--ai-dry-run", commandOptions.aiDryRun);
|
|
50
|
+
appendBooleanFlag(args, "--stream", commandOptions.stream);
|
|
51
|
+
appendBooleanFlag(args, "--dry-run", commandOptions.dryRun);
|
|
52
|
+
appendNegatedBooleanFlag(args, "--no-email", commandOptions.email);
|
|
53
|
+
appendNegatedBooleanFlag(args, "--no-dashboard", commandOptions.dashboard);
|
|
54
|
+
appendPassthroughFlag(args, "--scan-mode", commandOptions.scanMode);
|
|
55
|
+
appendPassthroughFlag(args, "--max-parallel", commandOptions.maxParallel);
|
|
56
|
+
appendPassthroughFlag(args, "--max-cost", commandOptions.maxCost);
|
|
57
|
+
appendPassthroughFlag(args, "--max-runtime-minutes", commandOptions.maxRuntimeMinutes);
|
|
58
|
+
appendPassthroughFlag(args, "--model", commandOptions.model);
|
|
59
|
+
appendPassthroughFlag(args, "--provider", commandOptions.provider);
|
|
60
|
+
appendPassthroughFlag(args, "--reuse-omargate", commandOptions.reuseOmargate);
|
|
61
|
+
appendPassthroughFlag(args, "--notify-email", commandOptions.notifyEmail);
|
|
62
|
+
appendPassthroughFlag(args, "--email-on-complete", commandOptions.emailOnComplete);
|
|
63
|
+
appendPassthroughFlag(args, "--notify-session", commandOptions.notifySession);
|
|
64
|
+
appendPassthroughFlag(args, "--devtestbot-base-url", commandOptions.devtestbotBaseUrl);
|
|
65
|
+
appendPassthroughFlag(args, "--devtestbot-scope", commandOptions.devtestbotScope);
|
|
66
|
+
appendNegatedBooleanFlag(args, "--no-devtestbot", commandOptions.devtestbot);
|
|
36
67
|
// Omar Gate per-persona filter flags (A-CLI-1).
|
|
37
68
|
appendPassthroughFlag(args, "--persona", commandOptions.persona);
|
|
38
69
|
appendPassthroughFlag(args, "--skip-persona", commandOptions.skipPersona);
|
package/src/commands/omargate.js
CHANGED
|
@@ -48,9 +48,13 @@ export function registerOmarGateCommand(program, invokeLegacy) {
|
|
|
48
48
|
.option("--skip-persona <csv>", "Skip these personas (comma-separated IDs)")
|
|
49
49
|
.option("--stream", "Emit NDJSON events to stdout as personas work file-by-file")
|
|
50
50
|
.option("--notify-email <addr>", "Send final report to this email (default: account email)")
|
|
51
|
+
.option("--email-on-complete <addr>", "Trigger the API-side DD report email after the run completes")
|
|
51
52
|
.option("--notify-session <session-id>", "Stream progress into this Senti session (default: auto-start)")
|
|
52
53
|
.option("--no-email", "Skip email dispatch")
|
|
53
54
|
.option("--no-dashboard", "Skip dashboard card persistence")
|
|
55
|
+
.option("--devtestbot-base-url <url>", "Approved absolute URL for devTestBot browser lanes")
|
|
56
|
+
.option("--devtestbot-scope <scope>", "devTestBot runtime scope (default: orchestrator decides)")
|
|
57
|
+
.option("--no-devtestbot", "Skip the automated devTestBot phase")
|
|
54
58
|
.option("--dry-run", "Validate config + emit plan.json; skip LLM calls")
|
|
55
59
|
.option("--json", "Emit machine-readable final output")
|
|
56
60
|
.action(async (options, command) => {
|