@askexenow/exe-os 0.9.289 → 0.9.290
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/dist/active-agent-L22OENGJ.js +26 -0
- package/dist/active-agent-SVG6F6HY.js +27 -0
- package/dist/agentic-ontology-3GHJHLDY.js +25 -0
- package/dist/backfill-metadata-HJNVBORD.js +599 -0
- package/dist/behaviors-ROOZS234.js +39 -0
- package/dist/bin/agentic-ontology-backfill.js +5 -5
- package/dist/bin/agentic-reflection-backfill.js +6 -6
- package/dist/bin/agentic-semantic-label.js +5 -5
- package/dist/bin/backfill-conversations.js +4 -4
- package/dist/bin/backfill-responses.js +4 -4
- package/dist/bin/backfill-vectors.js +98 -13
- package/dist/bin/bulk-sync-postgres.js +6 -6
- package/dist/bin/cc-doctor.js +4 -4
- package/dist/bin/cleanup-stale-review-tasks.js +9 -9
- package/dist/bin/cli.js +51 -15
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +5 -5
- package/dist/bin/exe-boot.js +16 -16
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +23 -5
- package/dist/bin/exe-dispatch.js +9 -9
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +7 -7
- package/dist/bin/exe-healthcheck.js +4 -4
- package/dist/bin/exe-heartbeat.js +9 -9
- package/dist/bin/exe-kill.js +12 -12
- package/dist/bin/exe-launch-agent.js +16 -16
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +10 -10
- package/dist/bin/exe-pending-notifications.js +9 -9
- package/dist/bin/exe-pending-reviews.js +9 -9
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +11 -11
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +14 -14
- package/dist/bin/exe-settings.js +4 -4
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +10 -10
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/git-sweep.js +10 -10
- package/dist/bin/graph-backfill.js +4 -4
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/import-history.js +7 -7
- package/dist/bin/install.js +6 -6
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/scan-tasks.js +9 -9
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/capability-cards-O6XB2AU4.js +88 -0
- package/dist/capacity-monitor-ZE7CFVWH.js +50 -0
- package/dist/catchup-brief-3NONSIMA.js +174 -0
- package/dist/chunk-232DHK5C.js +1119 -0
- package/dist/chunk-272SJ4RN.js +129 -0
- package/dist/chunk-4NMTGHUE.js +127 -0
- package/dist/chunk-5PLW3QL6.js +668 -0
- package/dist/chunk-66EIYAF2.js +157 -0
- package/dist/chunk-6IPJF5QD.js +630 -0
- package/dist/chunk-6NSJTOXE.js +122 -0
- package/dist/chunk-6TLURATK.js +4318 -0
- package/dist/chunk-73JAJQRY.js +85 -0
- package/dist/chunk-7FTKXL5A.js +286 -0
- package/dist/chunk-7IRQSO3F.js +735 -0
- package/dist/chunk-7MINWZ3J.js +214 -0
- package/dist/chunk-7T5PS5DG.js +14439 -0
- package/dist/chunk-A74WXY4S.js +227 -0
- package/dist/chunk-AVD5C3NG.js +197 -0
- package/dist/chunk-B36MRLEP.js +58 -0
- package/dist/chunk-B4TCZ3PS.js +373 -0
- package/dist/chunk-BPLEJ3EU.js +411 -0
- package/dist/chunk-BTDPLFGK.js +221 -0
- package/dist/chunk-BU45UYTK.js +185 -0
- package/dist/chunk-CCAA6XOZ.js +284 -0
- package/dist/chunk-DBQ6I6K2.js +3276 -0
- package/dist/chunk-DDWFHEPG.js +345 -0
- package/dist/chunk-DSOKTUTT.js +167 -0
- package/dist/chunk-ETCARC76.js +836 -0
- package/dist/chunk-EZHTLPOS.js +280 -0
- package/dist/chunk-F3DQ3HDH.js +333 -0
- package/dist/chunk-F6ZCUDCN.js +244 -0
- package/dist/chunk-FI5Q6F5S.js +382 -0
- package/dist/chunk-FNQZGNSG.js +1094 -0
- package/dist/chunk-FVKTXXKK.js +128 -0
- package/dist/chunk-HHR5NB6N.js +377 -0
- package/dist/chunk-HRZLGHT6.js +290 -0
- package/dist/chunk-HSSRWMVA.js +68 -0
- package/dist/chunk-I3NVB5MG.js +85 -0
- package/dist/chunk-I7Z6MK2B.js +240 -0
- package/dist/chunk-ID4SMRYX.js +2078 -0
- package/dist/chunk-JXGHDROV.js +546 -0
- package/dist/chunk-KQY4QIEN.js +731 -0
- package/dist/chunk-LRSU2ZU2.js +38 -0
- package/dist/chunk-MFCL4GAN.js +2113 -0
- package/dist/chunk-MFGMVKGM.js +150 -0
- package/dist/chunk-NHGBVLCD.js +210 -0
- package/dist/chunk-NOEBJMNN.js +33 -0
- package/dist/chunk-NQ2VNTGL.js +538 -0
- package/dist/chunk-O4PZPM6H.js +204 -0
- package/dist/chunk-O5OW3YGQ.js +262 -0
- package/dist/chunk-OJQTONDJ.js +171 -0
- package/dist/chunk-OKZGUHE5.js +76 -0
- package/dist/chunk-OOH5M36Q.js +448 -0
- package/dist/chunk-P5ARTZP2.js +128 -0
- package/dist/chunk-PKRSYS7F.js +402 -0
- package/dist/chunk-PQWO5D3F.js +348 -0
- package/dist/chunk-Q6MJIJ2O.js +1352 -0
- package/dist/chunk-QKDRYZ2N.js +231 -0
- package/dist/chunk-RAV356E6.js +30 -0
- package/dist/chunk-RK7EAA53.js +1157 -0
- package/dist/chunk-RSLVAYWS.js +192 -0
- package/dist/chunk-SL6WJP2Q.js +123 -0
- package/dist/chunk-T57DOVGE.js +97 -0
- package/dist/chunk-TMCKL43Q.js +181 -0
- package/dist/chunk-TQZABASE.js +97 -0
- package/dist/chunk-UBWBEY6I.js +81 -0
- package/dist/chunk-UP7DNYG7.js +456 -0
- package/dist/chunk-V5MGYIZS.js +70 -0
- package/dist/chunk-XCPVYQVK.js +336 -0
- package/dist/chunk-XWVBLZRP.js +50 -0
- package/dist/chunk-YBTN5F2U.js +1068 -0
- package/dist/chunk-Z772TGD2.js +54 -0
- package/dist/chunk-ZAMPIXLH.js +1350 -0
- package/dist/chunk-ZYEOHGU5.js +362 -0
- package/dist/co-activation-WJTFJOTK.js +73 -0
- package/dist/co-occurrence-KFP6ZS7G.js +94 -0
- package/dist/core-memory-DBZJ72TV.js +110 -0
- package/dist/crdt-sync-6DVGRMTV.js +33 -0
- package/dist/crm-webhook-55T4Z6XJ.js +10 -0
- package/dist/cto-delegation-gate-SPM6LAL2.js +279 -0
- package/dist/daemon-orchestration-XZLWWIV4.js +138 -0
- package/dist/db-backup-JHCI47JQ.js +37 -0
- package/dist/doc-graph-extractor-4X23NP4I.js +132 -0
- package/dist/dreaming-TFZDGA72.js +33 -0
- package/dist/exe-drift-TEM7ELNY.js +69 -0
- package/dist/exe-export-CRCA4T4S.js +75 -0
- package/dist/exe-import-UZMMWNHJ.js +78 -0
- package/dist/exe-key-NQQXEDUA.js +672 -0
- package/dist/exe-snapshot-P7PUAJTV.js +337 -0
- package/dist/fast-db-init-G63PRINQ.js +7 -0
- package/dist/gateway/index.js +8 -8
- package/dist/git-staleness-42TTCFDP.js +111 -0
- package/dist/git-task-sweep-4LW5RYYO.js +41 -0
- package/dist/global-procedures-BVFRWJAV.js +21 -0
- package/dist/graph-auto-extract-4ZA7UC6C.js +182 -0
- package/dist/hooks/bug-report-worker.js +11 -11
- package/dist/hooks/codex-stop-task-finalizer.js +11 -11
- package/dist/hooks/commit-complete.js +11 -11
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest.js +6 -6
- package/dist/hooks/instructions-loaded.js +4 -4
- package/dist/hooks/manifest.json +19 -19
- package/dist/hooks/notification.js +4 -4
- package/dist/hooks/post-compact.js +10 -10
- package/dist/hooks/post-tool-combined.js +5 -5
- package/dist/hooks/pre-compact.js +11 -11
- package/dist/hooks/pre-tool-use.js +14 -14
- package/dist/hooks/prompt-submit.js +21 -21
- package/dist/hooks/session-end.js +15 -15
- package/dist/hooks/session-start.js +12 -12
- package/dist/hooks/stop.js +14 -14
- package/dist/hooks/subagent-stop.js +10 -10
- package/dist/hooks/summary-worker.js +14 -14
- package/dist/index.js +17 -17
- package/dist/installer-CBGRTGIF.js +297 -0
- package/dist/installer-DGU4WZKJ.js +39 -0
- package/dist/installer-WTWEOSEK.js +343 -0
- package/dist/lib/cloud-sync.js +4 -4
- package/dist/lib/consolidation.js +7 -5
- package/dist/lib/database.js +2 -2
- package/dist/lib/db.js +2 -2
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon.js +64 -43
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +9 -9
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +5 -5
- package/dist/lib/session-registry.js +4 -4
- package/dist/lib/skill-learning.js +6 -6
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +10 -10
- package/dist/lib/tmux-routing.js +8 -8
- package/dist/lib/token-spend.js +3 -3
- package/dist/license-gate-OSPA2OD7.js +16 -0
- package/dist/mcp/register-tools.js +55 -55
- package/dist/mcp/server.js +117 -73
- package/dist/mcp/tools/complete-reminder.js +4 -4
- package/dist/mcp/tools/create-reminder.js +4 -4
- package/dist/mcp/tools/create-task.js +12 -12
- package/dist/mcp/tools/deactivate-behavior.js +7 -7
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +12 -12
- package/dist/mcp/tools/send-message.js +11 -11
- package/dist/mcp/tools/update-task.js +11 -11
- package/dist/mcp-http-config-OGFPLJYH.js +28 -0
- package/dist/memory-cards-GJ3VHKAM.js +179 -0
- package/dist/memory-graph-extractor-TCTCM7PZ.js +21 -0
- package/dist/memory-poisoning-defense-FVLGA35X.js +223 -0
- package/dist/memory-reflection-BYJFIFSV.js +243 -0
- package/dist/notifications-AQKZFSR3.js +46 -0
- package/dist/orchestration-events-RDSYLFXZ.js +26 -0
- package/dist/orchestrator-2JTJQLPG.js +34 -0
- package/dist/pipeline-router-HBSTKHG5.js +14 -0
- package/dist/plan-limits-GQENSNTG.js +27 -0
- package/dist/project-boot-W2LTP7WW.js +299 -0
- package/dist/projection-worker-ZMT5KNJJ.js +1084 -0
- package/dist/prospective-memory-LANRNOJX.js +231 -0
- package/dist/reranker-QGJO6EHO.js +19 -0
- package/dist/retrieval-health-JE66LJ3I.js +11 -0
- package/dist/review-polling-IXJ57M6Q.js +125 -0
- package/dist/runtime/index.js +11 -11
- package/dist/session-events-XKG66APL.js +37 -0
- package/dist/session-kill-telemetry-VTU7YBII.js +30 -0
- package/dist/session-scope-TQZONLZL.js +87 -0
- package/dist/setup-wizard-PXK6SC2D.js +12 -0
- package/dist/skill-refinement-Y6LLKYRL.js +158 -0
- package/dist/steward-gate-QV2APBFB.js +14 -0
- package/dist/task-enforcement-GLDD2W5D.js +505 -0
- package/dist/task-scope-HMPIP6XB.js +36 -0
- package/dist/tasks-crud-FH2SFCNQ.js +78 -0
- package/dist/tasks-notify-3ZW2GLCS.js +39 -0
- package/dist/tasks-review-XERV6KZD.js +48 -0
- package/dist/telemetry-upload-R77W7I7G.js +740 -0
- package/dist/token-budget-NA4WQAY6.js +85 -0
- package/dist/tool-telemetry-D4Q76LAS.js +17 -0
- package/dist/tui/App.js +16 -16
- package/dist/tui-data-NJSEIA2Q.js +259 -0
- package/dist/wiki-acl-RE5IR5VV.js +111 -0
- package/dist/worker-gate-VN2POPFL.js +21 -0
- package/dist/workflow-engine-D7ALMSDM.js +28 -0
- package/dist/worktree-6I45JV5N.js +27 -0
- package/dist/worktree-sweep-IMDR3XHT.js +20 -0
- package/package.json +1 -1
- package/release-notes.json +88 -88
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
storeBehavior
|
|
3
|
+
} from "./chunk-7FTKXL5A.js";
|
|
4
|
+
import {
|
|
5
|
+
getClient
|
|
6
|
+
} from "./chunk-DBQ6I6K2.js";
|
|
7
|
+
import {
|
|
8
|
+
loadConfig
|
|
9
|
+
} from "./chunk-5P3HOBZX.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/skill-learning.ts
|
|
12
|
+
import crypto from "crypto";
|
|
13
|
+
var DEFAULT_SKILL_THRESHOLD = 3;
|
|
14
|
+
async function extractTrajectory(taskId, agentId) {
|
|
15
|
+
const client = getClient();
|
|
16
|
+
const result = await client.execute({
|
|
17
|
+
sql: `SELECT tool_name, raw_text
|
|
18
|
+
FROM memories
|
|
19
|
+
WHERE task_id = ? AND agent_id = ?
|
|
20
|
+
ORDER BY timestamp ASC`,
|
|
21
|
+
args: [taskId, agentId]
|
|
22
|
+
});
|
|
23
|
+
if (result.rows.length === 0) return [];
|
|
24
|
+
const rawTools = result.rows.map((r) => {
|
|
25
|
+
const toolName = String(r.tool_name);
|
|
26
|
+
if (toolName === "Bash") {
|
|
27
|
+
const text = String(r.raw_text);
|
|
28
|
+
const cmdMatch = text.match(/(?:command|Command).*?[:\s]+"?(\w+)/);
|
|
29
|
+
return cmdMatch ? `Bash:${cmdMatch[1]}` : "Bash";
|
|
30
|
+
}
|
|
31
|
+
return toolName;
|
|
32
|
+
});
|
|
33
|
+
const signature = [];
|
|
34
|
+
for (const tool of rawTools) {
|
|
35
|
+
if (signature.length === 0 || signature[signature.length - 1] !== tool) {
|
|
36
|
+
signature.push(tool);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return signature;
|
|
40
|
+
}
|
|
41
|
+
function hashSignature(signature) {
|
|
42
|
+
return crypto.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
|
|
43
|
+
}
|
|
44
|
+
async function storeTrajectory(opts) {
|
|
45
|
+
const client = getClient();
|
|
46
|
+
const id = crypto.randomUUID();
|
|
47
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
48
|
+
const signatureHash = hashSignature(opts.signature);
|
|
49
|
+
await client.execute({
|
|
50
|
+
sql: `INSERT INTO trajectories (id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, created_at)
|
|
51
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
52
|
+
args: [
|
|
53
|
+
id,
|
|
54
|
+
opts.taskId,
|
|
55
|
+
opts.agentId,
|
|
56
|
+
opts.projectName,
|
|
57
|
+
opts.taskTitle,
|
|
58
|
+
JSON.stringify(opts.signature),
|
|
59
|
+
signatureHash,
|
|
60
|
+
opts.signature.length,
|
|
61
|
+
now
|
|
62
|
+
]
|
|
63
|
+
});
|
|
64
|
+
return id;
|
|
65
|
+
}
|
|
66
|
+
async function findSimilarTrajectories(signature, threshold = DEFAULT_SKILL_THRESHOLD) {
|
|
67
|
+
const client = getClient();
|
|
68
|
+
const hash = hashSignature(signature);
|
|
69
|
+
const result = await client.execute({
|
|
70
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, skill_id, created_at
|
|
71
|
+
FROM trajectories
|
|
72
|
+
WHERE signature_hash = ?
|
|
73
|
+
ORDER BY created_at DESC
|
|
74
|
+
LIMIT 20`,
|
|
75
|
+
args: [hash]
|
|
76
|
+
});
|
|
77
|
+
const mapRow = (r) => ({
|
|
78
|
+
id: String(r.id),
|
|
79
|
+
taskId: String(r.task_id),
|
|
80
|
+
agentId: String(r.agent_id),
|
|
81
|
+
projectName: String(r.project_name),
|
|
82
|
+
taskTitle: String(r.task_title),
|
|
83
|
+
signature: JSON.parse(String(r.signature)),
|
|
84
|
+
signatureHash: String(r.signature_hash),
|
|
85
|
+
toolCount: Number(r.tool_count),
|
|
86
|
+
skillId: r.skill_id ? String(r.skill_id) : null,
|
|
87
|
+
createdAt: String(r.created_at)
|
|
88
|
+
});
|
|
89
|
+
const matches = result.rows.map(mapRow);
|
|
90
|
+
if (matches.length >= threshold) return matches;
|
|
91
|
+
const nearResult = await client.execute({
|
|
92
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, skill_id, created_at
|
|
93
|
+
FROM trajectories
|
|
94
|
+
WHERE tool_count BETWEEN ? AND ?
|
|
95
|
+
AND signature_hash != ?
|
|
96
|
+
ORDER BY created_at DESC
|
|
97
|
+
LIMIT 50`,
|
|
98
|
+
args: [
|
|
99
|
+
Math.max(1, signature.length - 3),
|
|
100
|
+
signature.length + 3,
|
|
101
|
+
hash
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
for (const r of nearResult.rows) {
|
|
105
|
+
const candidateSig = JSON.parse(String(r.signature));
|
|
106
|
+
if (editDistance(signature, candidateSig) <= 2) {
|
|
107
|
+
matches.push(mapRow(r));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return matches;
|
|
111
|
+
}
|
|
112
|
+
async function captureTrajectory(opts) {
|
|
113
|
+
const signature = await extractTrajectory(opts.taskId, opts.agentId);
|
|
114
|
+
if (signature.length < 3) {
|
|
115
|
+
return { trajectoryId: "", similarCount: 0, similar: [] };
|
|
116
|
+
}
|
|
117
|
+
const trajectoryId = await storeTrajectory({
|
|
118
|
+
taskId: opts.taskId,
|
|
119
|
+
agentId: opts.agentId,
|
|
120
|
+
projectName: opts.projectName,
|
|
121
|
+
taskTitle: opts.taskTitle,
|
|
122
|
+
signature
|
|
123
|
+
});
|
|
124
|
+
const similar = await findSimilarTrajectories(
|
|
125
|
+
signature,
|
|
126
|
+
opts.skillThreshold ?? DEFAULT_SKILL_THRESHOLD
|
|
127
|
+
);
|
|
128
|
+
return { trajectoryId, similarCount: similar.length, similar };
|
|
129
|
+
}
|
|
130
|
+
function buildExtractionPrompt(trajectories) {
|
|
131
|
+
const items = trajectories.map((t, i) => {
|
|
132
|
+
const sig = t.signature.join(" \u2192 ");
|
|
133
|
+
return `Task ${i + 1}: "${t.taskTitle}" (${t.agentId}, ${t.projectName}) \u2014 ${t.toolCount} tool calls
|
|
134
|
+
Signature: ${sig}`;
|
|
135
|
+
}).join("\n\n");
|
|
136
|
+
return `You are analyzing ${trajectories.length} completed tasks that followed similar procedures:
|
|
137
|
+
|
|
138
|
+
${items}
|
|
139
|
+
|
|
140
|
+
Extract the reusable procedure. Format your response EXACTLY like this:
|
|
141
|
+
|
|
142
|
+
SKILL: {name \u2014 short, descriptive}
|
|
143
|
+
TRIGGER: {when to use this \u2014 one sentence}
|
|
144
|
+
STEPS:
|
|
145
|
+
1. ...
|
|
146
|
+
2. ...
|
|
147
|
+
PITFALLS: {common mistakes to avoid}
|
|
148
|
+
|
|
149
|
+
Be specific and actionable. Include tool names, file patterns, and concrete commands where applicable.`;
|
|
150
|
+
}
|
|
151
|
+
async function extractSkill(trajectories, model) {
|
|
152
|
+
if (trajectories.length === 0) return null;
|
|
153
|
+
const config = await loadConfig();
|
|
154
|
+
const skillModel = model ?? config.skillModel;
|
|
155
|
+
const Anthropic = (await import("@anthropic-ai/sdk")).default;
|
|
156
|
+
const client = new Anthropic();
|
|
157
|
+
const prompt = buildExtractionPrompt(trajectories);
|
|
158
|
+
const response = await client.messages.create({
|
|
159
|
+
model: skillModel,
|
|
160
|
+
max_tokens: 500,
|
|
161
|
+
messages: [{ role: "user", content: prompt }]
|
|
162
|
+
});
|
|
163
|
+
const textBlock = response.content.find((b) => b.type === "text");
|
|
164
|
+
const skillText = textBlock?.text;
|
|
165
|
+
if (!skillText) return null;
|
|
166
|
+
const agentId = trajectories[0].agentId;
|
|
167
|
+
const projectName = trajectories[0].projectName;
|
|
168
|
+
const skillId = await storeBehavior({
|
|
169
|
+
agentId,
|
|
170
|
+
content: skillText,
|
|
171
|
+
domain: "skill",
|
|
172
|
+
projectName
|
|
173
|
+
});
|
|
174
|
+
const dbClient = getClient();
|
|
175
|
+
for (const t of trajectories) {
|
|
176
|
+
await dbClient.execute({
|
|
177
|
+
sql: "UPDATE trajectories SET skill_id = ? WHERE id = ?",
|
|
178
|
+
args: [skillId, t.id]
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
process.stderr.write(
|
|
182
|
+
`[skill-learning] Skill extracted from ${trajectories.length} trajectories \u2192 behavior ${skillId}
|
|
183
|
+
`
|
|
184
|
+
);
|
|
185
|
+
return skillId;
|
|
186
|
+
}
|
|
187
|
+
async function captureAndLearn(opts) {
|
|
188
|
+
try {
|
|
189
|
+
const config = await loadConfig();
|
|
190
|
+
if (!config.skillLearning) return;
|
|
191
|
+
const { trajectoryId, similarCount, similar } = await captureTrajectory({
|
|
192
|
+
...opts,
|
|
193
|
+
skillThreshold: config.skillThreshold
|
|
194
|
+
});
|
|
195
|
+
if (!trajectoryId) return;
|
|
196
|
+
if (similarCount >= config.skillThreshold) {
|
|
197
|
+
const unprocessed = similar.filter((t) => !t.skillId);
|
|
198
|
+
if (unprocessed.length >= config.skillThreshold) {
|
|
199
|
+
extractSkill(unprocessed, config.skillModel).catch((err) => {
|
|
200
|
+
process.stderr.write(
|
|
201
|
+
`[skill-learning] Extraction failed: ${err instanceof Error ? err.message : String(err)}
|
|
202
|
+
`
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch (err) {
|
|
208
|
+
process.stderr.write(
|
|
209
|
+
`[skill-learning] captureAndLearn failed: ${err instanceof Error ? err.message : String(err)}
|
|
210
|
+
`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async function sweepTrajectories(threshold, model) {
|
|
215
|
+
const config = await loadConfig();
|
|
216
|
+
if (!config.skillLearning) return { clustersProcessed: 0, skillsExtracted: 0 };
|
|
217
|
+
const t = threshold ?? config.skillThreshold;
|
|
218
|
+
const client = getClient();
|
|
219
|
+
const result = await client.execute({
|
|
220
|
+
sql: `SELECT signature_hash, COUNT(*) as cnt
|
|
221
|
+
FROM trajectories
|
|
222
|
+
WHERE skill_id IS NULL
|
|
223
|
+
GROUP BY signature_hash
|
|
224
|
+
HAVING cnt >= ?
|
|
225
|
+
ORDER BY cnt DESC
|
|
226
|
+
LIMIT 10`,
|
|
227
|
+
args: [t]
|
|
228
|
+
});
|
|
229
|
+
let clustersProcessed = 0;
|
|
230
|
+
let skillsExtracted = 0;
|
|
231
|
+
for (const row of result.rows) {
|
|
232
|
+
const hash = String(row.signature_hash);
|
|
233
|
+
const trajResult = await client.execute({
|
|
234
|
+
sql: `SELECT id, task_id, agent_id, project_name, task_title, signature, signature_hash, tool_count, created_at
|
|
235
|
+
FROM trajectories
|
|
236
|
+
WHERE signature_hash = ? AND skill_id IS NULL
|
|
237
|
+
ORDER BY created_at DESC
|
|
238
|
+
LIMIT 10`,
|
|
239
|
+
args: [hash]
|
|
240
|
+
});
|
|
241
|
+
const trajectories = trajResult.rows.map((r) => ({
|
|
242
|
+
id: String(r.id),
|
|
243
|
+
taskId: String(r.task_id),
|
|
244
|
+
agentId: String(r.agent_id),
|
|
245
|
+
projectName: String(r.project_name),
|
|
246
|
+
taskTitle: String(r.task_title),
|
|
247
|
+
signature: JSON.parse(String(r.signature)),
|
|
248
|
+
signatureHash: String(r.signature_hash),
|
|
249
|
+
toolCount: Number(r.tool_count),
|
|
250
|
+
skillId: null,
|
|
251
|
+
createdAt: String(r.created_at)
|
|
252
|
+
}));
|
|
253
|
+
if (trajectories.length >= t) {
|
|
254
|
+
clustersProcessed++;
|
|
255
|
+
const skillId = await extractSkill(trajectories, model ?? config.skillModel);
|
|
256
|
+
if (skillId) skillsExtracted++;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { clustersProcessed, skillsExtracted };
|
|
260
|
+
}
|
|
261
|
+
function editDistance(a, b) {
|
|
262
|
+
const m = a.length;
|
|
263
|
+
const n = b.length;
|
|
264
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
265
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
266
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
267
|
+
for (let i = 1; i <= m; i++) {
|
|
268
|
+
for (let j = 1; j <= n; j++) {
|
|
269
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
270
|
+
dp[i][j] = Math.min(
|
|
271
|
+
dp[i - 1][j] + 1,
|
|
272
|
+
dp[i][j - 1] + 1,
|
|
273
|
+
dp[i - 1][j - 1] + cost
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return dp[m][n];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export {
|
|
281
|
+
extractTrajectory,
|
|
282
|
+
hashSignature,
|
|
283
|
+
storeTrajectory,
|
|
284
|
+
findSimilarTrajectories,
|
|
285
|
+
captureTrajectory,
|
|
286
|
+
extractSkill,
|
|
287
|
+
captureAndLearn,
|
|
288
|
+
sweepTrajectories,
|
|
289
|
+
editDistance
|
|
290
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkLicense,
|
|
3
|
+
loadLicense
|
|
4
|
+
} from "./chunk-SYOGNG2R.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/license-gate.ts
|
|
7
|
+
var _cachedLicense = null;
|
|
8
|
+
var _hasLicenseKey = false;
|
|
9
|
+
var _refreshInFlight = null;
|
|
10
|
+
async function initLicenseGate() {
|
|
11
|
+
const key = loadLicense();
|
|
12
|
+
_hasLicenseKey = key !== null && key.length > 0;
|
|
13
|
+
if (_hasLicenseKey) {
|
|
14
|
+
try {
|
|
15
|
+
_cachedLicense = await checkLicense();
|
|
16
|
+
} catch {
|
|
17
|
+
_cachedLicense = null;
|
|
18
|
+
}
|
|
19
|
+
return { license: _cachedLicense, hasKey: true };
|
|
20
|
+
}
|
|
21
|
+
return { license: null, hasKey: false };
|
|
22
|
+
}
|
|
23
|
+
function getCachedLicenseGate() {
|
|
24
|
+
if (!_hasLicenseKey) {
|
|
25
|
+
const key = loadLicense();
|
|
26
|
+
if (key && key.length > 0) {
|
|
27
|
+
_hasLicenseKey = true;
|
|
28
|
+
process.stderr.write("[license-gate] License key found on re-check (was missing at boot)\n");
|
|
29
|
+
void refreshLicenseGate();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
license: _cachedLicense,
|
|
34
|
+
hasKey: _hasLicenseKey
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function refreshLicenseGate() {
|
|
38
|
+
if (!_hasLicenseKey) {
|
|
39
|
+
const key = loadLicense();
|
|
40
|
+
_hasLicenseKey = key !== null && key.length > 0;
|
|
41
|
+
}
|
|
42
|
+
if (!_hasLicenseKey) {
|
|
43
|
+
_cachedLicense = null;
|
|
44
|
+
return { license: null, hasKey: false };
|
|
45
|
+
}
|
|
46
|
+
if (_refreshInFlight) return _refreshInFlight;
|
|
47
|
+
_refreshInFlight = (async () => {
|
|
48
|
+
try {
|
|
49
|
+
const license = await checkLicense();
|
|
50
|
+
_cachedLicense = license;
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
return { license: _cachedLicense, hasKey: _hasLicenseKey };
|
|
54
|
+
})();
|
|
55
|
+
try {
|
|
56
|
+
return await _refreshInFlight;
|
|
57
|
+
} finally {
|
|
58
|
+
_refreshInFlight = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
var NO_LICENSE_MESSAGE = "License key required. Get your key from the Exe OS team, then:\n\n echo 'exe_sk_YOUR_KEY' > ~/.exe-os/license.key\n\nThen run /mcp to reconnect, or restart your session.";
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
initLicenseGate,
|
|
65
|
+
getCachedLicenseGate,
|
|
66
|
+
refreshLicenseGate,
|
|
67
|
+
NO_LICENSE_MESSAGE
|
|
68
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PLATFORM_PROCEDURES,
|
|
3
|
+
PLATFORM_PROCEDURE_TITLES
|
|
4
|
+
} from "./chunk-VUH67PT4.js";
|
|
5
|
+
import {
|
|
6
|
+
getClient
|
|
7
|
+
} from "./chunk-DBQ6I6K2.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/global-procedures.ts
|
|
10
|
+
import { randomUUID } from "crypto";
|
|
11
|
+
var _customerCache = "";
|
|
12
|
+
var _cacheLoaded = false;
|
|
13
|
+
var _platformCache = PLATFORM_PROCEDURES.map((p) => `### ${p.title}
|
|
14
|
+
${p.content}`).join("\n\n");
|
|
15
|
+
async function loadGlobalProcedures() {
|
|
16
|
+
const client = getClient();
|
|
17
|
+
const result = await client.execute({
|
|
18
|
+
sql: "SELECT * FROM company_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
|
|
19
|
+
args: []
|
|
20
|
+
});
|
|
21
|
+
const allRows = result.rows;
|
|
22
|
+
const customerOnly = allRows.filter((p) => {
|
|
23
|
+
if (PLATFORM_PROCEDURE_TITLES.has(p.title)) return false;
|
|
24
|
+
const title = (p.title ?? "").trim();
|
|
25
|
+
const content = (p.content ?? "").trim();
|
|
26
|
+
if (!title || title === "(untitled)") return false;
|
|
27
|
+
if (!content) return false;
|
|
28
|
+
return true;
|
|
29
|
+
});
|
|
30
|
+
const values = customerOnly.filter((p) => p.kind === "value");
|
|
31
|
+
const procedures = customerOnly.filter((p) => p.kind !== "value");
|
|
32
|
+
const parts = [];
|
|
33
|
+
if (values.length > 0) {
|
|
34
|
+
parts.push("### Company Values\n" + values.map((v) => `- **${v.title}:** ${v.content}`).join("\n"));
|
|
35
|
+
}
|
|
36
|
+
if (procedures.length > 0) {
|
|
37
|
+
parts.push(procedures.map((p) => `### ${p.title}
|
|
38
|
+
${p.content}`).join("\n\n"));
|
|
39
|
+
}
|
|
40
|
+
_customerCache = parts.join("\n\n");
|
|
41
|
+
_cacheLoaded = true;
|
|
42
|
+
return customerOnly;
|
|
43
|
+
}
|
|
44
|
+
function getGlobalProceduresBlock() {
|
|
45
|
+
const sections = [];
|
|
46
|
+
if (_platformCache) sections.push(_platformCache);
|
|
47
|
+
if (_cacheLoaded && _customerCache) sections.push(_customerCache);
|
|
48
|
+
if (sections.length === 0) return "";
|
|
49
|
+
return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
|
|
50
|
+
|
|
51
|
+
${sections.join("\n\n")}
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
async function storeGlobalProcedure(input) {
|
|
55
|
+
if (!input.title?.trim() || !input.content?.trim()) {
|
|
56
|
+
throw new Error("storeGlobalProcedure requires a non-empty title and content");
|
|
57
|
+
}
|
|
58
|
+
const id = randomUUID();
|
|
59
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
60
|
+
const client = getClient();
|
|
61
|
+
await client.execute({
|
|
62
|
+
sql: `INSERT INTO company_procedures (id, title, content, priority, domain, kind, active, created_at, updated_at)
|
|
63
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
64
|
+
args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, input.kind ?? "procedure", now, now]
|
|
65
|
+
});
|
|
66
|
+
await loadGlobalProcedures();
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
async function deactivateGlobalProcedure(id) {
|
|
70
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
71
|
+
const client = getClient();
|
|
72
|
+
const result = await client.execute({
|
|
73
|
+
sql: "UPDATE company_procedures SET active = 0, updated_at = ? WHERE id = ?",
|
|
74
|
+
args: [now, id]
|
|
75
|
+
});
|
|
76
|
+
await loadGlobalProcedures();
|
|
77
|
+
return result.rowsAffected > 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export {
|
|
81
|
+
loadGlobalProcedures,
|
|
82
|
+
getGlobalProceduresBlock,
|
|
83
|
+
storeGlobalProcedure,
|
|
84
|
+
deactivateGlobalProcedure
|
|
85
|
+
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClient,
|
|
3
|
+
isCoordinatorName,
|
|
4
|
+
loadEmployeesSync
|
|
5
|
+
} from "./chunk-DBQ6I6K2.js";
|
|
6
|
+
|
|
7
|
+
// src/lib/steward-gate.ts
|
|
8
|
+
import crypto from "crypto";
|
|
9
|
+
var ROLE_PERMISSIONS = {
|
|
10
|
+
coordinator: /* @__PURE__ */ new Set([
|
|
11
|
+
"close_task",
|
|
12
|
+
"cancel_task",
|
|
13
|
+
"merge_entities",
|
|
14
|
+
"purge_document",
|
|
15
|
+
"deactivate_behavior",
|
|
16
|
+
"override"
|
|
17
|
+
]),
|
|
18
|
+
manager: /* @__PURE__ */ new Set([
|
|
19
|
+
"close_task",
|
|
20
|
+
// their team only — enforced contextually
|
|
21
|
+
"deactivate_behavior"
|
|
22
|
+
// their team's behaviors
|
|
23
|
+
]),
|
|
24
|
+
specialist: /* @__PURE__ */ new Set([
|
|
25
|
+
"deactivate_behavior_own",
|
|
26
|
+
// own behaviors only
|
|
27
|
+
"delete_own_memory"
|
|
28
|
+
])
|
|
29
|
+
};
|
|
30
|
+
var UNIVERSAL_OPS = /* @__PURE__ */ new Set([
|
|
31
|
+
"update_own_task",
|
|
32
|
+
"store_memory",
|
|
33
|
+
"store_behavior"
|
|
34
|
+
]);
|
|
35
|
+
var MANAGER_ROLES = /* @__PURE__ */ new Set(["CTO", "CMO"]);
|
|
36
|
+
var StewardGate = class {
|
|
37
|
+
/**
|
|
38
|
+
* Check whether an agent has authority for a destructive operation.
|
|
39
|
+
*/
|
|
40
|
+
async checkAuthority(agent, operation, target) {
|
|
41
|
+
const role = await this.resolveRole(agent);
|
|
42
|
+
if (UNIVERSAL_OPS.has(operation)) {
|
|
43
|
+
const decision2 = {
|
|
44
|
+
allowed: true,
|
|
45
|
+
reason: `Operation "${operation}" is universally permitted.`,
|
|
46
|
+
confidence: 1,
|
|
47
|
+
requires_override: false
|
|
48
|
+
};
|
|
49
|
+
await this.logDecision(agent, operation, target, decision2);
|
|
50
|
+
return decision2;
|
|
51
|
+
}
|
|
52
|
+
const permissions = ROLE_PERMISSIONS[role];
|
|
53
|
+
let allowed = permissions.has(operation);
|
|
54
|
+
let reason;
|
|
55
|
+
if (!allowed && role === "specialist" && operation === "deactivate_behavior") {
|
|
56
|
+
const isOwn = await this.isOwnBehavior(agent, target);
|
|
57
|
+
if (isOwn) {
|
|
58
|
+
allowed = true;
|
|
59
|
+
reason = `Specialist "${agent}" can deactivate their own behavior.`;
|
|
60
|
+
} else {
|
|
61
|
+
reason = `Specialist "${agent}" cannot deactivate behaviors belonging to other agents.`;
|
|
62
|
+
}
|
|
63
|
+
} else if (allowed) {
|
|
64
|
+
reason = `Role "${role}" has authority for "${operation}".`;
|
|
65
|
+
} else {
|
|
66
|
+
reason = `Role "${role}" does not have authority for "${operation}". Requires coordinator override.`;
|
|
67
|
+
}
|
|
68
|
+
let requiresOverride = !allowed;
|
|
69
|
+
let confidence = allowed ? 0.95 : 0.9;
|
|
70
|
+
try {
|
|
71
|
+
const dreamingPath = "./dreaming.js";
|
|
72
|
+
const dreaming = await import(
|
|
73
|
+
/* @vite-ignore */
|
|
74
|
+
dreamingPath
|
|
75
|
+
);
|
|
76
|
+
if (typeof dreaming.calculateDrift === "function") {
|
|
77
|
+
const driftScore = await dreaming.calculateDrift(agent);
|
|
78
|
+
if (typeof driftScore === "number" && driftScore > 0.8) {
|
|
79
|
+
requiresOverride = true;
|
|
80
|
+
confidence = Math.max(0.5, confidence - 0.3);
|
|
81
|
+
reason += ` (\u26A0\uFE0F High drift score: ${driftScore.toFixed(2)} \u2014 requires override.)`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
const decision = {
|
|
87
|
+
allowed: allowed && !requiresOverride,
|
|
88
|
+
reason,
|
|
89
|
+
confidence,
|
|
90
|
+
requires_override: requiresOverride
|
|
91
|
+
};
|
|
92
|
+
await this.logDecision(agent, operation, target, decision);
|
|
93
|
+
return decision;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Record an explicit coordinator override that bypasses the gate.
|
|
97
|
+
*/
|
|
98
|
+
async override(agent, operation, target, reason) {
|
|
99
|
+
const role = await this.resolveRole(agent);
|
|
100
|
+
if (role !== "coordinator") {
|
|
101
|
+
const decision2 = {
|
|
102
|
+
allowed: false,
|
|
103
|
+
reason: `Only coordinators can issue overrides. "${agent}" is a ${role}.`,
|
|
104
|
+
confidence: 1,
|
|
105
|
+
requires_override: false
|
|
106
|
+
};
|
|
107
|
+
await this.logDecision(agent, `override:${operation}`, target, decision2);
|
|
108
|
+
return decision2;
|
|
109
|
+
}
|
|
110
|
+
const decision = {
|
|
111
|
+
allowed: true,
|
|
112
|
+
reason: `Coordinator override: ${reason}`,
|
|
113
|
+
confidence: 1,
|
|
114
|
+
requires_override: false
|
|
115
|
+
};
|
|
116
|
+
await this.logDecision(agent, `override:${operation}`, target, decision);
|
|
117
|
+
return decision;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Query the audit trail.
|
|
121
|
+
*/
|
|
122
|
+
async getAuditLog(opts) {
|
|
123
|
+
await this.ensureAuditTable();
|
|
124
|
+
const client = getClient();
|
|
125
|
+
const conditions = [];
|
|
126
|
+
const args = [];
|
|
127
|
+
if (opts?.agent) {
|
|
128
|
+
conditions.push("agent = ?");
|
|
129
|
+
args.push(opts.agent);
|
|
130
|
+
}
|
|
131
|
+
if (opts?.operation) {
|
|
132
|
+
conditions.push("operation = ?");
|
|
133
|
+
args.push(opts.operation);
|
|
134
|
+
}
|
|
135
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
136
|
+
const limit = opts?.limit ?? 50;
|
|
137
|
+
const result = await client.execute({
|
|
138
|
+
sql: `SELECT * FROM steward_audit ${where} ORDER BY created_at DESC LIMIT ?`,
|
|
139
|
+
args: [...args, limit]
|
|
140
|
+
});
|
|
141
|
+
return result.rows.map((row) => ({
|
|
142
|
+
id: String(row.id),
|
|
143
|
+
agent: String(row.agent),
|
|
144
|
+
operation: String(row.operation),
|
|
145
|
+
target: String(row.target),
|
|
146
|
+
decision: {
|
|
147
|
+
allowed: Number(row.allowed) === 1,
|
|
148
|
+
reason: String(row.reason),
|
|
149
|
+
confidence: Number(row.confidence),
|
|
150
|
+
requires_override: Number(row.requires_override) === 1
|
|
151
|
+
},
|
|
152
|
+
timestamp: String(row.created_at)
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
// -------------------------------------------------------------------------
|
|
156
|
+
// Internal methods
|
|
157
|
+
// -------------------------------------------------------------------------
|
|
158
|
+
/**
|
|
159
|
+
* Resolve an agent name to a role category.
|
|
160
|
+
*/
|
|
161
|
+
async resolveRole(agent) {
|
|
162
|
+
if (isCoordinatorName(agent)) return "coordinator";
|
|
163
|
+
try {
|
|
164
|
+
const employees = loadEmployeesSync();
|
|
165
|
+
const employee = employees.find((e) => e.name === agent);
|
|
166
|
+
if (employee && MANAGER_ROLES.has(employee.role)) return "manager";
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
return "specialist";
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Check if a behavior belongs to the given agent.
|
|
173
|
+
*/
|
|
174
|
+
async isOwnBehavior(agent, behaviorId) {
|
|
175
|
+
try {
|
|
176
|
+
const client = getClient();
|
|
177
|
+
const result = await client.execute({
|
|
178
|
+
sql: "SELECT agent_id FROM behaviors WHERE id = ? LIMIT 1",
|
|
179
|
+
args: [behaviorId]
|
|
180
|
+
});
|
|
181
|
+
if (result.rows.length === 0) return false;
|
|
182
|
+
return String(result.rows[0].agent_id) === agent;
|
|
183
|
+
} catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Ensure the steward_audit table exists.
|
|
189
|
+
*/
|
|
190
|
+
async ensureAuditTable() {
|
|
191
|
+
const client = getClient();
|
|
192
|
+
await client.execute({
|
|
193
|
+
sql: `CREATE TABLE IF NOT EXISTS steward_audit (
|
|
194
|
+
id TEXT PRIMARY KEY,
|
|
195
|
+
agent TEXT NOT NULL,
|
|
196
|
+
operation TEXT NOT NULL,
|
|
197
|
+
target TEXT NOT NULL,
|
|
198
|
+
allowed INTEGER NOT NULL,
|
|
199
|
+
reason TEXT NOT NULL,
|
|
200
|
+
confidence REAL NOT NULL,
|
|
201
|
+
requires_override INTEGER NOT NULL DEFAULT 0,
|
|
202
|
+
created_at TEXT NOT NULL
|
|
203
|
+
)`,
|
|
204
|
+
args: []
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Log a gate decision to the audit trail.
|
|
209
|
+
*/
|
|
210
|
+
async logDecision(agent, operation, target, decision) {
|
|
211
|
+
try {
|
|
212
|
+
await this.ensureAuditTable();
|
|
213
|
+
const client = getClient();
|
|
214
|
+
await client.execute({
|
|
215
|
+
sql: `INSERT INTO steward_audit (id, agent, operation, target, allowed, reason, confidence, requires_override, created_at)
|
|
216
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
217
|
+
args: [
|
|
218
|
+
crypto.randomUUID(),
|
|
219
|
+
agent,
|
|
220
|
+
operation,
|
|
221
|
+
target,
|
|
222
|
+
decision.allowed ? 1 : 0,
|
|
223
|
+
decision.reason,
|
|
224
|
+
decision.confidence,
|
|
225
|
+
decision.requires_override ? 1 : 0,
|
|
226
|
+
(/* @__PURE__ */ new Date()).toISOString()
|
|
227
|
+
]
|
|
228
|
+
});
|
|
229
|
+
} catch {
|
|
230
|
+
process.stderr.write(
|
|
231
|
+
`[steward-gate] Audit log write failed for ${agent}:${operation}
|
|
232
|
+
`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export {
|
|
239
|
+
StewardGate
|
|
240
|
+
};
|