sentinelayer-cli 0.1.2 → 0.3.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 +996 -996
- package/bin/create-sentinelayer.js +5 -5
- package/bin/sentinelayer-cli.js +4 -4
- package/bin/sl.js +5 -5
- package/package.json +62 -54
- package/src/agents/jules/config/definition.js +209 -209
- package/src/agents/jules/config/system-prompt.js +175 -175
- package/src/agents/jules/error-intake.js +51 -51
- package/src/agents/jules/fix-cycle.js +377 -377
- package/src/agents/jules/loop.js +367 -367
- package/src/agents/jules/pulse.js +319 -319
- package/src/agents/jules/stream.js +186 -186
- package/src/agents/jules/swarm/file-scanner.js +74 -74
- package/src/agents/jules/swarm/index.js +11 -11
- package/src/agents/jules/swarm/orchestrator.js +362 -362
- package/src/agents/jules/swarm/pattern-hunter.js +123 -123
- package/src/agents/jules/swarm/sub-agent.js +308 -308
- package/src/agents/jules/tools/auth-audit.js +226 -222
- package/src/agents/jules/tools/dispatch.js +327 -327
- package/src/agents/jules/tools/file-edit.js +180 -180
- package/src/agents/jules/tools/file-read.js +100 -100
- package/src/agents/jules/tools/frontend-analyze.js +570 -570
- package/src/agents/jules/tools/glob.js +168 -168
- package/src/agents/jules/tools/grep.js +228 -228
- package/src/agents/jules/tools/index.js +29 -29
- package/src/agents/jules/tools/path-guards.js +161 -161
- package/src/agents/jules/tools/runtime-audit.js +493 -493
- package/src/agents/jules/tools/shell.js +383 -383
- package/src/ai/aidenid.js +972 -945
- package/src/ai/client.js +508 -508
- package/src/ai/domain-target-store.js +268 -268
- package/src/ai/identity-store.js +270 -270
- package/src/ai/site-store.js +145 -145
- package/src/audit/agents/architecture.js +180 -180
- package/src/audit/agents/compliance.js +179 -179
- package/src/audit/agents/documentation.js +165 -165
- package/src/audit/agents/performance.js +145 -145
- package/src/audit/agents/security.js +215 -215
- package/src/audit/agents/testing.js +172 -172
- package/src/audit/orchestrator.js +557 -557
- package/src/audit/package.js +204 -204
- package/src/audit/registry.js +284 -284
- package/src/audit/replay.js +103 -103
- package/src/auth/http.js +113 -113
- package/src/auth/service.js +891 -848
- package/src/auth/session-store.js +359 -345
- package/src/cli.js +252 -252
- package/src/commands/ai/identity-lifecycle.js +1338 -1337
- package/src/commands/ai/provision-governance.js +1272 -1246
- package/src/commands/ai/shared.js +147 -147
- package/src/commands/ai.js +11 -11
- package/src/commands/apply.js +12 -12
- package/src/commands/audit.js +1166 -1166
- package/src/commands/auth.js +375 -366
- package/src/commands/chat.js +191 -191
- package/src/commands/config.js +184 -184
- package/src/commands/cost.js +311 -311
- package/src/commands/daemon/core.js +850 -850
- package/src/commands/daemon/extended.js +1048 -1048
- package/src/commands/daemon/shared.js +213 -213
- package/src/commands/daemon.js +11 -11
- package/src/commands/guide.js +174 -174
- package/src/commands/ingest.js +58 -58
- package/src/commands/init.js +55 -55
- package/src/commands/legacy-args.js +10 -10
- package/src/commands/mcp.js +461 -404
- package/src/commands/omargate.js +15 -15
- package/src/commands/persona.js +20 -20
- package/src/commands/plugin.js +260 -260
- package/src/commands/policy.js +132 -132
- package/src/commands/prompt.js +238 -238
- package/src/commands/review.js +704 -704
- package/src/commands/scan.js +866 -788
- package/src/commands/spec.js +716 -716
- package/src/commands/swarm.js +651 -651
- package/src/commands/telemetry.js +202 -202
- package/src/commands/watch.js +510 -510
- package/src/config/agent-dictionary.js +182 -182
- package/src/config/io.js +56 -56
- package/src/config/paths.js +18 -18
- package/src/config/schema.js +55 -55
- package/src/config/service.js +184 -184
- package/src/cost/budget.js +235 -235
- package/src/cost/history.js +188 -188
- package/src/cost/tracker.js +171 -171
- package/src/daemon/artifact-lineage.js +534 -534
- package/src/daemon/assignment-ledger.js +770 -770
- package/src/daemon/ast-parser-layer.js +258 -258
- package/src/daemon/budget-governor.js +633 -633
- package/src/daemon/callgraph-overlay.js +646 -646
- package/src/daemon/error-worker.js +626 -626
- package/src/daemon/hybrid-mapper.js +929 -929
- package/src/daemon/jira-lifecycle.js +632 -632
- package/src/daemon/operator-control.js +657 -657
- package/src/daemon/reliability-lane.js +471 -471
- package/src/daemon/watchdog.js +971 -971
- package/src/guide/generator.js +316 -316
- package/src/ingest/engine.js +918 -918
- package/src/legacy-cli.js +2548 -2435
- package/src/mcp/registry.js +695 -695
- package/src/memory/blackboard.js +301 -301
- package/src/memory/retrieval.js +581 -581
- package/src/plugin/manifest.js +553 -553
- package/src/policy/packs.js +144 -144
- package/src/prompt/generator.js +118 -106
- package/src/review/ai-review.js +669 -669
- package/src/review/local-review.js +1284 -1284
- package/src/review/replay.js +235 -235
- package/src/review/report.js +664 -664
- package/src/review/spec-binding.js +487 -487
- package/src/scaffold/generator.js +67 -0
- package/src/scaffold/templates.js +150 -0
- package/src/scan/generator.js +418 -351
- package/src/scan/gh-secrets.js +107 -0
- package/src/spec/generator.js +519 -519
- package/src/spec/regenerate.js +237 -237
- package/src/spec/templates.js +91 -91
- package/src/swarm/dashboard.js +247 -247
- package/src/swarm/factory.js +363 -363
- package/src/swarm/pentest.js +934 -934
- package/src/swarm/registry.js +419 -419
- package/src/swarm/report.js +158 -158
- package/src/swarm/runtime.js +576 -576
- package/src/swarm/scenario-dsl.js +272 -272
- package/src/telemetry/ledger.js +302 -302
- package/src/telemetry/sync.js +96 -59
- package/src/ui/markdown.js +220 -220
|
@@ -1,182 +1,182 @@
|
|
|
1
|
-
const SUPPORTED_CODING_AGENT_TABLE = Object.freeze({
|
|
2
|
-
"claude-code": Object.freeze({
|
|
3
|
-
name: "Claude Code",
|
|
4
|
-
promptTarget: "claude",
|
|
5
|
-
configFile: "CLAUDE.md",
|
|
6
|
-
configDir: ".claude/",
|
|
7
|
-
}),
|
|
8
|
-
cursor: Object.freeze({
|
|
9
|
-
name: "Cursor",
|
|
10
|
-
promptTarget: "cursor",
|
|
11
|
-
configFile: ".cursorrules",
|
|
12
|
-
configDir: ".cursor/",
|
|
13
|
-
}),
|
|
14
|
-
copilot: Object.freeze({
|
|
15
|
-
name: "GitHub Copilot",
|
|
16
|
-
promptTarget: "copilot",
|
|
17
|
-
configFile: ".github/copilot-instructions.md",
|
|
18
|
-
configDir: ".github/",
|
|
19
|
-
}),
|
|
20
|
-
windsurf: Object.freeze({
|
|
21
|
-
name: "Windsurf",
|
|
22
|
-
promptTarget: "generic",
|
|
23
|
-
configFile: ".windsurfrules",
|
|
24
|
-
configDir: null,
|
|
25
|
-
}),
|
|
26
|
-
cody: Object.freeze({
|
|
27
|
-
name: "Sourcegraph Cody",
|
|
28
|
-
promptTarget: "generic",
|
|
29
|
-
configFile: ".cody/cody.json",
|
|
30
|
-
configDir: ".cody/",
|
|
31
|
-
}),
|
|
32
|
-
aider: Object.freeze({
|
|
33
|
-
name: "Aider",
|
|
34
|
-
promptTarget: "generic",
|
|
35
|
-
configFile: ".aider.conf.yml",
|
|
36
|
-
configDir: null,
|
|
37
|
-
}),
|
|
38
|
-
continue: Object.freeze({
|
|
39
|
-
name: "Continue",
|
|
40
|
-
promptTarget: "generic",
|
|
41
|
-
configFile: ".continue/config.json",
|
|
42
|
-
configDir: ".continue/",
|
|
43
|
-
}),
|
|
44
|
-
codex: Object.freeze({
|
|
45
|
-
name: "OpenAI Codex",
|
|
46
|
-
promptTarget: "codex",
|
|
47
|
-
configFile: "AGENTS.md",
|
|
48
|
-
configDir: null,
|
|
49
|
-
}),
|
|
50
|
-
bolt: Object.freeze({
|
|
51
|
-
name: "Bolt.new",
|
|
52
|
-
promptTarget: "generic",
|
|
53
|
-
configFile: null,
|
|
54
|
-
configDir: null,
|
|
55
|
-
}),
|
|
56
|
-
generic: Object.freeze({
|
|
57
|
-
name: "Other",
|
|
58
|
-
promptTarget: "generic",
|
|
59
|
-
configFile: null,
|
|
60
|
-
configDir: null,
|
|
61
|
-
}),
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const SUPPORTED_IDE_TABLE = Object.freeze({
|
|
65
|
-
vscode: Object.freeze({
|
|
66
|
-
name: "VS Code",
|
|
67
|
-
detect: (env) =>
|
|
68
|
-
String(env.TERM_PROGRAM || "").toLowerCase().includes("vscode") &&
|
|
69
|
-
!String(env.CURSOR_TRACE_ID || "").trim(),
|
|
70
|
-
}),
|
|
71
|
-
cursor: Object.freeze({
|
|
72
|
-
name: "Cursor",
|
|
73
|
-
detect: (env) => Boolean(String(env.CURSOR_TRACE_ID || "").trim()),
|
|
74
|
-
}),
|
|
75
|
-
jetbrains: Object.freeze({
|
|
76
|
-
name: "JetBrains",
|
|
77
|
-
detect: (env) => Boolean(String(env.JETBRAINS_IDE || "").trim()),
|
|
78
|
-
}),
|
|
79
|
-
neovim: Object.freeze({
|
|
80
|
-
name: "Neovim",
|
|
81
|
-
detect: (env) => Boolean(String(env.NVIM || "").trim()),
|
|
82
|
-
}),
|
|
83
|
-
zed: Object.freeze({
|
|
84
|
-
name: "Zed",
|
|
85
|
-
detect: (env) => String(env.TERM_PROGRAM || "").trim().toLowerCase() === "zed",
|
|
86
|
-
}),
|
|
87
|
-
sublime: Object.freeze({
|
|
88
|
-
name: "Sublime Text",
|
|
89
|
-
detect: (env) => Boolean(String(env.SUBLIME_TEXT || "").trim()),
|
|
90
|
-
}),
|
|
91
|
-
vim: Object.freeze({
|
|
92
|
-
name: "Vim",
|
|
93
|
-
detect: (env) => Boolean(String(env.VIM || "").trim()),
|
|
94
|
-
}),
|
|
95
|
-
emacs: Object.freeze({
|
|
96
|
-
name: "Emacs",
|
|
97
|
-
detect: (env) => Boolean(String(env.INSIDE_EMACS || "").trim()),
|
|
98
|
-
}),
|
|
99
|
-
terminal: Object.freeze({
|
|
100
|
-
name: "Terminal",
|
|
101
|
-
detect: () => true,
|
|
102
|
-
}),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const IDE_DETECTION_ORDER = Object.freeze([
|
|
106
|
-
"cursor",
|
|
107
|
-
"vscode",
|
|
108
|
-
"jetbrains",
|
|
109
|
-
"neovim",
|
|
110
|
-
"zed",
|
|
111
|
-
"sublime",
|
|
112
|
-
"vim",
|
|
113
|
-
"emacs",
|
|
114
|
-
"terminal",
|
|
115
|
-
]);
|
|
116
|
-
|
|
117
|
-
export const DEFAULT_CODING_AGENT_ID = "generic";
|
|
118
|
-
export const DEFAULT_IDE_ID = "terminal";
|
|
119
|
-
|
|
120
|
-
export const SUPPORTED_CODING_AGENTS = SUPPORTED_CODING_AGENT_TABLE;
|
|
121
|
-
export const SUPPORTED_IDES = SUPPORTED_IDE_TABLE;
|
|
122
|
-
|
|
123
|
-
function normalizeKey(value) {
|
|
124
|
-
return String(value || "")
|
|
125
|
-
.trim()
|
|
126
|
-
.toLowerCase();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function listSupportedCodingAgents() {
|
|
130
|
-
return Object.entries(SUPPORTED_CODING_AGENT_TABLE).map(([id, record]) => ({
|
|
131
|
-
id,
|
|
132
|
-
...record,
|
|
133
|
-
}));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function resolveCodingAgent(agentId = DEFAULT_CODING_AGENT_ID) {
|
|
137
|
-
const normalized = normalizeKey(agentId) || DEFAULT_CODING_AGENT_ID;
|
|
138
|
-
const record = SUPPORTED_CODING_AGENT_TABLE[normalized];
|
|
139
|
-
if (!record) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
`Unsupported coding agent '${agentId}'. Use one of: ${Object.keys(SUPPORTED_CODING_AGENT_TABLE).join(", ")}`
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
return {
|
|
145
|
-
id: normalized,
|
|
146
|
-
...record,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function detectCodingAgentFromEnv(env = process.env) {
|
|
151
|
-
const explicit = normalizeKey(env.SENTINELAYER_CODING_AGENT || env.CODING_AGENT || "");
|
|
152
|
-
if (explicit && Object.prototype.hasOwnProperty.call(SUPPORTED_CODING_AGENT_TABLE, explicit)) {
|
|
153
|
-
return resolveCodingAgent(explicit);
|
|
154
|
-
}
|
|
155
|
-
if (String(env.CURSOR_TRACE_ID || "").trim()) {
|
|
156
|
-
return resolveCodingAgent("cursor");
|
|
157
|
-
}
|
|
158
|
-
return resolveCodingAgent(DEFAULT_CODING_AGENT_ID);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function listSupportedIdes() {
|
|
162
|
-
return Object.entries(SUPPORTED_IDE_TABLE).map(([id, record]) => ({
|
|
163
|
-
id,
|
|
164
|
-
name: record.name,
|
|
165
|
-
}));
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function detectIdeFromEnv(env = process.env) {
|
|
169
|
-
for (const id of IDE_DETECTION_ORDER) {
|
|
170
|
-
const entry = SUPPORTED_IDE_TABLE[id];
|
|
171
|
-
if (entry && typeof entry.detect === "function" && entry.detect(env)) {
|
|
172
|
-
return {
|
|
173
|
-
id,
|
|
174
|
-
name: entry.name,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return {
|
|
179
|
-
id: DEFAULT_IDE_ID,
|
|
180
|
-
name: SUPPORTED_IDE_TABLE[DEFAULT_IDE_ID].name,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
1
|
+
const SUPPORTED_CODING_AGENT_TABLE = Object.freeze({
|
|
2
|
+
"claude-code": Object.freeze({
|
|
3
|
+
name: "Claude Code",
|
|
4
|
+
promptTarget: "claude",
|
|
5
|
+
configFile: "CLAUDE.md",
|
|
6
|
+
configDir: ".claude/",
|
|
7
|
+
}),
|
|
8
|
+
cursor: Object.freeze({
|
|
9
|
+
name: "Cursor",
|
|
10
|
+
promptTarget: "cursor",
|
|
11
|
+
configFile: ".cursorrules",
|
|
12
|
+
configDir: ".cursor/",
|
|
13
|
+
}),
|
|
14
|
+
copilot: Object.freeze({
|
|
15
|
+
name: "GitHub Copilot",
|
|
16
|
+
promptTarget: "copilot",
|
|
17
|
+
configFile: ".github/copilot-instructions.md",
|
|
18
|
+
configDir: ".github/",
|
|
19
|
+
}),
|
|
20
|
+
windsurf: Object.freeze({
|
|
21
|
+
name: "Windsurf",
|
|
22
|
+
promptTarget: "generic",
|
|
23
|
+
configFile: ".windsurfrules",
|
|
24
|
+
configDir: null,
|
|
25
|
+
}),
|
|
26
|
+
cody: Object.freeze({
|
|
27
|
+
name: "Sourcegraph Cody",
|
|
28
|
+
promptTarget: "generic",
|
|
29
|
+
configFile: ".cody/cody.json",
|
|
30
|
+
configDir: ".cody/",
|
|
31
|
+
}),
|
|
32
|
+
aider: Object.freeze({
|
|
33
|
+
name: "Aider",
|
|
34
|
+
promptTarget: "generic",
|
|
35
|
+
configFile: ".aider.conf.yml",
|
|
36
|
+
configDir: null,
|
|
37
|
+
}),
|
|
38
|
+
continue: Object.freeze({
|
|
39
|
+
name: "Continue",
|
|
40
|
+
promptTarget: "generic",
|
|
41
|
+
configFile: ".continue/config.json",
|
|
42
|
+
configDir: ".continue/",
|
|
43
|
+
}),
|
|
44
|
+
codex: Object.freeze({
|
|
45
|
+
name: "OpenAI Codex",
|
|
46
|
+
promptTarget: "codex",
|
|
47
|
+
configFile: "AGENTS.md",
|
|
48
|
+
configDir: null,
|
|
49
|
+
}),
|
|
50
|
+
bolt: Object.freeze({
|
|
51
|
+
name: "Bolt.new",
|
|
52
|
+
promptTarget: "generic",
|
|
53
|
+
configFile: null,
|
|
54
|
+
configDir: null,
|
|
55
|
+
}),
|
|
56
|
+
generic: Object.freeze({
|
|
57
|
+
name: "Other",
|
|
58
|
+
promptTarget: "generic",
|
|
59
|
+
configFile: null,
|
|
60
|
+
configDir: null,
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const SUPPORTED_IDE_TABLE = Object.freeze({
|
|
65
|
+
vscode: Object.freeze({
|
|
66
|
+
name: "VS Code",
|
|
67
|
+
detect: (env) =>
|
|
68
|
+
String(env.TERM_PROGRAM || "").toLowerCase().includes("vscode") &&
|
|
69
|
+
!String(env.CURSOR_TRACE_ID || "").trim(),
|
|
70
|
+
}),
|
|
71
|
+
cursor: Object.freeze({
|
|
72
|
+
name: "Cursor",
|
|
73
|
+
detect: (env) => Boolean(String(env.CURSOR_TRACE_ID || "").trim()),
|
|
74
|
+
}),
|
|
75
|
+
jetbrains: Object.freeze({
|
|
76
|
+
name: "JetBrains",
|
|
77
|
+
detect: (env) => Boolean(String(env.JETBRAINS_IDE || "").trim()),
|
|
78
|
+
}),
|
|
79
|
+
neovim: Object.freeze({
|
|
80
|
+
name: "Neovim",
|
|
81
|
+
detect: (env) => Boolean(String(env.NVIM || "").trim()),
|
|
82
|
+
}),
|
|
83
|
+
zed: Object.freeze({
|
|
84
|
+
name: "Zed",
|
|
85
|
+
detect: (env) => String(env.TERM_PROGRAM || "").trim().toLowerCase() === "zed",
|
|
86
|
+
}),
|
|
87
|
+
sublime: Object.freeze({
|
|
88
|
+
name: "Sublime Text",
|
|
89
|
+
detect: (env) => Boolean(String(env.SUBLIME_TEXT || "").trim()),
|
|
90
|
+
}),
|
|
91
|
+
vim: Object.freeze({
|
|
92
|
+
name: "Vim",
|
|
93
|
+
detect: (env) => Boolean(String(env.VIM || "").trim()),
|
|
94
|
+
}),
|
|
95
|
+
emacs: Object.freeze({
|
|
96
|
+
name: "Emacs",
|
|
97
|
+
detect: (env) => Boolean(String(env.INSIDE_EMACS || "").trim()),
|
|
98
|
+
}),
|
|
99
|
+
terminal: Object.freeze({
|
|
100
|
+
name: "Terminal",
|
|
101
|
+
detect: () => true,
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const IDE_DETECTION_ORDER = Object.freeze([
|
|
106
|
+
"cursor",
|
|
107
|
+
"vscode",
|
|
108
|
+
"jetbrains",
|
|
109
|
+
"neovim",
|
|
110
|
+
"zed",
|
|
111
|
+
"sublime",
|
|
112
|
+
"vim",
|
|
113
|
+
"emacs",
|
|
114
|
+
"terminal",
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
export const DEFAULT_CODING_AGENT_ID = "generic";
|
|
118
|
+
export const DEFAULT_IDE_ID = "terminal";
|
|
119
|
+
|
|
120
|
+
export const SUPPORTED_CODING_AGENTS = SUPPORTED_CODING_AGENT_TABLE;
|
|
121
|
+
export const SUPPORTED_IDES = SUPPORTED_IDE_TABLE;
|
|
122
|
+
|
|
123
|
+
function normalizeKey(value) {
|
|
124
|
+
return String(value || "")
|
|
125
|
+
.trim()
|
|
126
|
+
.toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function listSupportedCodingAgents() {
|
|
130
|
+
return Object.entries(SUPPORTED_CODING_AGENT_TABLE).map(([id, record]) => ({
|
|
131
|
+
id,
|
|
132
|
+
...record,
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function resolveCodingAgent(agentId = DEFAULT_CODING_AGENT_ID) {
|
|
137
|
+
const normalized = normalizeKey(agentId) || DEFAULT_CODING_AGENT_ID;
|
|
138
|
+
const record = SUPPORTED_CODING_AGENT_TABLE[normalized];
|
|
139
|
+
if (!record) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Unsupported coding agent '${agentId}'. Use one of: ${Object.keys(SUPPORTED_CODING_AGENT_TABLE).join(", ")}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
id: normalized,
|
|
146
|
+
...record,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function detectCodingAgentFromEnv(env = process.env) {
|
|
151
|
+
const explicit = normalizeKey(env.SENTINELAYER_CODING_AGENT || env.CODING_AGENT || "");
|
|
152
|
+
if (explicit && Object.prototype.hasOwnProperty.call(SUPPORTED_CODING_AGENT_TABLE, explicit)) {
|
|
153
|
+
return resolveCodingAgent(explicit);
|
|
154
|
+
}
|
|
155
|
+
if (String(env.CURSOR_TRACE_ID || "").trim()) {
|
|
156
|
+
return resolveCodingAgent("cursor");
|
|
157
|
+
}
|
|
158
|
+
return resolveCodingAgent(DEFAULT_CODING_AGENT_ID);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function listSupportedIdes() {
|
|
162
|
+
return Object.entries(SUPPORTED_IDE_TABLE).map(([id, record]) => ({
|
|
163
|
+
id,
|
|
164
|
+
name: record.name,
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function detectIdeFromEnv(env = process.env) {
|
|
169
|
+
for (const id of IDE_DETECTION_ORDER) {
|
|
170
|
+
const entry = SUPPORTED_IDE_TABLE[id];
|
|
171
|
+
if (entry && typeof entry.detect === "function" && entry.detect(env)) {
|
|
172
|
+
return {
|
|
173
|
+
id,
|
|
174
|
+
name: entry.name,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
id: DEFAULT_IDE_ID,
|
|
180
|
+
name: SUPPORTED_IDE_TABLE[DEFAULT_IDE_ID].name,
|
|
181
|
+
};
|
|
182
|
+
}
|
package/src/config/io.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import fsp from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
import { parse, stringify } from "yaml";
|
|
5
|
-
|
|
6
|
-
import { configSchema } from "./schema.js";
|
|
7
|
-
|
|
8
|
-
function parseConfigObject(raw, filePath) {
|
|
9
|
-
const parsed = parse(raw);
|
|
10
|
-
if (parsed === null || parsed === undefined) {
|
|
11
|
-
return {};
|
|
12
|
-
}
|
|
13
|
-
if (typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
14
|
-
throw new Error(`Config at ${filePath} must be a YAML mapping/object.`);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const normalized = configSchema.safeParse(parsed);
|
|
18
|
-
if (!normalized.success) {
|
|
19
|
-
throw new Error(`Invalid config at ${filePath}: ${normalized.error.issues[0]?.message || "schema error"}`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return normalized.data;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function readConfigFile(filePath) {
|
|
26
|
-
try {
|
|
27
|
-
const raw = await fsp.readFile(filePath, "utf-8");
|
|
28
|
-
if (!String(raw || "").trim()) {
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
return parseConfigObject(raw, filePath);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
if (error && error.code === "ENOENT") {
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function writeConfigFile(filePath, data) {
|
|
41
|
-
const normalized = configSchema.parse(data || {});
|
|
42
|
-
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
43
|
-
await fsp.writeFile(filePath, stringify(normalized), "utf-8");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function ensureConfigFile(filePath) {
|
|
47
|
-
try {
|
|
48
|
-
await fsp.access(filePath);
|
|
49
|
-
} catch (error) {
|
|
50
|
-
if (error && error.code === "ENOENT") {
|
|
51
|
-
await writeConfigFile(filePath, {});
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
import fsp from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
|
|
6
|
+
import { configSchema } from "./schema.js";
|
|
7
|
+
|
|
8
|
+
function parseConfigObject(raw, filePath) {
|
|
9
|
+
const parsed = parse(raw);
|
|
10
|
+
if (parsed === null || parsed === undefined) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
if (typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
14
|
+
throw new Error(`Config at ${filePath} must be a YAML mapping/object.`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const normalized = configSchema.safeParse(parsed);
|
|
18
|
+
if (!normalized.success) {
|
|
19
|
+
throw new Error(`Invalid config at ${filePath}: ${normalized.error.issues[0]?.message || "schema error"}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return normalized.data;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function readConfigFile(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
const raw = await fsp.readFile(filePath, "utf-8");
|
|
28
|
+
if (!String(raw || "").trim()) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
return parseConfigObject(raw, filePath);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error && error.code === "ENOENT") {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function writeConfigFile(filePath, data) {
|
|
41
|
+
const normalized = configSchema.parse(data || {});
|
|
42
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
43
|
+
await fsp.writeFile(filePath, stringify(normalized), "utf-8");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function ensureConfigFile(filePath) {
|
|
47
|
+
try {
|
|
48
|
+
await fsp.access(filePath);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error && error.code === "ENOENT") {
|
|
51
|
+
await writeConfigFile(filePath, {});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/config/paths.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import process from "node:process";
|
|
4
|
-
|
|
5
|
-
export function getGlobalConfigPath({ homeDir = os.homedir() } = {}) {
|
|
6
|
-
return path.join(homeDir, ".sentinelayer", "config.yml");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function getProjectConfigPath({ cwd = process.cwd() } = {}) {
|
|
10
|
-
return path.join(path.resolve(cwd), ".sentinelayer.yml");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function getConfigPaths({ cwd = process.cwd(), homeDir } = {}) {
|
|
14
|
-
return {
|
|
15
|
-
global: getGlobalConfigPath({ homeDir }),
|
|
16
|
-
project: getProjectConfigPath({ cwd }),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
|
|
5
|
+
export function getGlobalConfigPath({ homeDir = os.homedir() } = {}) {
|
|
6
|
+
return path.join(homeDir, ".sentinelayer", "config.yml");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getProjectConfigPath({ cwd = process.cwd() } = {}) {
|
|
10
|
+
return path.join(path.resolve(cwd), ".sentinelayer.yml");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getConfigPaths({ cwd = process.cwd(), homeDir } = {}) {
|
|
14
|
+
return {
|
|
15
|
+
global: getGlobalConfigPath({ homeDir }),
|
|
16
|
+
project: getProjectConfigPath({ cwd }),
|
|
17
|
+
};
|
|
18
|
+
}
|
package/src/config/schema.js
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
function emptyToUndefined(value) {
|
|
4
|
-
if (value === null || value === undefined) {
|
|
5
|
-
return undefined;
|
|
6
|
-
}
|
|
7
|
-
const normalized = String(value).trim();
|
|
8
|
-
return normalized ? normalized : undefined;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const optionalTrimmedString = z.preprocess(emptyToUndefined, z.string().min(1)).optional();
|
|
12
|
-
const optionalUrl = z.preprocess(emptyToUndefined, z.string().url()).optional();
|
|
13
|
-
const optionalStringArray = z
|
|
14
|
-
.array(z.preprocess(emptyToUndefined, z.string().min(1)))
|
|
15
|
-
.optional();
|
|
16
|
-
|
|
17
|
-
const alertsChannelSchema = z
|
|
18
|
-
.object({
|
|
19
|
-
type: optionalTrimmedString,
|
|
20
|
-
webhook_url: optionalTrimmedString,
|
|
21
|
-
webhookUrl: optionalTrimmedString,
|
|
22
|
-
url: optionalTrimmedString,
|
|
23
|
-
bot_token: optionalTrimmedString,
|
|
24
|
-
botToken: optionalTrimmedString,
|
|
25
|
-
chat_id: optionalTrimmedString,
|
|
26
|
-
chatId: optionalTrimmedString,
|
|
27
|
-
})
|
|
28
|
-
.passthrough();
|
|
29
|
-
|
|
30
|
-
const alertsConfigSchema = z
|
|
31
|
-
.object({
|
|
32
|
-
channels: z.array(alertsChannelSchema).optional(),
|
|
33
|
-
frequency: optionalTrimmedString,
|
|
34
|
-
events: optionalStringArray,
|
|
35
|
-
})
|
|
36
|
-
.passthrough()
|
|
37
|
-
.optional();
|
|
38
|
-
|
|
39
|
-
export const configSchema = z
|
|
40
|
-
.object({
|
|
41
|
-
apiUrl: optionalUrl,
|
|
42
|
-
webUrl: optionalUrl,
|
|
43
|
-
outputDir: optionalTrimmedString,
|
|
44
|
-
defaultPolicyPack: optionalTrimmedString,
|
|
45
|
-
defaultModelProvider: z.enum(["openai", "anthropic", "google"]).optional(),
|
|
46
|
-
defaultModelId: optionalTrimmedString,
|
|
47
|
-
sentinelayerToken: optionalTrimmedString,
|
|
48
|
-
openaiApiKey: optionalTrimmedString,
|
|
49
|
-
anthropicApiKey: optionalTrimmedString,
|
|
50
|
-
googleApiKey: optionalTrimmedString,
|
|
51
|
-
alerts: alertsConfigSchema,
|
|
52
|
-
})
|
|
53
|
-
.strict();
|
|
54
|
-
|
|
55
|
-
export const CONFIG_KEYS = Object.freeze(Object.keys(configSchema.shape));
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
function emptyToUndefined(value) {
|
|
4
|
+
if (value === null || value === undefined) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const normalized = String(value).trim();
|
|
8
|
+
return normalized ? normalized : undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const optionalTrimmedString = z.preprocess(emptyToUndefined, z.string().min(1)).optional();
|
|
12
|
+
const optionalUrl = z.preprocess(emptyToUndefined, z.string().url()).optional();
|
|
13
|
+
const optionalStringArray = z
|
|
14
|
+
.array(z.preprocess(emptyToUndefined, z.string().min(1)))
|
|
15
|
+
.optional();
|
|
16
|
+
|
|
17
|
+
const alertsChannelSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
type: optionalTrimmedString,
|
|
20
|
+
webhook_url: optionalTrimmedString,
|
|
21
|
+
webhookUrl: optionalTrimmedString,
|
|
22
|
+
url: optionalTrimmedString,
|
|
23
|
+
bot_token: optionalTrimmedString,
|
|
24
|
+
botToken: optionalTrimmedString,
|
|
25
|
+
chat_id: optionalTrimmedString,
|
|
26
|
+
chatId: optionalTrimmedString,
|
|
27
|
+
})
|
|
28
|
+
.passthrough();
|
|
29
|
+
|
|
30
|
+
const alertsConfigSchema = z
|
|
31
|
+
.object({
|
|
32
|
+
channels: z.array(alertsChannelSchema).optional(),
|
|
33
|
+
frequency: optionalTrimmedString,
|
|
34
|
+
events: optionalStringArray,
|
|
35
|
+
})
|
|
36
|
+
.passthrough()
|
|
37
|
+
.optional();
|
|
38
|
+
|
|
39
|
+
export const configSchema = z
|
|
40
|
+
.object({
|
|
41
|
+
apiUrl: optionalUrl,
|
|
42
|
+
webUrl: optionalUrl,
|
|
43
|
+
outputDir: optionalTrimmedString,
|
|
44
|
+
defaultPolicyPack: optionalTrimmedString,
|
|
45
|
+
defaultModelProvider: z.enum(["openai", "anthropic", "google"]).optional(),
|
|
46
|
+
defaultModelId: optionalTrimmedString,
|
|
47
|
+
sentinelayerToken: optionalTrimmedString,
|
|
48
|
+
openaiApiKey: optionalTrimmedString,
|
|
49
|
+
anthropicApiKey: optionalTrimmedString,
|
|
50
|
+
googleApiKey: optionalTrimmedString,
|
|
51
|
+
alerts: alertsConfigSchema,
|
|
52
|
+
})
|
|
53
|
+
.strict();
|
|
54
|
+
|
|
55
|
+
export const CONFIG_KEYS = Object.freeze(Object.keys(configSchema.shape));
|