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.
Files changed (133) hide show
  1. package/README.md +47 -3
  2. package/package.json +12 -7
  3. package/skills/omar-gate-setup/SKILL.md +103 -0
  4. package/skills/senti-agent-identity/SKILL.md +80 -0
  5. package/skills/senti-judge/SKILL.md +139 -0
  6. package/skills/senti-room-notifications/SKILL.md +73 -0
  7. package/skills/senti-room-notifications/listen-wrapper.cjs +150 -0
  8. package/skills/senti-room-notifications/package.json +1 -0
  9. package/skills/senti-room-notifications/test-classifier.js +109 -0
  10. package/skills/senti-room-notifications/test-receipt.js +54 -0
  11. package/skills/sentinelayer-cli/SKILL.md +222 -0
  12. package/src/agents/devtestbot/runner.js +22 -11
  13. package/src/agents/devtestbot/tool.js +24 -11
  14. package/src/agents/jules/fix-cycle.js +7 -1
  15. package/src/agents/jules/tools/runtime-audit.js +17 -12
  16. package/src/agents/shared-tools/dispatch-core.js +10 -5
  17. package/src/ai/aidenid.js +4 -2
  18. package/src/ai/domain-target-store.js +11 -5
  19. package/src/ai/identity-store.js +11 -5
  20. package/src/ai/site-store.js +8 -4
  21. package/src/audit/orchestrator.js +21 -14
  22. package/src/audit/package.js +6 -4
  23. package/src/audit/persona-loop.js +7 -0
  24. package/src/audit/replay.js +4 -2
  25. package/src/auth/gate.js +32 -1
  26. package/src/auth/session-store.js +37 -0
  27. package/src/board/evidence-resolvers.js +3 -4
  28. package/src/cli.js +23 -3
  29. package/src/commands/ai/identity-lifecycle.js +30 -26
  30. package/src/commands/ai/provision-governance.js +32 -24
  31. package/src/commands/ai/shared.js +6 -4
  32. package/src/commands/audit.js +14 -12
  33. package/src/commands/board.js +2 -2
  34. package/src/commands/chat.js +8 -6
  35. package/src/commands/judge.js +125 -0
  36. package/src/commands/legacy-args.js +1 -0
  37. package/src/commands/mcp.js +45 -52
  38. package/src/commands/omargate.js +2 -1
  39. package/src/commands/plugin.js +11 -3
  40. package/src/commands/review.js +9 -4
  41. package/src/commands/scan.js +7 -7
  42. package/src/commands/session.js +516 -30
  43. package/src/commands/skills.js +45 -0
  44. package/src/commands/watch.js +9 -7
  45. package/src/config/output-filesystem.js +156 -0
  46. package/src/config/schema.js +4 -2
  47. package/src/config/service.js +40 -4
  48. package/src/cost/history.js +15 -9
  49. package/src/daemon/artifact-lineage.js +15 -12
  50. package/src/daemon/assignment-ledger.js +31 -25
  51. package/src/daemon/ast-drift.js +7 -3
  52. package/src/daemon/budget-governor.js +26 -20
  53. package/src/daemon/error-worker.js +28 -22
  54. package/src/daemon/fix-cycle.js +5 -4
  55. package/src/daemon/hybrid-mapper.js +19 -16
  56. package/src/daemon/ingest-refresh.js +4 -0
  57. package/src/daemon/jira-lifecycle.js +21 -17
  58. package/src/daemon/operator-control.js +18 -15
  59. package/src/daemon/reliability-lane.js +18 -15
  60. package/src/daemon/scope-engine.js +12 -8
  61. package/src/daemon/watchdog.js +15 -12
  62. package/src/engram/build-state.js +24 -3
  63. package/src/engram/capability-index.js +367 -0
  64. package/src/engram/compile-graph.js +1063 -0
  65. package/src/engram/contracts/action-receipt.js +82 -0
  66. package/src/engram/contracts/capability-index.js +259 -0
  67. package/src/engram/contracts/capability.js +377 -0
  68. package/src/engram/contracts/content-hash.js +8 -0
  69. package/src/engram/contracts/evidence.js +258 -0
  70. package/src/engram/contracts/graph.js +594 -0
  71. package/src/engram/contracts/identity.js +8 -0
  72. package/src/engram/contracts/index.js +149 -0
  73. package/src/engram/contracts/media-asset.js +85 -0
  74. package/src/engram/contracts/money.js +249 -0
  75. package/src/engram/contracts/source-snapshot.js +57 -0
  76. package/src/engram/contracts/task-context-pack.js +114 -0
  77. package/src/engram/contracts/temporal-segment.js +72 -0
  78. package/src/engram/contracts/versions.js +96 -0
  79. package/src/engram/extract-html.js +692 -0
  80. package/src/engram/graph-store.js +877 -0
  81. package/src/engram/index.js +98 -14
  82. package/src/engram/ingest-site.js +132 -0
  83. package/src/engram/live-state.js +1180 -0
  84. package/src/engram/namespace.js +34 -1
  85. package/src/engram/retrieve-site.js +753 -0
  86. package/src/engram/safe-reader.js +597 -0
  87. package/src/engram/source-intake.js +251 -0
  88. package/src/engram/store.js +227 -9
  89. package/src/ingest/engine.js +21 -28
  90. package/src/judge/verdict.js +305 -0
  91. package/src/legacy-cli.js +96 -19
  92. package/src/mcp/bridge-inputs.js +25 -4
  93. package/src/mcp/cli-command-tools.js +70 -0
  94. package/src/mcp/registry.js +17 -13
  95. package/src/mcp/session-stdio-server.js +297 -19
  96. package/src/memory/blackboard.js +5 -4
  97. package/src/net/gh-api-path.js +35 -9
  98. package/src/net/test-egress-guard.js +16 -4
  99. package/src/plugin/manifest.js +12 -8
  100. package/src/review/ai-review.js +110 -10
  101. package/src/review/investor-dd-devtestbot.js +17 -6
  102. package/src/review/investor-dd-orchestrator.js +21 -13
  103. package/src/review/local-review.js +26 -16
  104. package/src/review/omargate-cache.js +5 -5
  105. package/src/review/omargate-orchestrator.js +89 -17
  106. package/src/review/replay.js +9 -4
  107. package/src/review/report.js +22 -13
  108. package/src/review/typesafe-severity.js +201 -0
  109. package/src/session/admission-auth.js +34 -7
  110. package/src/session/admission.js +110 -15
  111. package/src/session/attachment-summary.js +77 -0
  112. package/src/session/edit-summary.js +19 -0
  113. package/src/session/invitations.js +65 -1
  114. package/src/session/mentions.js +17 -9
  115. package/src/session/message-edits.js +5 -4
  116. package/src/session/preview.js +10 -2
  117. package/src/session/recap.js +3 -2
  118. package/src/session/room-files.js +519 -0
  119. package/src/session/route-classes.js +22 -8
  120. package/src/session/setup-guides.js +4 -0
  121. package/src/session/standup.js +192 -0
  122. package/src/session/sync.js +229 -10
  123. package/src/session/tickets.js +41 -0
  124. package/src/session/transcript.js +2 -1
  125. package/src/session/wake/resolve-target.js +7 -3
  126. package/src/skills/listener-runtime.cjs +92 -0
  127. package/src/skills/service.js +207 -0
  128. package/src/swarm/factory.js +5 -5
  129. package/src/swarm/pentest.js +9 -9
  130. package/src/swarm/report.js +4 -4
  131. package/src/swarm/runtime.js +15 -12
  132. package/src/swarm/scenario-dsl.js +7 -5
  133. package/src/telemetry/ledger.js +16 -7
@@ -0,0 +1,82 @@
1
+ /**
2
+ * ENGRAM §EW02 — ActionReceipt contract.
3
+ *
4
+ * An ActionReceipt is a verifiable record of an action taken by an agent or
5
+ * system. It carries a content hash, timestamp, verifier identity, and a
6
+ * source snapshot. Receipts without these fields cannot be used to establish
7
+ * authoritative provenance.
8
+ *
9
+ * The contentHash and verifier fields are claims until an application checks
10
+ * the digest against the actual action payload and authenticates the verifier.
11
+ */
12
+
13
+ import { z } from "zod";
14
+ import { sourceSnapshotSchema } from "./source-snapshot.js";
15
+ import { sha256ContentHashSchema } from "./content-hash.js";
16
+
17
+ export const ACTION_RECEIPT_STATUSES = Object.freeze([
18
+ "executed",
19
+ "failed",
20
+ "pending",
21
+ "rolled_back",
22
+ ]);
23
+
24
+ export const actionReceiptStatusSchema = z.enum([
25
+ "executed",
26
+ "failed",
27
+ "pending",
28
+ "rolled_back",
29
+ ]);
30
+
31
+ /**
32
+ * A verifiable receipt for an action performed in the system.
33
+ *
34
+ * Every receipt carries a content hash over the action payload, the
35
+ * verifier identity, and a source snapshot. The contentHash format is a
36
+ * scheme-prefixed digest (e.g. "sha256:<hex>") for integrity checking;
37
+ * full signature verification is deferred to a future contract version.
38
+ */
39
+ export const actionReceiptSchema = z.object({
40
+ receiptId: z.string().min(1),
41
+ action: z.string().min(1),
42
+ status: actionReceiptStatusSchema,
43
+ performedAt: z.string().datetime(),
44
+ verifier: z.string().min(1),
45
+ contentHash: sha256ContentHashSchema,
46
+ sourceSnapshot: sourceSnapshotSchema,
47
+ tenantScope: z.string().min(1),
48
+ evidenceRefs: z.array(z.string().min(1)).optional(),
49
+ metadata: z.record(z.string(), z.json()).optional(),
50
+ }).strict().refine(
51
+ (data) => {
52
+ // Tenant scope must be consistent with sourceSnapshot.
53
+ if (data.tenantScope !== data.sourceSnapshot.tenantScope) {
54
+ return false;
55
+ }
56
+ return true;
57
+ },
58
+ {
59
+ message: "tenantScope must match sourceSnapshot.tenantScope; cross-tenant requires explicit authorization",
60
+ path: ["tenantScope"],
61
+ },
62
+ );
63
+
64
+ /**
65
+ * Valid fixture: a complete, valid action receipt.
66
+ */
67
+ export const VALID_ACTION_RECEIPT = Object.freeze({
68
+ receiptId: "rec-exec-abc123",
69
+ action: "graph.validate",
70
+ status: "executed",
71
+ performedAt: "2026-10-23T12:00:01Z",
72
+ verifier: "aidenid-verifier-01",
73
+ contentHash: "sha256:nji40eArkmG6ZZyc3Od23mge2TYew/f4vFc/wTBwCOE=",
74
+ sourceSnapshot: {
75
+ sourceId: "src-session-abc123",
76
+ sourceType: "session",
77
+ version: "1.2.0",
78
+ capturedAt: "2026-10-23T12:00:00Z",
79
+ tenantScope: "tenant/acme",
80
+ },
81
+ tenantScope: "tenant/acme",
82
+ });
@@ -0,0 +1,259 @@
1
+ /**
2
+ * ENGRAM §EW08 — Capability Index and Skill Descriptor contracts.
3
+ *
4
+ * Defines:
5
+ * - skillSchema: a single capability skill descriptor (MCP-tool-compatible)
6
+ * - capabilityIndexSchema: a deterministic, versioned, digest-signed index
7
+ * of all advertised skills for a publisher origin.
8
+ *
9
+ * Every skill in the index maps onto an MCP tool descriptor unchanged so a
10
+ * later MCP adapter (EW20) reuses it. The index carries a sha256 digest over
11
+ * the canonical JSON of its body (sans the digest field) so a consumer can
12
+ * verify integrity without trusting the transport.
13
+ *
14
+ * All schemas are strict: extra fields are rejected.
15
+ */
16
+
17
+ import { z } from "zod";
18
+ import { capabilityVersionSchema } from "./capability.js";
19
+ import { sha256ContentHashSchema } from "./content-hash.js";
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Skill descriptor
23
+ // ---------------------------------------------------------------------------
24
+
25
+ /** Valid scope values for a skill. */
26
+ const SKILL_SCOPE = z.enum(["read", "write"]);
27
+
28
+ /** Valid side-effect classifications. */
29
+ const SKILL_SIDE_EFFECTS = z.enum(["none", "simulated", "real"]);
30
+
31
+ /** Valid visibility levels. */
32
+ const SKILL_VISIBILITY = z.enum(["public", "private"]);
33
+
34
+ /**
35
+ * A bounded text field: plain text, no control characters, size-capped.
36
+ * MCP tools have titles and descriptions; this is the ENGRAM equivalent
37
+ * for a skill descriptor that can be projected onto a tool unchanged.
38
+ */
39
+ const boundedTextField = (maxLen, label) =>
40
+ z.string()
41
+ .min(1, `${label} must not be empty`)
42
+ .max(maxLen, `${label} exceeds ${maxLen} characters`)
43
+ .refine((s) => !/[\u0000-\u001f\u007f-\u009f]/.test(s), {
44
+ message: `${label} must not contain control characters`,
45
+ });
46
+
47
+ /**
48
+ * A single capability skill descriptor.
49
+ *
50
+ * Fields project directly onto MCP tool annotations:
51
+ * - name + title + description → tool identity
52
+ * - inputSchema / outputSchema → JSON Schema objects (size-bounded)
53
+ * - readOnlyHint / destructiveHint / idempotentHint → scope + sideEffects
54
+ * - requiresConfirmation → a client UX gate
55
+ * - fallback → what to show when the capability is unavailable
56
+ *
57
+ * Private skills are NEVER included in a public index.
58
+ */
59
+ export const skillSchema = z.object({
60
+ capability: z.string().regex(/^[a-z][a-z0-9_-]{0,47}$/),
61
+ version: capabilityVersionSchema,
62
+ title: boundedTextField(128, "title"),
63
+ purpose: boundedTextField(1024, "purpose"),
64
+ inputSchema: z.record(z.unknown()).refine(
65
+ (s) => JSON.stringify(s).length <= 8192,
66
+ { message: "inputSchema JSON must not exceed 8192 bytes" },
67
+ ),
68
+ outputSchema: z.record(z.unknown()).refine(
69
+ (s) => JSON.stringify(s).length <= 8192,
70
+ { message: "outputSchema JSON must not exceed 8192 bytes" },
71
+ ),
72
+ scope: SKILL_SCOPE,
73
+ sideEffects: SKILL_SIDE_EFFECTS,
74
+ requiresConfirmation: z.boolean(),
75
+ fallback: z.string().max(2048).optional(),
76
+ visibility: SKILL_VISIBILITY,
77
+ }).strict().superRefine((skill, ctx) => {
78
+ if (!versionNameMatches(skill.capability, skill.version)) {
79
+ ctx.addIssue({
80
+ code: "custom",
81
+ path: ["version"],
82
+ message: "version name must match capability",
83
+ });
84
+ }
85
+ });
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Capability index
89
+ // ---------------------------------------------------------------------------
90
+
91
+ /**
92
+ * A publisher origin: an https origin with no path, query, or fragment.
93
+ */
94
+ const publisherOriginSchema = z.string().refine((s) => {
95
+ try {
96
+ const u = new URL(s);
97
+ return (
98
+ u.protocol === "https:" &&
99
+ u.hostname.length > 0 &&
100
+ u.pathname === "/" &&
101
+ u.search === "" &&
102
+ u.hash === "" &&
103
+ u.username === "" &&
104
+ u.password === ""
105
+ );
106
+ } catch {
107
+ return false;
108
+ }
109
+ }, { message: "publisherOrigin must be an https origin with no path" });
110
+
111
+ /**
112
+ * An ISO-8601 datetime string in UTC (must end with Z).
113
+ */
114
+ const utcDatetimeSchema = z.string().refine(
115
+ (s) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(s),
116
+ { message: "datetime must be ISO-8601 in UTC (ending with Z)" },
117
+ );
118
+
119
+ /**
120
+ * A deterministic capability index for a publisher origin.
121
+ *
122
+ * Layout:
123
+ * - publisherOrigin: who published this index (https origin)
124
+ * - indexVersion: monotonic version of the index format
125
+ * - issuedAt / expiresAt: validity window
126
+ * - revoked: list of capability versions that are no longer valid
127
+ * - skills: only public, implemented skills sorted by capability name
128
+ * - digest: sha256 of the canonical JSON of the index WITHOUT this field
129
+ *
130
+ * The digest lets a consumer verify the index is intact: strip digest,
131
+ * canonicalize, sha256, compare. If they don't match, the index is tampered
132
+ * or corrupted.
133
+ */
134
+ export const capabilityIndexSchema = z.object({
135
+ publisherOrigin: publisherOriginSchema,
136
+ indexVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
137
+ issuedAt: utcDatetimeSchema,
138
+ expiresAt: utcDatetimeSchema,
139
+ revoked: z.array(capabilityVersionSchema).default([]),
140
+ skills: z.array(skillSchema),
141
+ digest: sha256ContentHashSchema,
142
+ }).strict().superRefine((index, ctx) => {
143
+ // Every revoked entry must correspond to a version of a capability that
144
+ // exists (or existed) — validate the format at minimum.
145
+ for (let i = 0; i < index.revoked.length; i++) {
146
+ const r = index.revoked[i];
147
+ if (!capabilityVersionSchema.safeParse(r).success) {
148
+ ctx.addIssue({
149
+ code: "custom",
150
+ path: ["revoked", i],
151
+ message: `revoked entry "${r}" is not a valid capability version`,
152
+ });
153
+ }
154
+ }
155
+
156
+ // Skills must be sorted by capability name (deterministic output).
157
+ for (let i = 1; i < index.skills.length; i++) {
158
+ if (index.skills[i].capability < index.skills[i - 1].capability) {
159
+ ctx.addIssue({
160
+ code: "custom",
161
+ path: ["skills", i],
162
+ message: "skills must be sorted by capability name",
163
+ });
164
+ break;
165
+ }
166
+ }
167
+
168
+ // No private skills in a published index.
169
+ for (let i = 0; i < index.skills.length; i++) {
170
+ if (index.skills[i].visibility === "private") {
171
+ ctx.addIssue({
172
+ code: "custom",
173
+ path: ["skills", i, "visibility"],
174
+ message: "private skills must not appear in a published index",
175
+ });
176
+ break;
177
+ }
178
+ }
179
+
180
+ // expiresAt must be after issuedAt.
181
+ if (new Date(index.expiresAt) <= new Date(index.issuedAt)) {
182
+ ctx.addIssue({
183
+ code: "custom",
184
+ path: ["expiresAt"],
185
+ message: "expiresAt must be after issuedAt",
186
+ });
187
+ }
188
+ });
189
+
190
+ // ---------------------------------------------------------------------------
191
+ // Helpers
192
+ // ---------------------------------------------------------------------------
193
+
194
+ /**
195
+ * Check that a capability version's name prefix matches the expected
196
+ * capability name.
197
+ */
198
+ function versionNameMatches(capability, version) {
199
+ const parts = parseCapVersion(version);
200
+ return parts !== null && parts[0] === capability;
201
+ }
202
+
203
+ /**
204
+ * Parse a capability version string into [name, major, minor, patch].
205
+ * Returns null if the string does not match.
206
+ */
207
+ function parseCapVersion(v) {
208
+ if (typeof v !== "string") return null;
209
+ const m = v.match(
210
+ /^([a-z][a-z0-9_-]{0,47})@(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/,
211
+ );
212
+ if (!m) return null;
213
+ return [m[1], Number(m[2]), Number(m[3]), Number(m[4])];
214
+ }
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // Errors
218
+ // ---------------------------------------------------------------------------
219
+
220
+ /** Base error for capability index operations. */
221
+ export class CapabilityIndexError extends Error {
222
+ constructor(message, evidence) {
223
+ super(message);
224
+ this.name = "CapabilityIndexError";
225
+ this.evidence = evidence ?? null;
226
+ }
227
+ }
228
+
229
+ /** The index digest does not match the computed digest over the body. */
230
+ export function digestMismatch(expected, actual, evidence) {
231
+ return new CapabilityIndexError(
232
+ `digest mismatch: expected ${expected}, computed ${actual}`,
233
+ evidence,
234
+ );
235
+ }
236
+
237
+ /** The index has expired. */
238
+ export function indexExpired(expiresAt, now, evidence) {
239
+ return new CapabilityIndexError(
240
+ `index expired at ${expiresAt} (now: ${now})`,
241
+ evidence,
242
+ );
243
+ }
244
+
245
+ /** The index publisher origin does not match the expected origin. */
246
+ export function originMismatch(expected, actual, evidence) {
247
+ return new CapabilityIndexError(
248
+ `origin mismatch: expected ${expected}, got ${actual}`,
249
+ evidence,
250
+ );
251
+ }
252
+
253
+ /** A requested capability has been revoked. */
254
+ export function capabilityRevoked(capability, version, evidence) {
255
+ return new CapabilityIndexError(
256
+ `capability ${capability} version ${version} has been revoked`,
257
+ evidence,
258
+ );
259
+ }