@ftarganski/omni-ai 1.1.10 → 1.2.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 +12 -1
- package/dist/cli/bin.js +1043 -155
- package/dist/history.d.ts +1 -0
- package/dist/history.js +545 -0
- package/dist/index.d.ts +1 -0
- package/package.json +10 -5
package/dist/cli/bin.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "../chunk-AU3KUCI7.js";
|
|
9
9
|
|
|
10
10
|
// ../../packages/cli/dist/bin.js
|
|
11
|
-
import { dirname as
|
|
11
|
+
import { dirname as dirname5, resolve as resolve17 } from "path";
|
|
12
12
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
import { config as loadDotenv } from "dotenv";
|
|
@@ -1155,13 +1155,888 @@ async function exportCommand(sessionArg, opts) {
|
|
|
1155
1155
|
${messages.length} message(s) exported.`));
|
|
1156
1156
|
}
|
|
1157
1157
|
|
|
1158
|
+
// ../../packages/cli/dist/commands/history/doctor.js
|
|
1159
|
+
import { existsSync } from "fs";
|
|
1160
|
+
import chalk5 from "chalk";
|
|
1161
|
+
|
|
1162
|
+
// ../../packages/history/dist/parsers/claude-code.js
|
|
1163
|
+
import { readdir as readdir4, readFile as readFile6, stat } from "fs/promises";
|
|
1164
|
+
import { homedir } from "os";
|
|
1165
|
+
import { join as join4 } from "path";
|
|
1166
|
+
import { glob } from "glob";
|
|
1167
|
+
function extractContent(message) {
|
|
1168
|
+
const raw = message?.content;
|
|
1169
|
+
if (typeof raw === "string")
|
|
1170
|
+
return { content: raw };
|
|
1171
|
+
if (Array.isArray(raw)) {
|
|
1172
|
+
const blocks = raw;
|
|
1173
|
+
const text = blocks.map((b) => {
|
|
1174
|
+
if (b.type === "text")
|
|
1175
|
+
return b.text ?? "";
|
|
1176
|
+
if (b.type === "tool_use")
|
|
1177
|
+
return `[tool_use:${b.name}] ${JSON.stringify(b.input ?? {})}`;
|
|
1178
|
+
if (b.type === "tool_result")
|
|
1179
|
+
return typeof b.content === "string" ? b.content : JSON.stringify(b.content);
|
|
1180
|
+
return "";
|
|
1181
|
+
}).filter(Boolean).join("\n");
|
|
1182
|
+
const toolUse = blocks.find((b) => b.type === "tool_use");
|
|
1183
|
+
return { content: text, toolName: toolUse?.name };
|
|
1184
|
+
}
|
|
1185
|
+
return { content: "" };
|
|
1186
|
+
}
|
|
1187
|
+
function defaultClaudeCodeRoot() {
|
|
1188
|
+
return join4(homedir(), ".claude", "projects");
|
|
1189
|
+
}
|
|
1190
|
+
async function parseTranscriptFile(file, provider, scope) {
|
|
1191
|
+
const raw = await readFile6(file, "utf-8");
|
|
1192
|
+
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
1193
|
+
const events = [];
|
|
1194
|
+
const citations = [];
|
|
1195
|
+
let ordinal = 0;
|
|
1196
|
+
lines.forEach((line, lineIndex) => {
|
|
1197
|
+
let entry;
|
|
1198
|
+
try {
|
|
1199
|
+
entry = JSON.parse(line);
|
|
1200
|
+
} catch {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
const type = typeof entry.type === "string" ? entry.type : void 0;
|
|
1204
|
+
const message = entry.message;
|
|
1205
|
+
if (!message || type !== "user" && type !== "assistant")
|
|
1206
|
+
return;
|
|
1207
|
+
const { content, toolName } = extractContent(message);
|
|
1208
|
+
if (!content)
|
|
1209
|
+
return;
|
|
1210
|
+
const timestamp = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : Number.NaN;
|
|
1211
|
+
events.push({
|
|
1212
|
+
role: message.role ?? type ?? "user",
|
|
1213
|
+
content,
|
|
1214
|
+
toolName,
|
|
1215
|
+
ordinal: ordinal++,
|
|
1216
|
+
timestamp: Number.isNaN(timestamp) ? Date.now() : timestamp
|
|
1217
|
+
});
|
|
1218
|
+
citations.push({ sourcePath: file, sourceLine: lineIndex + 1 });
|
|
1219
|
+
});
|
|
1220
|
+
if (events.length === 0)
|
|
1221
|
+
return null;
|
|
1222
|
+
const sourceSessionId = file.replace(/\.jsonl$/, "").split(/[/\\]/).pop() ?? file;
|
|
1223
|
+
return {
|
|
1224
|
+
session: {
|
|
1225
|
+
id: `${provider}:${scope ?? ""}:${sourceSessionId}`,
|
|
1226
|
+
provider,
|
|
1227
|
+
sourceSessionId,
|
|
1228
|
+
importedAt: Date.now(),
|
|
1229
|
+
scope
|
|
1230
|
+
},
|
|
1231
|
+
events,
|
|
1232
|
+
citations
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
var ClaudeCodeHistoryParser = class {
|
|
1236
|
+
provider = "claude-code";
|
|
1237
|
+
root;
|
|
1238
|
+
constructor(options = {}) {
|
|
1239
|
+
this.root = options.root ?? defaultClaudeCodeRoot();
|
|
1240
|
+
}
|
|
1241
|
+
async discover() {
|
|
1242
|
+
const id = `${this.provider}:${this.root}`;
|
|
1243
|
+
const base = {
|
|
1244
|
+
id,
|
|
1245
|
+
provider: this.provider,
|
|
1246
|
+
path: this.root,
|
|
1247
|
+
nativeImport: true
|
|
1248
|
+
};
|
|
1249
|
+
let entries;
|
|
1250
|
+
try {
|
|
1251
|
+
const info = await stat(this.root);
|
|
1252
|
+
if (!info.isDirectory()) {
|
|
1253
|
+
return [{ ...base, importable: false, reason: "path is not a directory" }];
|
|
1254
|
+
}
|
|
1255
|
+
entries = await readdir4(this.root, { withFileTypes: true });
|
|
1256
|
+
} catch {
|
|
1257
|
+
return [{ ...base, importable: false, reason: "history directory not found" }];
|
|
1258
|
+
}
|
|
1259
|
+
const sources = [];
|
|
1260
|
+
const looseFiles = await glob("*.jsonl", { cwd: this.root });
|
|
1261
|
+
if (looseFiles.length > 0) {
|
|
1262
|
+
sources.push({ ...base, importable: true });
|
|
1263
|
+
}
|
|
1264
|
+
for (const entry of entries) {
|
|
1265
|
+
if (!entry.isDirectory())
|
|
1266
|
+
continue;
|
|
1267
|
+
const dir = join4(this.root, entry.name);
|
|
1268
|
+
const files = await glob("**/*.jsonl", { cwd: dir });
|
|
1269
|
+
if (files.length === 0)
|
|
1270
|
+
continue;
|
|
1271
|
+
sources.push({
|
|
1272
|
+
id: `${this.provider}:${dir}`,
|
|
1273
|
+
provider: this.provider,
|
|
1274
|
+
path: dir,
|
|
1275
|
+
nativeImport: true,
|
|
1276
|
+
importable: true,
|
|
1277
|
+
scope: entry.name
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
if (sources.length === 0) {
|
|
1281
|
+
return [{ ...base, importable: false, reason: "no .jsonl transcripts found" }];
|
|
1282
|
+
}
|
|
1283
|
+
return sources;
|
|
1284
|
+
}
|
|
1285
|
+
async import(source) {
|
|
1286
|
+
const files = await glob("**/*.jsonl", { cwd: source.path, absolute: true });
|
|
1287
|
+
const results = [];
|
|
1288
|
+
for (const file of files) {
|
|
1289
|
+
const result = await parseTranscriptFile(file, source.provider, source.scope);
|
|
1290
|
+
if (result)
|
|
1291
|
+
results.push(result);
|
|
1292
|
+
}
|
|
1293
|
+
return results;
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
// ../../packages/history/dist/parsers/codex.js
|
|
1298
|
+
import { readFile as readFile7, stat as stat2 } from "fs/promises";
|
|
1299
|
+
import { homedir as homedir2 } from "os";
|
|
1300
|
+
import { join as join5 } from "path";
|
|
1301
|
+
import { glob as glob2 } from "glob";
|
|
1302
|
+
|
|
1303
|
+
// ../../packages/history/dist/store.js
|
|
1304
|
+
import { mkdirSync } from "fs";
|
|
1305
|
+
import { dirname as dirname3 } from "path";
|
|
1306
|
+
import Database2 from "better-sqlite3";
|
|
1307
|
+
var sourceFromRow = (r) => ({
|
|
1308
|
+
id: r.id,
|
|
1309
|
+
provider: r.provider,
|
|
1310
|
+
path: r.path,
|
|
1311
|
+
nativeImport: Boolean(r.native_import),
|
|
1312
|
+
importable: Boolean(r.importable),
|
|
1313
|
+
reason: r.reason ?? void 0,
|
|
1314
|
+
scope: r.scope || void 0
|
|
1315
|
+
});
|
|
1316
|
+
var sessionFromRow = (r) => ({
|
|
1317
|
+
id: r.id,
|
|
1318
|
+
provider: r.provider,
|
|
1319
|
+
sourceSessionId: r.source_session_id,
|
|
1320
|
+
importedAt: r.imported_at,
|
|
1321
|
+
scope: r.scope || void 0
|
|
1322
|
+
});
|
|
1323
|
+
var eventFromRow = (r) => ({
|
|
1324
|
+
id: r.id,
|
|
1325
|
+
sessionId: r.session_id,
|
|
1326
|
+
role: r.role,
|
|
1327
|
+
content: r.content,
|
|
1328
|
+
toolName: r.tool_name ?? void 0,
|
|
1329
|
+
ordinal: r.ordinal,
|
|
1330
|
+
timestamp: r.ts
|
|
1331
|
+
});
|
|
1332
|
+
var HistoryStore = class {
|
|
1333
|
+
db;
|
|
1334
|
+
constructor(options = {}) {
|
|
1335
|
+
const path = options.path ?? "./omni-ai-history.db";
|
|
1336
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
1337
|
+
this.db = new Database2(path);
|
|
1338
|
+
this.db.pragma("journal_mode = WAL");
|
|
1339
|
+
this.migrate();
|
|
1340
|
+
}
|
|
1341
|
+
migrate() {
|
|
1342
|
+
this.db.exec(`
|
|
1343
|
+
CREATE TABLE IF NOT EXISTS sources (
|
|
1344
|
+
id TEXT PRIMARY KEY,
|
|
1345
|
+
provider TEXT NOT NULL,
|
|
1346
|
+
path TEXT NOT NULL,
|
|
1347
|
+
native_import INTEGER NOT NULL,
|
|
1348
|
+
importable INTEGER NOT NULL,
|
|
1349
|
+
reason TEXT,
|
|
1350
|
+
scope TEXT NOT NULL DEFAULT ''
|
|
1351
|
+
);
|
|
1352
|
+
|
|
1353
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
1354
|
+
id TEXT PRIMARY KEY,
|
|
1355
|
+
provider TEXT NOT NULL,
|
|
1356
|
+
source_session_id TEXT NOT NULL,
|
|
1357
|
+
imported_at INTEGER NOT NULL,
|
|
1358
|
+
scope TEXT NOT NULL DEFAULT '',
|
|
1359
|
+
UNIQUE (provider, scope, source_session_id)
|
|
1360
|
+
);
|
|
1361
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_scope ON sessions (scope);
|
|
1362
|
+
|
|
1363
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
1364
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1365
|
+
session_id TEXT NOT NULL REFERENCES sessions (id),
|
|
1366
|
+
role TEXT NOT NULL,
|
|
1367
|
+
content TEXT NOT NULL,
|
|
1368
|
+
tool_name TEXT,
|
|
1369
|
+
ordinal INTEGER NOT NULL,
|
|
1370
|
+
ts INTEGER NOT NULL
|
|
1371
|
+
);
|
|
1372
|
+
CREATE INDEX IF NOT EXISTS idx_events_session ON events (session_id, ordinal);
|
|
1373
|
+
|
|
1374
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
|
|
1375
|
+
content,
|
|
1376
|
+
content='events',
|
|
1377
|
+
content_rowid='id'
|
|
1378
|
+
);
|
|
1379
|
+
|
|
1380
|
+
CREATE TRIGGER IF NOT EXISTS events_ai AFTER INSERT ON events BEGIN
|
|
1381
|
+
INSERT INTO events_fts (rowid, content) VALUES (new.id, new.content);
|
|
1382
|
+
END;
|
|
1383
|
+
|
|
1384
|
+
CREATE TABLE IF NOT EXISTS citations (
|
|
1385
|
+
event_id INTEGER NOT NULL REFERENCES events (id),
|
|
1386
|
+
source_path TEXT NOT NULL,
|
|
1387
|
+
source_line INTEGER,
|
|
1388
|
+
PRIMARY KEY (event_id)
|
|
1389
|
+
);
|
|
1390
|
+
`);
|
|
1391
|
+
}
|
|
1392
|
+
upsertSource(source) {
|
|
1393
|
+
this.db.prepare(`INSERT INTO sources (id, provider, path, native_import, importable, reason, scope)
|
|
1394
|
+
VALUES (@id, @provider, @path, @nativeImport, @importable, @reason, @scope)
|
|
1395
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
1396
|
+
provider = excluded.provider,
|
|
1397
|
+
path = excluded.path,
|
|
1398
|
+
native_import = excluded.native_import,
|
|
1399
|
+
importable = excluded.importable,
|
|
1400
|
+
reason = excluded.reason,
|
|
1401
|
+
scope = excluded.scope`).run({
|
|
1402
|
+
id: source.id,
|
|
1403
|
+
provider: source.provider,
|
|
1404
|
+
path: source.path,
|
|
1405
|
+
nativeImport: source.nativeImport ? 1 : 0,
|
|
1406
|
+
importable: source.importable ? 1 : 0,
|
|
1407
|
+
reason: source.reason ?? null,
|
|
1408
|
+
scope: source.scope ?? ""
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
listSources(provider) {
|
|
1412
|
+
const rows = provider ? this.db.prepare(`SELECT * FROM sources WHERE provider = ? ORDER BY id`).all(provider) : this.db.prepare(`SELECT * FROM sources ORDER BY provider, id`).all();
|
|
1413
|
+
return rows.map(sourceFromRow);
|
|
1414
|
+
}
|
|
1415
|
+
/** Persists one imported session and its events/citations. Idempotent per (provider, scope, sourceSessionId). */
|
|
1416
|
+
saveImportResult(provider, sessionId, result) {
|
|
1417
|
+
const upsertSession = this.db.prepare(`INSERT INTO sessions (id, provider, source_session_id, imported_at, scope)
|
|
1418
|
+
VALUES (@id, @provider, @sourceSessionId, @importedAt, @scope)
|
|
1419
|
+
ON CONFLICT (provider, scope, source_session_id) DO UPDATE SET imported_at = excluded.imported_at`);
|
|
1420
|
+
const insertEvent = this.db.prepare(`INSERT INTO events (session_id, role, content, tool_name, ordinal, ts)
|
|
1421
|
+
VALUES (@sessionId, @role, @content, @toolName, @ordinal, @ts)`);
|
|
1422
|
+
const insertCitation = this.db.prepare(`INSERT INTO citations (event_id, source_path, source_line)
|
|
1423
|
+
VALUES (@eventId, @sourcePath, @sourceLine)
|
|
1424
|
+
ON CONFLICT (event_id) DO UPDATE SET source_path = excluded.source_path, source_line = excluded.source_line`);
|
|
1425
|
+
const deleteCitations = this.db.prepare(`DELETE FROM citations WHERE event_id IN (SELECT id FROM events WHERE session_id = ?)`);
|
|
1426
|
+
const deleteEvents = this.db.prepare(`DELETE FROM events WHERE session_id = ?`);
|
|
1427
|
+
const run = this.db.transaction(() => {
|
|
1428
|
+
upsertSession.run({
|
|
1429
|
+
id: sessionId,
|
|
1430
|
+
provider,
|
|
1431
|
+
sourceSessionId: result.session.sourceSessionId,
|
|
1432
|
+
importedAt: result.session.importedAt,
|
|
1433
|
+
scope: result.session.scope ?? ""
|
|
1434
|
+
});
|
|
1435
|
+
deleteCitations.run(sessionId);
|
|
1436
|
+
deleteEvents.run(sessionId);
|
|
1437
|
+
result.events.forEach((event, i) => {
|
|
1438
|
+
const info = insertEvent.run({
|
|
1439
|
+
sessionId,
|
|
1440
|
+
role: event.role,
|
|
1441
|
+
content: event.content,
|
|
1442
|
+
toolName: event.toolName ?? null,
|
|
1443
|
+
ordinal: event.ordinal,
|
|
1444
|
+
ts: event.timestamp
|
|
1445
|
+
});
|
|
1446
|
+
const citation = result.citations[i];
|
|
1447
|
+
if (citation) {
|
|
1448
|
+
insertCitation.run({
|
|
1449
|
+
eventId: info.lastInsertRowid,
|
|
1450
|
+
sourcePath: citation.sourcePath,
|
|
1451
|
+
sourceLine: citation.sourceLine ?? null
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
run();
|
|
1457
|
+
}
|
|
1458
|
+
getSession(id) {
|
|
1459
|
+
const row = this.db.prepare(`SELECT * FROM sessions WHERE id = ?`).get(id);
|
|
1460
|
+
return row ? sessionFromRow(row) : null;
|
|
1461
|
+
}
|
|
1462
|
+
listSessions(options = {}) {
|
|
1463
|
+
const clauses = [];
|
|
1464
|
+
const params = [];
|
|
1465
|
+
if (options.provider) {
|
|
1466
|
+
clauses.push("provider = ?");
|
|
1467
|
+
params.push(options.provider);
|
|
1468
|
+
}
|
|
1469
|
+
if (options.scope) {
|
|
1470
|
+
clauses.push("scope = ?");
|
|
1471
|
+
params.push(options.scope);
|
|
1472
|
+
}
|
|
1473
|
+
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
1474
|
+
const rows = this.db.prepare(`SELECT * FROM sessions ${where} ORDER BY imported_at DESC`).all(...params);
|
|
1475
|
+
return rows.map(sessionFromRow);
|
|
1476
|
+
}
|
|
1477
|
+
listEvents(sessionId) {
|
|
1478
|
+
const rows = this.db.prepare(`SELECT * FROM events WHERE session_id = ? ORDER BY ordinal ASC`).all(sessionId);
|
|
1479
|
+
return rows.map(eventFromRow);
|
|
1480
|
+
}
|
|
1481
|
+
getEvent(id) {
|
|
1482
|
+
const row = this.db.prepare(`SELECT * FROM events WHERE id = ?`).get(id);
|
|
1483
|
+
return row ? eventFromRow(row) : null;
|
|
1484
|
+
}
|
|
1485
|
+
/** Events immediately before/after `id` within the same session, `id` included. */
|
|
1486
|
+
getEventWindow(id, window) {
|
|
1487
|
+
const center = this.getEvent(id);
|
|
1488
|
+
if (!center)
|
|
1489
|
+
return [];
|
|
1490
|
+
const rows = this.db.prepare(`SELECT * FROM events
|
|
1491
|
+
WHERE session_id = ? AND ordinal BETWEEN ? AND ?
|
|
1492
|
+
ORDER BY ordinal ASC`).all(center.sessionId, center.ordinal - window, center.ordinal + window);
|
|
1493
|
+
return rows.map(eventFromRow);
|
|
1494
|
+
}
|
|
1495
|
+
getCitation(eventId) {
|
|
1496
|
+
const row = this.db.prepare(`SELECT * FROM citations WHERE event_id = ?`).get(eventId);
|
|
1497
|
+
return row ? { eventId: row.event_id, sourcePath: row.source_path, sourceLine: row.source_line ?? void 0 } : null;
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Full-text search over event content. Session-diverse by default: at most `groupLimit`
|
|
1501
|
+
* hits per session so one large session can't crowd out the rest of the result page.
|
|
1502
|
+
*
|
|
1503
|
+
* Scoped by default in spirit — callers (CLI, MCP skills) are expected to pass `scope`
|
|
1504
|
+
* for project-aware providers so an agent working in one project never sees another
|
|
1505
|
+
* project's imported history. Omitting `scope` searches across every scope.
|
|
1506
|
+
*/
|
|
1507
|
+
search(query, options = {}) {
|
|
1508
|
+
const limit = options.limit ?? 20;
|
|
1509
|
+
const groupLimit = options.groupLimit ?? 3;
|
|
1510
|
+
const clauses = ["fts.content MATCH @query"];
|
|
1511
|
+
const params = { query };
|
|
1512
|
+
if (options.sessionId) {
|
|
1513
|
+
clauses.push("e.session_id = @sessionId");
|
|
1514
|
+
params.sessionId = options.sessionId;
|
|
1515
|
+
}
|
|
1516
|
+
if (options.scope) {
|
|
1517
|
+
clauses.push("s.scope = @scope");
|
|
1518
|
+
params.scope = options.scope;
|
|
1519
|
+
}
|
|
1520
|
+
const rows = this.db.prepare(`SELECT e.*, rank AS score FROM events_fts fts
|
|
1521
|
+
JOIN events e ON e.id = fts.rowid
|
|
1522
|
+
JOIN sessions s ON s.id = e.session_id
|
|
1523
|
+
WHERE ${clauses.join(" AND ")}
|
|
1524
|
+
ORDER BY rank`).all(params);
|
|
1525
|
+
const perSession = /* @__PURE__ */ new Map();
|
|
1526
|
+
const sessionCache = /* @__PURE__ */ new Map();
|
|
1527
|
+
const hits = [];
|
|
1528
|
+
for (const row of rows) {
|
|
1529
|
+
if (hits.length >= limit)
|
|
1530
|
+
break;
|
|
1531
|
+
const count = perSession.get(row.session_id) ?? 0;
|
|
1532
|
+
if (count >= groupLimit)
|
|
1533
|
+
continue;
|
|
1534
|
+
let session = sessionCache.get(row.session_id);
|
|
1535
|
+
if (session === void 0) {
|
|
1536
|
+
session = this.getSession(row.session_id);
|
|
1537
|
+
sessionCache.set(row.session_id, session);
|
|
1538
|
+
}
|
|
1539
|
+
if (!session)
|
|
1540
|
+
continue;
|
|
1541
|
+
perSession.set(row.session_id, count + 1);
|
|
1542
|
+
hits.push({ event: eventFromRow(row), session, score: row.score });
|
|
1543
|
+
}
|
|
1544
|
+
return hits;
|
|
1545
|
+
}
|
|
1546
|
+
listCitations() {
|
|
1547
|
+
const rows = this.db.prepare(`SELECT * FROM citations`).all();
|
|
1548
|
+
return rows.map((r) => ({
|
|
1549
|
+
eventId: r.event_id,
|
|
1550
|
+
sourcePath: r.source_path,
|
|
1551
|
+
sourceLine: r.source_line ?? void 0
|
|
1552
|
+
}));
|
|
1553
|
+
}
|
|
1554
|
+
close() {
|
|
1555
|
+
this.db.close();
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
|
|
1559
|
+
// ../../packages/history/dist/skills.js
|
|
1560
|
+
function defaultHistoryDbPath() {
|
|
1561
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
|
|
1562
|
+
return `${home}/.omni-ai/history.db`;
|
|
1563
|
+
}
|
|
1564
|
+
function encodeProjectScope(absPath) {
|
|
1565
|
+
return absPath.replace(/[^a-zA-Z0-9]/g, "-");
|
|
1566
|
+
}
|
|
1567
|
+
var searchHistorySkill = {
|
|
1568
|
+
name: "search-history",
|
|
1569
|
+
description: "Full-text search over already-imported third-party AI agent history (run `omni history import` first to populate it). Scoped to the caller's own project by default \u2014 pass allProjects:true to search every imported project.",
|
|
1570
|
+
async execute(input5) {
|
|
1571
|
+
const scope = input5.allProjects ? void 0 : input5.scope ?? encodeProjectScope(process.cwd());
|
|
1572
|
+
const store = new HistoryStore({ path: defaultHistoryDbPath() });
|
|
1573
|
+
try {
|
|
1574
|
+
const hits = store.search(input5.query, { scope, limit: input5.limit });
|
|
1575
|
+
return { scope: scope ?? null, hits };
|
|
1576
|
+
} finally {
|
|
1577
|
+
store.close();
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
var showEventSkill = {
|
|
1582
|
+
name: "show-history-event",
|
|
1583
|
+
description: "Show one imported history event with N events of surrounding context. Refuses events that belong to a different project scope than the caller's, unless allProjects:true is passed.",
|
|
1584
|
+
async execute(input5) {
|
|
1585
|
+
const store = new HistoryStore({ path: defaultHistoryDbPath() });
|
|
1586
|
+
try {
|
|
1587
|
+
const center = store.getEvent(input5.eventId);
|
|
1588
|
+
if (!center)
|
|
1589
|
+
return { events: [] };
|
|
1590
|
+
if (!input5.allProjects) {
|
|
1591
|
+
const session = store.getSession(center.sessionId);
|
|
1592
|
+
const callerScope = encodeProjectScope(process.cwd());
|
|
1593
|
+
if (session?.scope && session.scope !== callerScope) {
|
|
1594
|
+
throw new Error(`Event ${input5.eventId} belongs to a different project scope ("${session.scope}"). Pass allProjects:true to override.`);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
return { events: store.getEventWindow(input5.eventId, input5.window ?? 3) };
|
|
1598
|
+
} finally {
|
|
1599
|
+
store.close();
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
|
|
1604
|
+
// ../../packages/history/dist/parsers/codex.js
|
|
1605
|
+
function defaultCodexRoot() {
|
|
1606
|
+
return join5(homedir2(), ".codex", "sessions");
|
|
1607
|
+
}
|
|
1608
|
+
var CodexHistoryParser = class {
|
|
1609
|
+
provider = "codex";
|
|
1610
|
+
root;
|
|
1611
|
+
constructor(options = {}) {
|
|
1612
|
+
this.root = options.root ?? defaultCodexRoot();
|
|
1613
|
+
}
|
|
1614
|
+
async discover() {
|
|
1615
|
+
const id = `${this.provider}:${this.root}`;
|
|
1616
|
+
const base = {
|
|
1617
|
+
id,
|
|
1618
|
+
provider: this.provider,
|
|
1619
|
+
path: this.root,
|
|
1620
|
+
nativeImport: true
|
|
1621
|
+
};
|
|
1622
|
+
try {
|
|
1623
|
+
const info = await stat2(this.root);
|
|
1624
|
+
if (!info.isDirectory()) {
|
|
1625
|
+
return [{ ...base, importable: false, reason: "path is not a directory" }];
|
|
1626
|
+
}
|
|
1627
|
+
} catch {
|
|
1628
|
+
return [{ ...base, importable: false, reason: "history directory not found" }];
|
|
1629
|
+
}
|
|
1630
|
+
const files = await glob2("*.json", { cwd: this.root });
|
|
1631
|
+
if (files.length === 0) {
|
|
1632
|
+
return [{ ...base, importable: false, reason: "no session state files found" }];
|
|
1633
|
+
}
|
|
1634
|
+
return [{ ...base, importable: true }];
|
|
1635
|
+
}
|
|
1636
|
+
async import(source) {
|
|
1637
|
+
const files = await glob2("*.json", { cwd: source.path, absolute: true });
|
|
1638
|
+
const results = [];
|
|
1639
|
+
for (const file of files) {
|
|
1640
|
+
let parsed;
|
|
1641
|
+
try {
|
|
1642
|
+
parsed = JSON.parse(await readFile7(file, "utf-8"));
|
|
1643
|
+
} catch {
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
1647
|
+
const events = [];
|
|
1648
|
+
const citations = [];
|
|
1649
|
+
let ordinal = 0;
|
|
1650
|
+
for (const m of messages) {
|
|
1651
|
+
if (!m || typeof m.content !== "string" || !m.content)
|
|
1652
|
+
continue;
|
|
1653
|
+
const timestamp = typeof m.timestamp === "string" ? Date.parse(m.timestamp) : Number.NaN;
|
|
1654
|
+
events.push({
|
|
1655
|
+
role: m.role ?? "user",
|
|
1656
|
+
content: m.content,
|
|
1657
|
+
toolName: m.toolName,
|
|
1658
|
+
ordinal: ordinal++,
|
|
1659
|
+
timestamp: Number.isNaN(timestamp) ? Date.now() : timestamp
|
|
1660
|
+
});
|
|
1661
|
+
citations.push({ sourcePath: file });
|
|
1662
|
+
}
|
|
1663
|
+
if (events.length === 0)
|
|
1664
|
+
continue;
|
|
1665
|
+
const sourceSessionId = parsed.id ?? file.replace(/\.json$/, "").split(/[/\\]/).pop() ?? file;
|
|
1666
|
+
const scope = parsed.cwd ? encodeProjectScope(parsed.cwd) : void 0;
|
|
1667
|
+
results.push({
|
|
1668
|
+
session: {
|
|
1669
|
+
id: `${source.provider}:${scope ?? ""}:${sourceSessionId}`,
|
|
1670
|
+
provider: source.provider,
|
|
1671
|
+
sourceSessionId,
|
|
1672
|
+
importedAt: Date.now(),
|
|
1673
|
+
scope
|
|
1674
|
+
},
|
|
1675
|
+
events,
|
|
1676
|
+
citations
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
return results;
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
// ../../packages/history/dist/registry.js
|
|
1684
|
+
var HistoryParserRegistry = class {
|
|
1685
|
+
parsers = /* @__PURE__ */ new Map();
|
|
1686
|
+
register(parser) {
|
|
1687
|
+
this.parsers.set(parser.provider, parser);
|
|
1688
|
+
}
|
|
1689
|
+
get(provider) {
|
|
1690
|
+
return this.parsers.get(provider);
|
|
1691
|
+
}
|
|
1692
|
+
list() {
|
|
1693
|
+
return [...this.parsers.values()];
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
// ../../packages/cli/dist/commands/history/shared.js
|
|
1698
|
+
function getHistoryDbPath() {
|
|
1699
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
|
|
1700
|
+
return `${home}/.omni-ai/history.db`;
|
|
1701
|
+
}
|
|
1702
|
+
function buildHistoryRegistry() {
|
|
1703
|
+
const registry = new HistoryParserRegistry();
|
|
1704
|
+
registry.register(new ClaudeCodeHistoryParser());
|
|
1705
|
+
registry.register(new CodexHistoryParser());
|
|
1706
|
+
return registry;
|
|
1707
|
+
}
|
|
1708
|
+
function openHistoryStore() {
|
|
1709
|
+
return new HistoryStore({ path: getHistoryDbPath() });
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// ../../packages/cli/dist/commands/history/doctor.js
|
|
1713
|
+
async function historyDoctorCommand(opts) {
|
|
1714
|
+
const store = openHistoryStore();
|
|
1715
|
+
try {
|
|
1716
|
+
const sources = store.listSources();
|
|
1717
|
+
const sessions = store.listSessions();
|
|
1718
|
+
const citations = store.listCitations();
|
|
1719
|
+
const notImportable = sources.filter((s) => !s.importable);
|
|
1720
|
+
const pathExists = /* @__PURE__ */ new Map();
|
|
1721
|
+
let brokenCitations = 0;
|
|
1722
|
+
for (const citation of citations) {
|
|
1723
|
+
let exists = pathExists.get(citation.sourcePath);
|
|
1724
|
+
if (exists === void 0) {
|
|
1725
|
+
exists = existsSync(citation.sourcePath);
|
|
1726
|
+
pathExists.set(citation.sourcePath, exists);
|
|
1727
|
+
}
|
|
1728
|
+
if (!exists)
|
|
1729
|
+
brokenCitations++;
|
|
1730
|
+
}
|
|
1731
|
+
const report = {
|
|
1732
|
+
sources: sources.length,
|
|
1733
|
+
notImportable: notImportable.map((s) => ({ provider: s.provider, path: s.path, reason: s.reason })),
|
|
1734
|
+
sessions: sessions.length,
|
|
1735
|
+
events: citations.length,
|
|
1736
|
+
brokenCitations
|
|
1737
|
+
};
|
|
1738
|
+
if (opts.json) {
|
|
1739
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
console.log(chalk5.bold("omni history doctor\n"));
|
|
1743
|
+
console.log(` sources: ${report.sources}`);
|
|
1744
|
+
console.log(` not importable: ${notImportable.length}`);
|
|
1745
|
+
for (const s of notImportable) {
|
|
1746
|
+
console.log(` ${chalk5.yellow("-")} ${s.provider}: ${s.reason} (${s.path})`);
|
|
1747
|
+
}
|
|
1748
|
+
console.log(` sessions: ${report.sessions}`);
|
|
1749
|
+
console.log(` citations: ${report.events}`);
|
|
1750
|
+
console.log(` broken citations: ${brokenCitations > 0 ? chalk5.yellow(String(brokenCitations)) : chalk5.green("0")}`);
|
|
1751
|
+
} finally {
|
|
1752
|
+
store.close();
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// ../../packages/cli/dist/commands/history/import.js
|
|
1757
|
+
import { basename } from "path";
|
|
1758
|
+
import chalk6 from "chalk";
|
|
1759
|
+
async function historyImportCommand(opts) {
|
|
1760
|
+
if (!opts.all && !opts.provider) {
|
|
1761
|
+
console.error(chalk6.red("Specify --provider <name> or --all."));
|
|
1762
|
+
process.exitCode = 1;
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
if (opts.path && (!opts.provider || opts.all)) {
|
|
1766
|
+
console.error(chalk6.red("--path requires a single --provider (not --all)."));
|
|
1767
|
+
process.exitCode = 1;
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
const registry = buildHistoryRegistry();
|
|
1771
|
+
const parsers = opts.all ? registry.list() : (() => {
|
|
1772
|
+
const parser = opts.provider ? registry.get(opts.provider) : void 0;
|
|
1773
|
+
return parser ? [parser] : [];
|
|
1774
|
+
})();
|
|
1775
|
+
if (parsers.length === 0) {
|
|
1776
|
+
const known = registry.list().map((p) => p.provider).join(", ");
|
|
1777
|
+
console.error(chalk6.red(`Unknown provider: "${opts.provider}". Registered: ${known || "(none)"}`));
|
|
1778
|
+
process.exitCode = 1;
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const store = openHistoryStore();
|
|
1782
|
+
try {
|
|
1783
|
+
for (const parser of parsers) {
|
|
1784
|
+
const sources = opts.path ? [
|
|
1785
|
+
{
|
|
1786
|
+
id: `${parser.provider}:${opts.path}`,
|
|
1787
|
+
provider: parser.provider,
|
|
1788
|
+
path: opts.path,
|
|
1789
|
+
nativeImport: true,
|
|
1790
|
+
importable: true,
|
|
1791
|
+
scope: basename(opts.path)
|
|
1792
|
+
}
|
|
1793
|
+
] : await parser.discover();
|
|
1794
|
+
for (const source of sources) {
|
|
1795
|
+
store.upsertSource(source);
|
|
1796
|
+
if (!source.importable) {
|
|
1797
|
+
console.log(chalk6.yellow(` - ${parser.provider}: skipped (${source.reason})`));
|
|
1798
|
+
continue;
|
|
1799
|
+
}
|
|
1800
|
+
const results = await parser.import(source);
|
|
1801
|
+
for (const result of results) {
|
|
1802
|
+
store.saveImportResult(parser.provider, result.session.id, result);
|
|
1803
|
+
}
|
|
1804
|
+
const eventCount = results.reduce((n, r) => n + r.events.length, 0);
|
|
1805
|
+
console.log(chalk6.green(` \u2713 ${parser.provider}: imported ${results.length} session(s), ${eventCount} event(s)`));
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
} finally {
|
|
1809
|
+
store.close();
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
// ../../packages/cli/dist/commands/history/locate.js
|
|
1814
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1815
|
+
import chalk7 from "chalk";
|
|
1816
|
+
async function historyLocateEventCommand(id, opts) {
|
|
1817
|
+
const store = openHistoryStore();
|
|
1818
|
+
try {
|
|
1819
|
+
const eventId = Number.parseInt(id, 10);
|
|
1820
|
+
const event = store.getEvent(eventId);
|
|
1821
|
+
if (!event) {
|
|
1822
|
+
console.error(chalk7.red(`Event ${id} not found.`));
|
|
1823
|
+
process.exitCode = 1;
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
const citation = store.getCitation(eventId);
|
|
1827
|
+
if (!citation) {
|
|
1828
|
+
console.error(chalk7.yellow(`No citation recorded for event ${id}.`));
|
|
1829
|
+
process.exitCode = 1;
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
const exists = existsSync2(citation.sourcePath);
|
|
1833
|
+
if (opts.json) {
|
|
1834
|
+
console.log(JSON.stringify({ citation, exists }, null, 2));
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
console.log(`${citation.sourcePath}${citation.sourceLine ? `:${citation.sourceLine}` : ""}`);
|
|
1838
|
+
if (!exists)
|
|
1839
|
+
console.log(chalk7.yellow(" ! source file no longer exists at this path"));
|
|
1840
|
+
} finally {
|
|
1841
|
+
store.close();
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
async function historyLocateSessionCommand(sessionId, opts) {
|
|
1845
|
+
const store = openHistoryStore();
|
|
1846
|
+
try {
|
|
1847
|
+
const events = store.listEvents(sessionId);
|
|
1848
|
+
if (events.length === 0) {
|
|
1849
|
+
console.error(chalk7.red(`Session "${sessionId}" not found or has no events.`));
|
|
1850
|
+
process.exitCode = 1;
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
const citation = store.getCitation(events[0].id);
|
|
1854
|
+
if (!citation) {
|
|
1855
|
+
console.error(chalk7.yellow("No citation recorded for this session."));
|
|
1856
|
+
process.exitCode = 1;
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
const exists = existsSync2(citation.sourcePath);
|
|
1860
|
+
if (opts.json) {
|
|
1861
|
+
console.log(JSON.stringify({ citation, exists }, null, 2));
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
console.log(citation.sourcePath);
|
|
1865
|
+
if (!exists)
|
|
1866
|
+
console.log(chalk7.yellow(" ! source file no longer exists at this path"));
|
|
1867
|
+
} finally {
|
|
1868
|
+
store.close();
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// ../../packages/cli/dist/commands/history/search.js
|
|
1873
|
+
import chalk8 from "chalk";
|
|
1874
|
+
async function refresh(mode, store, scope) {
|
|
1875
|
+
if (mode === "off")
|
|
1876
|
+
return { mode, ran: false };
|
|
1877
|
+
const registry = buildHistoryRegistry();
|
|
1878
|
+
try {
|
|
1879
|
+
for (const parser of registry.list()) {
|
|
1880
|
+
const sources = await parser.discover();
|
|
1881
|
+
const inScope = scope === void 0 ? sources : sources.filter((s) => s.scope === scope);
|
|
1882
|
+
for (const source of inScope) {
|
|
1883
|
+
store.upsertSource(source);
|
|
1884
|
+
if (!source.importable)
|
|
1885
|
+
continue;
|
|
1886
|
+
const results = await parser.import(source);
|
|
1887
|
+
for (const result of results)
|
|
1888
|
+
store.saveImportResult(parser.provider, result.session.id, result);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
return { mode, ran: true };
|
|
1892
|
+
} catch (err) {
|
|
1893
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1894
|
+
if (mode === "strict")
|
|
1895
|
+
throw new Error(message);
|
|
1896
|
+
return { mode, ran: false, error: message };
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
function toFtsQuery(terms) {
|
|
1900
|
+
return terms.map((t) => `"${t.replace(/"/g, '""')}"`).join(" ");
|
|
1901
|
+
}
|
|
1902
|
+
async function historySearchCommand(query, opts) {
|
|
1903
|
+
const terms = opts.term && opts.term.length > 0 ? opts.term : query ? [query] : [];
|
|
1904
|
+
if (terms.length === 0) {
|
|
1905
|
+
console.error(chalk8.red('Provide a query, e.g. omni history search "retry handling", or repeatable --term.'));
|
|
1906
|
+
process.exitCode = 1;
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
const mode = opts.refresh ?? "auto";
|
|
1910
|
+
const scope = opts.allProjects ? void 0 : opts.scope ?? encodeProjectScope(process.cwd());
|
|
1911
|
+
const store = openHistoryStore();
|
|
1912
|
+
try {
|
|
1913
|
+
let freshness;
|
|
1914
|
+
try {
|
|
1915
|
+
freshness = await refresh(mode, store, scope);
|
|
1916
|
+
} catch (err) {
|
|
1917
|
+
console.error(chalk8.red(`Refresh failed (--refresh strict): ${err instanceof Error ? err.message : String(err)}`));
|
|
1918
|
+
process.exitCode = 1;
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
const hits = store.search(toFtsQuery(terms), {
|
|
1922
|
+
sessionId: opts.session,
|
|
1923
|
+
scope,
|
|
1924
|
+
limit: opts.limit ? Number.parseInt(opts.limit, 10) : void 0
|
|
1925
|
+
});
|
|
1926
|
+
if (opts.json) {
|
|
1927
|
+
console.log(JSON.stringify({ freshness, scope: scope ?? null, hits }, null, 2));
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
if (freshness.error) {
|
|
1931
|
+
console.log(chalk8.gray(` (refresh skipped: ${freshness.error})
|
|
1932
|
+
`));
|
|
1933
|
+
}
|
|
1934
|
+
console.log(chalk8.gray(` scope: ${scope ?? "(all projects)"}
|
|
1935
|
+
`));
|
|
1936
|
+
if (hits.length === 0) {
|
|
1937
|
+
console.log(chalk8.gray("No results."));
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
for (const hit of hits) {
|
|
1941
|
+
console.log(`${chalk8.cyan(`[${hit.session.provider}]`)} ${chalk8.gray(hit.session.id)} ${chalk8.gray(`#${hit.event.id}`)}`);
|
|
1942
|
+
console.log(` ${hit.event.content.slice(0, 200).replace(/\n/g, " ")}
|
|
1943
|
+
`);
|
|
1944
|
+
}
|
|
1945
|
+
} finally {
|
|
1946
|
+
store.close();
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// ../../packages/cli/dist/commands/history/show.js
|
|
1951
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
1952
|
+
import chalk9 from "chalk";
|
|
1953
|
+
async function historyShowEventCommand(id, opts) {
|
|
1954
|
+
const store = openHistoryStore();
|
|
1955
|
+
try {
|
|
1956
|
+
const eventId = Number.parseInt(id, 10);
|
|
1957
|
+
const window = opts.window ? Number.parseInt(opts.window, 10) : 3;
|
|
1958
|
+
const events = store.getEventWindow(eventId, window);
|
|
1959
|
+
if (events.length === 0) {
|
|
1960
|
+
console.error(chalk9.red(`Event ${id} not found.`));
|
|
1961
|
+
process.exitCode = 1;
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
for (const e of events) {
|
|
1965
|
+
const marker = e.id === eventId ? chalk9.bold.cyan(">") : " ";
|
|
1966
|
+
console.log(`${marker} ${chalk9.cyan(`#${e.id}`)} ${chalk9.gray(e.role.padEnd(10))} ${e.content.slice(0, 300)}`);
|
|
1967
|
+
}
|
|
1968
|
+
} finally {
|
|
1969
|
+
store.close();
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
function formatSessionMarkdown(session, events) {
|
|
1973
|
+
const lines = [
|
|
1974
|
+
`# Session: ${session.provider} / ${session.sourceSessionId}`,
|
|
1975
|
+
`_Imported: ${new Date(session.importedAt).toISOString()}_`,
|
|
1976
|
+
""
|
|
1977
|
+
];
|
|
1978
|
+
for (const e of events) {
|
|
1979
|
+
lines.push(`### ${e.role} \u2014 #${e.id}`, "", e.content, "");
|
|
1980
|
+
}
|
|
1981
|
+
return lines.join("\n");
|
|
1982
|
+
}
|
|
1983
|
+
function formatSessionText(session, events) {
|
|
1984
|
+
const header = `Session: ${session.provider} / ${session.sourceSessionId}`;
|
|
1985
|
+
return [header, "", ...events.map((e) => `[${e.role}] ${e.content}`)].join("\n\n");
|
|
1986
|
+
}
|
|
1987
|
+
async function historyShowSessionCommand(sessionId, opts) {
|
|
1988
|
+
const store = openHistoryStore();
|
|
1989
|
+
try {
|
|
1990
|
+
const session = store.getSession(sessionId);
|
|
1991
|
+
if (!session) {
|
|
1992
|
+
console.error(chalk9.red(`Session "${sessionId}" not found.`));
|
|
1993
|
+
process.exitCode = 1;
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
const events = store.listEvents(sessionId);
|
|
1997
|
+
const format = opts.format ?? "text";
|
|
1998
|
+
const output = format === "markdown" ? formatSessionMarkdown(session, events) : formatSessionText(session, events);
|
|
1999
|
+
if (opts.out) {
|
|
2000
|
+
await writeFile5(opts.out, output, "utf-8");
|
|
2001
|
+
console.log(chalk9.green(`Session exported to: ${opts.out}`));
|
|
2002
|
+
} else {
|
|
2003
|
+
console.log(output);
|
|
2004
|
+
}
|
|
2005
|
+
} finally {
|
|
2006
|
+
store.close();
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// ../../packages/cli/dist/commands/history/sources.js
|
|
2011
|
+
import chalk10 from "chalk";
|
|
2012
|
+
async function historySourcesCommand(opts) {
|
|
2013
|
+
const registry = buildHistoryRegistry();
|
|
2014
|
+
const sources = (await Promise.all(registry.list().map((p) => p.discover()))).flat();
|
|
2015
|
+
if (opts.json) {
|
|
2016
|
+
console.log(JSON.stringify({ sources }, null, 2));
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
if (sources.length === 0) {
|
|
2020
|
+
console.log(chalk10.gray("No known providers registered."));
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
console.log(chalk10.bold(`Sources (${sources.length}):
|
|
2024
|
+
`));
|
|
2025
|
+
for (const s of sources) {
|
|
2026
|
+
const status = s.importable ? chalk10.green("importable") : chalk10.yellow(`not importable (${s.reason})`);
|
|
2027
|
+
console.log(` ${chalk10.cyan(s.provider.padEnd(14))} ${s.path}`);
|
|
2028
|
+
console.log(` ${" ".repeat(14)} scope=${s.scope ?? "(unscoped)"} native_import=${s.nativeImport} ${status}
|
|
2029
|
+
`);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
1158
2033
|
// ../../packages/cli/dist/commands/init.js
|
|
1159
|
-
import { access, readFile as
|
|
1160
|
-
import { dirname as
|
|
2034
|
+
import { access, readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
2035
|
+
import { dirname as dirname4, resolve as resolve9 } from "path";
|
|
1161
2036
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1162
2037
|
import { checkbox, confirm, input, password, select } from "@inquirer/prompts";
|
|
1163
|
-
import
|
|
1164
|
-
var __dirname =
|
|
2038
|
+
import chalk11 from "chalk";
|
|
2039
|
+
var __dirname = dirname4(fileURLToPath2(import.meta.url));
|
|
1165
2040
|
var OMNI_ROOT = resolve9(__dirname, "..", "..", "..", "..");
|
|
1166
2041
|
var CONFIG_PATH = resolve9(OMNI_ROOT, "config", "omni-ai.yaml");
|
|
1167
2042
|
var ENV_PATH = resolve9(OMNI_ROOT, ".env");
|
|
@@ -1176,7 +2051,7 @@ async function fileExists(path) {
|
|
|
1176
2051
|
async function readEnvFile(path) {
|
|
1177
2052
|
const map = /* @__PURE__ */ new Map();
|
|
1178
2053
|
try {
|
|
1179
|
-
const content = await
|
|
2054
|
+
const content = await readFile8(path, "utf-8");
|
|
1180
2055
|
for (const line of content.split("\n")) {
|
|
1181
2056
|
const trimmed = line.trim();
|
|
1182
2057
|
if (!trimmed || trimmed.startsWith("#"))
|
|
@@ -1259,9 +2134,9 @@ agents:
|
|
|
1259
2134
|
}
|
|
1260
2135
|
async function setupCopilot() {
|
|
1261
2136
|
console.log();
|
|
1262
|
-
console.log(
|
|
1263
|
-
console.log(
|
|
1264
|
-
console.log(
|
|
2137
|
+
console.log(chalk11.dim(" Para obter seu token GitHub:"));
|
|
2138
|
+
console.log(chalk11.dim(" gh auth login # se ainda n\xE3o fez"));
|
|
2139
|
+
console.log(chalk11.dim(" gh auth token # mostra o token atual"));
|
|
1265
2140
|
console.log();
|
|
1266
2141
|
const token = await password({
|
|
1267
2142
|
message: "Cole seu GitHub token (ghp_... ou github_pat_...):",
|
|
@@ -1286,8 +2161,8 @@ async function setupCopilot() {
|
|
|
1286
2161
|
}
|
|
1287
2162
|
async function setupAnthropic() {
|
|
1288
2163
|
console.log();
|
|
1289
|
-
console.log(
|
|
1290
|
-
console.log(
|
|
2164
|
+
console.log(chalk11.dim(" Como obter: https://console.anthropic.com \u2192 API Keys \u2192 Create key"));
|
|
2165
|
+
console.log(chalk11.dim(" Formato: sk-ant-api03-..."));
|
|
1291
2166
|
console.log();
|
|
1292
2167
|
const key = await password({
|
|
1293
2168
|
message: "Cole sua Anthropic API key:",
|
|
@@ -1311,8 +2186,8 @@ async function setupAnthropic() {
|
|
|
1311
2186
|
}
|
|
1312
2187
|
async function setupOpenAI() {
|
|
1313
2188
|
console.log();
|
|
1314
|
-
console.log(
|
|
1315
|
-
console.log(
|
|
2189
|
+
console.log(chalk11.dim(" Como obter: https://platform.openai.com \u2192 API keys \u2192 Create new secret key"));
|
|
2190
|
+
console.log(chalk11.dim(" Formato: sk-proj-... (novo) ou sk-... (legado)"));
|
|
1316
2191
|
console.log();
|
|
1317
2192
|
const key = await password({
|
|
1318
2193
|
message: "Cole sua OpenAI API key:",
|
|
@@ -1337,10 +2212,10 @@ async function setupOpenAI() {
|
|
|
1337
2212
|
}
|
|
1338
2213
|
async function setupCustom() {
|
|
1339
2214
|
console.log();
|
|
1340
|
-
console.log(
|
|
1341
|
-
console.log(
|
|
1342
|
-
console.log(
|
|
1343
|
-
console.log(
|
|
2215
|
+
console.log(chalk11.dim(" Compat\xEDvel com qualquer endpoint OpenAI-like:"));
|
|
2216
|
+
console.log(chalk11.dim(" Ollama: http://localhost:11434/v1"));
|
|
2217
|
+
console.log(chalk11.dim(" Groq: https://api.groq.com/openai/v1"));
|
|
2218
|
+
console.log(chalk11.dim(" Azure: https://<resource>.openai.azure.com"));
|
|
1344
2219
|
console.log();
|
|
1345
2220
|
const baseUrl = await input({
|
|
1346
2221
|
message: "Base URL do endpoint:",
|
|
@@ -1392,16 +2267,16 @@ async function selectProvider(label) {
|
|
|
1392
2267
|
}
|
|
1393
2268
|
async function initCommand() {
|
|
1394
2269
|
console.log();
|
|
1395
|
-
console.log(
|
|
1396
|
-
console.log(
|
|
2270
|
+
console.log(chalk11.bold(" omni-ai \u2014 configura\xE7\xE3o inicial"));
|
|
2271
|
+
console.log(chalk11.dim(" Isso vai criar config/omni-ai.yaml e atualizar o .env"));
|
|
1397
2272
|
console.log();
|
|
1398
2273
|
if (await fileExists(CONFIG_PATH)) {
|
|
1399
2274
|
const overwrite = await confirm({
|
|
1400
|
-
message:
|
|
2275
|
+
message: chalk11.yellow("config/omni-ai.yaml j\xE1 existe. Sobrescrever?"),
|
|
1401
2276
|
default: false
|
|
1402
2277
|
});
|
|
1403
2278
|
if (!overwrite) {
|
|
1404
|
-
console.log(
|
|
2279
|
+
console.log(chalk11.dim("\n Opera\xE7\xE3o cancelada.\n"));
|
|
1405
2280
|
return;
|
|
1406
2281
|
}
|
|
1407
2282
|
}
|
|
@@ -1417,7 +2292,7 @@ async function initCommand() {
|
|
|
1417
2292
|
if (second.name !== primary.name) {
|
|
1418
2293
|
extras.push(second);
|
|
1419
2294
|
} else {
|
|
1420
|
-
console.log(
|
|
2295
|
+
console.log(chalk11.dim(" Mesmo provider \u2014 ignorado."));
|
|
1421
2296
|
}
|
|
1422
2297
|
}
|
|
1423
2298
|
const agentSets = await checkbox({
|
|
@@ -1444,92 +2319,92 @@ async function initCommand() {
|
|
|
1444
2319
|
const envTemplatePath = resolve9(OMNI_ROOT, ".env.example");
|
|
1445
2320
|
let envTemplate = "";
|
|
1446
2321
|
try {
|
|
1447
|
-
envTemplate = await
|
|
2322
|
+
envTemplate = await readFile8(envTemplatePath, "utf-8");
|
|
1448
2323
|
} catch {
|
|
1449
2324
|
envTemplate = Array.from(envEntries.entries()).map(([k, v]) => `${k}=${v}`).join("\n");
|
|
1450
2325
|
}
|
|
1451
2326
|
const envContent = buildEnvFile(envEntries, envTemplate);
|
|
1452
2327
|
const yamlContent = buildYaml(primary, extras);
|
|
1453
|
-
await
|
|
1454
|
-
await
|
|
2328
|
+
await writeFile6(CONFIG_PATH, yamlContent, "utf-8");
|
|
2329
|
+
await writeFile6(ENV_PATH, envContent, "utf-8");
|
|
1455
2330
|
console.log();
|
|
1456
|
-
console.log(`${
|
|
1457
|
-
console.log(`${
|
|
2331
|
+
console.log(`${chalk11.green(" \u2713")} config/omni-ai.yaml criado`);
|
|
2332
|
+
console.log(`${chalk11.green(" \u2713")} .env atualizado`);
|
|
1458
2333
|
console.log();
|
|
1459
|
-
console.log(
|
|
2334
|
+
console.log(chalk11.bold(" Pr\xF3ximos passos:"));
|
|
1460
2335
|
console.log();
|
|
1461
|
-
console.log(
|
|
1462
|
-
console.log(
|
|
2336
|
+
console.log(chalk11.cyan(" omni list agents") + chalk11.dim(" # ver todos os agentes dispon\xEDveis"));
|
|
2337
|
+
console.log(chalk11.cyan(" omni run code-reviewer") + chalk11.dim(' "revise src/app.ts"'));
|
|
1463
2338
|
console.log();
|
|
1464
2339
|
if (agentSets.includes("backend")) {
|
|
1465
|
-
console.log(
|
|
2340
|
+
console.log(chalk11.cyan(" omni run backend-dev") + chalk11.dim(' "crie o m\xF3dulo de pedidos"'));
|
|
1466
2341
|
}
|
|
1467
2342
|
if (agentSets.includes("frontend")) {
|
|
1468
|
-
console.log(
|
|
2343
|
+
console.log(chalk11.cyan(" omni run frontend-dev") + chalk11.dim(' "crie a p\xE1gina de listagem de pedidos"'));
|
|
1469
2344
|
}
|
|
1470
2345
|
if (agentSets.includes("ux")) {
|
|
1471
|
-
console.log(
|
|
2346
|
+
console.log(chalk11.cyan(" omni run ux-lead") + chalk11.dim(' "audite o componente OrderForm"'));
|
|
1472
2347
|
}
|
|
1473
2348
|
if (agentSets.includes("qa")) {
|
|
1474
|
-
console.log(
|
|
2349
|
+
console.log(chalk11.cyan(" omni run qa-lead") + chalk11.dim(' "valide src/orders/"'));
|
|
1475
2350
|
}
|
|
1476
2351
|
console.log();
|
|
1477
|
-
console.log(
|
|
1478
|
-
console.log(
|
|
1479
|
-
console.log(
|
|
2352
|
+
console.log(chalk11.dim(" Para usar de outro projeto:"));
|
|
2353
|
+
console.log(chalk11.dim(" cd /caminho/para/meu-projeto"));
|
|
2354
|
+
console.log(chalk11.cyan(" omni run backend-dev") + chalk11.dim(' "..."'));
|
|
1480
2355
|
console.log();
|
|
1481
2356
|
}
|
|
1482
2357
|
|
|
1483
2358
|
// ../../packages/cli/dist/commands/list.js
|
|
1484
|
-
import
|
|
2359
|
+
import chalk12 from "chalk";
|
|
1485
2360
|
async function listCommand(target, opts) {
|
|
1486
2361
|
const configPath = opts.config ?? resolveConfigPath();
|
|
1487
2362
|
if (target === "providers") {
|
|
1488
2363
|
await import("../dist-Z76P5KV4.js");
|
|
1489
2364
|
await import("../dist-KBUP5623.js");
|
|
1490
2365
|
const names = getRegisteredProviders();
|
|
1491
|
-
console.log(
|
|
2366
|
+
console.log(chalk12.bold("Registered providers:"));
|
|
1492
2367
|
for (const name of names) {
|
|
1493
|
-
console.log(` ${
|
|
2368
|
+
console.log(` ${chalk12.cyan("\xB7")} ${name}`);
|
|
1494
2369
|
}
|
|
1495
2370
|
return;
|
|
1496
2371
|
}
|
|
1497
2372
|
const runtime = await createRuntime({ configPath }).catch(() => null);
|
|
1498
2373
|
if (target === "agents") {
|
|
1499
2374
|
if (!runtime) {
|
|
1500
|
-
console.error(
|
|
2375
|
+
console.error(chalk12.red("Could not load config. Run from the omni-ai directory or pass --config."));
|
|
1501
2376
|
process.exit(1);
|
|
1502
2377
|
}
|
|
1503
2378
|
const agents = await runtime.listAgents();
|
|
1504
2379
|
if (agents.length === 0) {
|
|
1505
|
-
console.log(
|
|
2380
|
+
console.log(chalk12.gray("No agents found."));
|
|
1506
2381
|
return;
|
|
1507
2382
|
}
|
|
1508
|
-
console.log(
|
|
2383
|
+
console.log(chalk12.bold(`Agents (${agents.length}):
|
|
1509
2384
|
`));
|
|
1510
2385
|
for (const agent of agents) {
|
|
1511
|
-
console.log(` ${
|
|
2386
|
+
console.log(` ${chalk12.cyan(agent.name.padEnd(30))} ${chalk12.gray(agent.description)}`);
|
|
1512
2387
|
}
|
|
1513
2388
|
return;
|
|
1514
2389
|
}
|
|
1515
2390
|
if (target === "skills") {
|
|
1516
2391
|
if (!runtime) {
|
|
1517
|
-
console.error(
|
|
2392
|
+
console.error(chalk12.red("Could not load config."));
|
|
1518
2393
|
process.exit(1);
|
|
1519
2394
|
}
|
|
1520
2395
|
const skills2 = runtime.skills.all();
|
|
1521
2396
|
if (skills2.length === 0) {
|
|
1522
|
-
console.log(
|
|
2397
|
+
console.log(chalk12.gray("No skills registered."));
|
|
1523
2398
|
return;
|
|
1524
2399
|
}
|
|
1525
|
-
console.log(
|
|
2400
|
+
console.log(chalk12.bold(`Skills (${skills2.length}):
|
|
1526
2401
|
`));
|
|
1527
2402
|
for (const skill of skills2) {
|
|
1528
|
-
console.log(` ${
|
|
2403
|
+
console.log(` ${chalk12.yellow(skill.name.padEnd(25))} ${chalk12.gray(skill.description)}`);
|
|
1529
2404
|
}
|
|
1530
2405
|
return;
|
|
1531
2406
|
}
|
|
1532
|
-
console.error(
|
|
2407
|
+
console.error(chalk12.red(`Unknown list target: "${target}". Use: agents | skills | providers`));
|
|
1533
2408
|
process.exit(1);
|
|
1534
2409
|
}
|
|
1535
2410
|
|
|
@@ -1583,7 +2458,7 @@ async function serveStdioMcp(skills2, options) {
|
|
|
1583
2458
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
1584
2459
|
|
|
1585
2460
|
// ../../packages/skills/dist/backend/analyze-dynamo-schema.js
|
|
1586
|
-
import { readFile as
|
|
2461
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
1587
2462
|
import { resolve as resolve10 } from "path";
|
|
1588
2463
|
import { z as z13 } from "zod";
|
|
1589
2464
|
var InputSchema12 = z13.object({
|
|
@@ -1651,7 +2526,7 @@ var analyzeDynamoSchemaSkill = {
|
|
|
1651
2526
|
description: "Parse a OneTable *.model.ts file and extract the schema name, entity type, fields (with types and required flags), enums, and Typenames references. Use this before generating a service to understand the exact entity shape.",
|
|
1652
2527
|
async execute(input5) {
|
|
1653
2528
|
const { path } = InputSchema12.parse(input5);
|
|
1654
|
-
const source = await
|
|
2529
|
+
const source = await readFile9(resolve10(path), "utf-8");
|
|
1655
2530
|
return {
|
|
1656
2531
|
schemaName: extractSchemaName(source),
|
|
1657
2532
|
entityType: extractEntityType(source),
|
|
@@ -1663,7 +2538,7 @@ var analyzeDynamoSchemaSkill = {
|
|
|
1663
2538
|
};
|
|
1664
2539
|
|
|
1665
2540
|
// ../../packages/skills/dist/backend/analyze-graphql-schema.js
|
|
1666
|
-
import { readFile as
|
|
2541
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
1667
2542
|
import { resolve as resolve11 } from "path";
|
|
1668
2543
|
import { z as z14 } from "zod";
|
|
1669
2544
|
var InputSchema13 = z14.object({
|
|
@@ -1705,7 +2580,7 @@ var analyzeGraphqlSchemaSkill = {
|
|
|
1705
2580
|
description: "Parse a GraphQL SDL file and extract types, queries, mutations, inputs and enums. Use this before generating a resolver to understand what operations already exist and what the correct return types are.",
|
|
1706
2581
|
async execute(input5) {
|
|
1707
2582
|
const { path } = InputSchema13.parse(input5);
|
|
1708
|
-
const source = await
|
|
2583
|
+
const source = await readFile10(resolve11(path), "utf-8");
|
|
1709
2584
|
return {
|
|
1710
2585
|
types: extractTypes(source),
|
|
1711
2586
|
queries: extractOperations(source, "Query"),
|
|
@@ -1717,7 +2592,7 @@ var analyzeGraphqlSchemaSkill = {
|
|
|
1717
2592
|
};
|
|
1718
2593
|
|
|
1719
2594
|
// ../../packages/skills/dist/backend/analyze-nestjs-module.js
|
|
1720
|
-
import { readFile as
|
|
2595
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
1721
2596
|
import { resolve as resolve12 } from "path";
|
|
1722
2597
|
import { z as z15 } from "zod";
|
|
1723
2598
|
var InputSchema14 = z15.object({
|
|
@@ -1739,7 +2614,7 @@ var analyzeNestjsModuleSkill = {
|
|
|
1739
2614
|
description: "Parse a NestJS *.module.ts file and extract its imports, providers, exports and controllers. Use this to understand what a module exposes before adding new providers or resolving injection dependencies.",
|
|
1740
2615
|
async execute(input5) {
|
|
1741
2616
|
const { path } = InputSchema14.parse(input5);
|
|
1742
|
-
const source = await
|
|
2617
|
+
const source = await readFile11(resolve12(path), "utf-8");
|
|
1743
2618
|
return {
|
|
1744
2619
|
moduleName: extractModuleName(source),
|
|
1745
2620
|
imports: extractArrayItems(source, "imports"),
|
|
@@ -1751,8 +2626,8 @@ var analyzeNestjsModuleSkill = {
|
|
|
1751
2626
|
};
|
|
1752
2627
|
|
|
1753
2628
|
// ../../packages/skills/dist/backend/find-code-pattern.js
|
|
1754
|
-
import { readdir as
|
|
1755
|
-
import { join as
|
|
2629
|
+
import { readdir as readdir5, readFile as readFile12 } from "fs/promises";
|
|
2630
|
+
import { join as join6 } from "path";
|
|
1756
2631
|
import { z as z16 } from "zod";
|
|
1757
2632
|
var patternSuffixes = {
|
|
1758
2633
|
service: [".service.ts"],
|
|
@@ -1770,7 +2645,7 @@ var InputSchema15 = z16.object({
|
|
|
1770
2645
|
async function walkForPattern(dir, suffixes, results, max) {
|
|
1771
2646
|
if (results.length >= max)
|
|
1772
2647
|
return;
|
|
1773
|
-
const entries = await
|
|
2648
|
+
const entries = await readdir5(dir, { withFileTypes: true }).catch(() => null);
|
|
1774
2649
|
if (!entries)
|
|
1775
2650
|
return;
|
|
1776
2651
|
for (const entry of entries) {
|
|
@@ -1778,11 +2653,11 @@ async function walkForPattern(dir, suffixes, results, max) {
|
|
|
1778
2653
|
break;
|
|
1779
2654
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
1780
2655
|
continue;
|
|
1781
|
-
const fullPath =
|
|
2656
|
+
const fullPath = join6(dir, entry.name);
|
|
1782
2657
|
if (entry.isDirectory()) {
|
|
1783
2658
|
await walkForPattern(fullPath, suffixes, results, max);
|
|
1784
2659
|
} else if (entry.isFile() && suffixes.some((s) => entry.name.endsWith(s))) {
|
|
1785
|
-
const content = await
|
|
2660
|
+
const content = await readFile12(fullPath, "utf-8");
|
|
1786
2661
|
results.push({ file: fullPath, content });
|
|
1787
2662
|
}
|
|
1788
2663
|
}
|
|
@@ -1800,7 +2675,7 @@ var findCodePatternSkill = {
|
|
|
1800
2675
|
};
|
|
1801
2676
|
|
|
1802
2677
|
// ../../packages/skills/dist/frontend/analyze-component.js
|
|
1803
|
-
import { readFile as
|
|
2678
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
1804
2679
|
import { resolve as resolve13 } from "path";
|
|
1805
2680
|
import { z as z17 } from "zod";
|
|
1806
2681
|
var InputSchema16 = z17.object({
|
|
@@ -1834,7 +2709,7 @@ var analyzeComponentSkill = {
|
|
|
1834
2709
|
description: "Parse a React component file and extract its name, props interface, hooks used, named exports, and whether it has a default export. Use this to understand an existing component's contract before creating a related component or hook.",
|
|
1835
2710
|
async execute(input5) {
|
|
1836
2711
|
const { path } = InputSchema16.parse(input5);
|
|
1837
|
-
const source = await
|
|
2712
|
+
const source = await readFile13(resolve13(path), "utf-8");
|
|
1838
2713
|
return {
|
|
1839
2714
|
componentName: extractComponentName(source, path),
|
|
1840
2715
|
propsInterface: extractPropsInterface(source),
|
|
@@ -1846,21 +2721,21 @@ var analyzeComponentSkill = {
|
|
|
1846
2721
|
};
|
|
1847
2722
|
|
|
1848
2723
|
// ../../packages/skills/dist/frontend/analyze-module-structure.js
|
|
1849
|
-
import { readdir as
|
|
1850
|
-
import { join as
|
|
2724
|
+
import { readdir as readdir6 } from "fs/promises";
|
|
2725
|
+
import { join as join7 } from "path";
|
|
1851
2726
|
import { z as z18 } from "zod";
|
|
1852
2727
|
var InputSchema17 = z18.object({
|
|
1853
2728
|
directory: z18.string().describe("Root directory of the React module or feature folder")
|
|
1854
2729
|
});
|
|
1855
2730
|
async function collectFiles2(dir) {
|
|
1856
|
-
const entries = await
|
|
2731
|
+
const entries = await readdir6(dir, { withFileTypes: true }).catch(() => null);
|
|
1857
2732
|
if (!entries)
|
|
1858
2733
|
return [];
|
|
1859
2734
|
const files = [];
|
|
1860
2735
|
for (const entry of entries) {
|
|
1861
2736
|
if (entry.name === "node_modules" || entry.name === "dist")
|
|
1862
2737
|
continue;
|
|
1863
|
-
const fullPath =
|
|
2738
|
+
const fullPath = join7(dir, entry.name);
|
|
1864
2739
|
if (entry.isDirectory()) {
|
|
1865
2740
|
files.push(...await collectFiles2(fullPath));
|
|
1866
2741
|
} else if (entry.isFile() && /\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
@@ -1899,8 +2774,8 @@ var analyzeModuleStructureSkill = {
|
|
|
1899
2774
|
};
|
|
1900
2775
|
|
|
1901
2776
|
// ../../packages/skills/dist/frontend/find-component-pattern.js
|
|
1902
|
-
import { readdir as
|
|
1903
|
-
import { join as
|
|
2777
|
+
import { readdir as readdir7, readFile as readFile14 } from "fs/promises";
|
|
2778
|
+
import { join as join8 } from "path";
|
|
1904
2779
|
import { z as z19 } from "zod";
|
|
1905
2780
|
var patternFilters = {
|
|
1906
2781
|
component: (name) => /^[A-Z]/.test(name) && (name.endsWith(".tsx") || name.endsWith(".ts")) && !name.includes(".spec."),
|
|
@@ -1916,7 +2791,7 @@ var InputSchema18 = z19.object({
|
|
|
1916
2791
|
async function walkForComponent(dir, filter, results, max) {
|
|
1917
2792
|
if (results.length >= max)
|
|
1918
2793
|
return;
|
|
1919
|
-
const entries = await
|
|
2794
|
+
const entries = await readdir7(dir, { withFileTypes: true }).catch(() => null);
|
|
1920
2795
|
if (!entries)
|
|
1921
2796
|
return;
|
|
1922
2797
|
for (const entry of entries) {
|
|
@@ -1924,11 +2799,11 @@ async function walkForComponent(dir, filter, results, max) {
|
|
|
1924
2799
|
break;
|
|
1925
2800
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
1926
2801
|
continue;
|
|
1927
|
-
const fullPath =
|
|
2802
|
+
const fullPath = join8(dir, entry.name);
|
|
1928
2803
|
if (entry.isDirectory()) {
|
|
1929
2804
|
await walkForComponent(fullPath, filter, results, max);
|
|
1930
2805
|
} else if (entry.isFile() && filter(entry.name)) {
|
|
1931
|
-
const content = await
|
|
2806
|
+
const content = await readFile14(fullPath, "utf-8");
|
|
1932
2807
|
results.push({ file: fullPath, content });
|
|
1933
2808
|
}
|
|
1934
2809
|
}
|
|
@@ -1946,8 +2821,8 @@ var findComponentPatternSkill = {
|
|
|
1946
2821
|
};
|
|
1947
2822
|
|
|
1948
2823
|
// ../../packages/skills/dist/qa/analyze-test-coverage.js
|
|
1949
|
-
import { readdir as
|
|
1950
|
-
import { join as
|
|
2824
|
+
import { readdir as readdir8 } from "fs/promises";
|
|
2825
|
+
import { join as join9 } from "path";
|
|
1951
2826
|
import { z as z20 } from "zod";
|
|
1952
2827
|
var InputSchema19 = z20.object({
|
|
1953
2828
|
directory: z20.string().describe("Root directory to scan for source files and their tests"),
|
|
@@ -1955,14 +2830,14 @@ var InputSchema19 = z20.object({
|
|
|
1955
2830
|
ignorePatterns: z20.array(z20.string()).default(["index.ts", "index.tsx", ".spec.", ".test.", ".d.ts", ".module.ts"]).describe("Substrings that mark files to skip (index, spec, declaration, module files)")
|
|
1956
2831
|
});
|
|
1957
2832
|
async function collectFiles3(dir, exts, ignore) {
|
|
1958
|
-
const entries = await
|
|
2833
|
+
const entries = await readdir8(dir, { withFileTypes: true }).catch(() => null);
|
|
1959
2834
|
if (!entries)
|
|
1960
2835
|
return [];
|
|
1961
2836
|
const files = [];
|
|
1962
2837
|
for (const entry of entries) {
|
|
1963
2838
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
1964
2839
|
continue;
|
|
1965
|
-
const fullPath =
|
|
2840
|
+
const fullPath = join9(dir, entry.name);
|
|
1966
2841
|
if (entry.isDirectory()) {
|
|
1967
2842
|
files.push(...await collectFiles3(fullPath, exts, ignore));
|
|
1968
2843
|
} else if (entry.isFile() && exts.some((e) => entry.name.endsWith(e)) && !ignore.some((p) => entry.name.includes(p) || fullPath.includes(p))) {
|
|
@@ -2005,8 +2880,8 @@ var analyzeTestCoverageSkill = {
|
|
|
2005
2880
|
};
|
|
2006
2881
|
|
|
2007
2882
|
// ../../packages/skills/dist/qa/find-test-pattern.js
|
|
2008
|
-
import { readdir as
|
|
2009
|
-
import { join as
|
|
2883
|
+
import { readdir as readdir9, readFile as readFile15 } from "fs/promises";
|
|
2884
|
+
import { join as join10 } from "path";
|
|
2010
2885
|
import { z as z21 } from "zod";
|
|
2011
2886
|
var patternFilters2 = {
|
|
2012
2887
|
service: (name) => name.endsWith(".service.spec.ts"),
|
|
@@ -2022,7 +2897,7 @@ var InputSchema20 = z21.object({
|
|
|
2022
2897
|
async function walkForTests(dir, filter, results, max) {
|
|
2023
2898
|
if (results.length >= max)
|
|
2024
2899
|
return;
|
|
2025
|
-
const entries = await
|
|
2900
|
+
const entries = await readdir9(dir, { withFileTypes: true }).catch(() => null);
|
|
2026
2901
|
if (!entries)
|
|
2027
2902
|
return;
|
|
2028
2903
|
for (const entry of entries) {
|
|
@@ -2030,11 +2905,11 @@ async function walkForTests(dir, filter, results, max) {
|
|
|
2030
2905
|
break;
|
|
2031
2906
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
2032
2907
|
continue;
|
|
2033
|
-
const fullPath =
|
|
2908
|
+
const fullPath = join10(dir, entry.name);
|
|
2034
2909
|
if (entry.isDirectory()) {
|
|
2035
2910
|
await walkForTests(fullPath, filter, results, max);
|
|
2036
2911
|
} else if (entry.isFile() && filter(entry.name)) {
|
|
2037
|
-
const content = await
|
|
2912
|
+
const content = await readFile15(fullPath, "utf-8");
|
|
2038
2913
|
results.push({ file: fullPath, content });
|
|
2039
2914
|
}
|
|
2040
2915
|
}
|
|
@@ -2052,7 +2927,7 @@ var findTestPatternSkill = {
|
|
|
2052
2927
|
};
|
|
2053
2928
|
|
|
2054
2929
|
// ../../packages/cli/dist/commands/mcp-serve.js
|
|
2055
|
-
import
|
|
2930
|
+
import chalk13 from "chalk";
|
|
2056
2931
|
var skills = [
|
|
2057
2932
|
readFileSkill,
|
|
2058
2933
|
writeFileSkill,
|
|
@@ -2073,32 +2948,34 @@ var skills = [
|
|
|
2073
2948
|
analyzeComponentSkill,
|
|
2074
2949
|
analyzeModuleStructureSkill,
|
|
2075
2950
|
findTestPatternSkill,
|
|
2076
|
-
analyzeTestCoverageSkill
|
|
2951
|
+
analyzeTestCoverageSkill,
|
|
2952
|
+
searchHistorySkill,
|
|
2953
|
+
showEventSkill
|
|
2077
2954
|
];
|
|
2078
2955
|
async function mcpServeCommand() {
|
|
2079
|
-
process.stderr.write(
|
|
2080
|
-
process.stderr.write(
|
|
2956
|
+
process.stderr.write(chalk13.bold.cyan("\n\u25C6 omni mcp serve\n"));
|
|
2957
|
+
process.stderr.write(chalk13.gray(` Transport: stdio
|
|
2081
2958
|
`));
|
|
2082
|
-
process.stderr.write(
|
|
2959
|
+
process.stderr.write(chalk13.gray(` Skills: ${skills.length}
|
|
2083
2960
|
`));
|
|
2084
|
-
process.stderr.write(
|
|
2961
|
+
process.stderr.write(chalk13.gray("\n Waiting for MCP client connection\u2026\n\n"));
|
|
2085
2962
|
await serveStdioMcp(skills, { name: "omni-ai" });
|
|
2086
2963
|
await new Promise(() => {
|
|
2087
2964
|
});
|
|
2088
2965
|
}
|
|
2089
2966
|
|
|
2090
2967
|
// ../../packages/cli/dist/commands/new.js
|
|
2091
|
-
import { readFile as
|
|
2092
|
-
import { join as
|
|
2968
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
2969
|
+
import { join as join14 } from "path";
|
|
2093
2970
|
import { select as select4 } from "@inquirer/prompts";
|
|
2094
|
-
import
|
|
2971
|
+
import chalk17 from "chalk";
|
|
2095
2972
|
import YAML from "yaml";
|
|
2096
2973
|
|
|
2097
2974
|
// ../../packages/cli/dist/commands/new/scaffold-agent.js
|
|
2098
|
-
import { access as access2, mkdir as mkdir2, writeFile as
|
|
2099
|
-
import { join as
|
|
2975
|
+
import { access as access2, mkdir as mkdir2, writeFile as writeFile7 } from "fs/promises";
|
|
2976
|
+
import { join as join11, resolve as resolve14 } from "path";
|
|
2100
2977
|
import { checkbox as checkbox2, confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
|
|
2101
|
-
import
|
|
2978
|
+
import chalk14 from "chalk";
|
|
2102
2979
|
|
|
2103
2980
|
// ../../packages/cli/dist/commands/new/templates.js
|
|
2104
2981
|
function kebabToPascal(s) {
|
|
@@ -2241,7 +3118,7 @@ var ALL_SKILLS = [
|
|
|
2241
3118
|
];
|
|
2242
3119
|
async function writeAgentFile(params, agentsDir) {
|
|
2243
3120
|
const dir = resolve14(process.cwd(), agentsDir, params.domain);
|
|
2244
|
-
const filePath =
|
|
3121
|
+
const filePath = join11(dir, `${params.domain}-${params.role}.yaml`);
|
|
2245
3122
|
const content = generateAgentYaml({
|
|
2246
3123
|
name: `${params.domain}-${params.role}`,
|
|
2247
3124
|
description: params.description,
|
|
@@ -2251,7 +3128,7 @@ async function writeAgentFile(params, agentsDir) {
|
|
|
2251
3128
|
temperature: 0.3
|
|
2252
3129
|
});
|
|
2253
3130
|
await mkdir2(dir, { recursive: true });
|
|
2254
|
-
await
|
|
3131
|
+
await writeFile7(filePath, content, "utf-8");
|
|
2255
3132
|
return filePath;
|
|
2256
3133
|
}
|
|
2257
3134
|
async function agentWizard(agentsDir) {
|
|
@@ -2283,38 +3160,38 @@ async function agentWizard(agentsDir) {
|
|
|
2283
3160
|
});
|
|
2284
3161
|
const outPath = resolve14(process.cwd(), agentsDir, domain, `${domain}-${role}.yaml`);
|
|
2285
3162
|
console.log();
|
|
2286
|
-
console.log(
|
|
3163
|
+
console.log(chalk14.dim(` Destino: ${outPath}`));
|
|
2287
3164
|
let shouldWrite = true;
|
|
2288
3165
|
try {
|
|
2289
3166
|
await access2(outPath);
|
|
2290
|
-
shouldWrite = await confirm2({ message:
|
|
3167
|
+
shouldWrite = await confirm2({ message: chalk14.yellow("Arquivo j\xE1 existe. Sobrescrever?"), default: false });
|
|
2291
3168
|
} catch {
|
|
2292
3169
|
}
|
|
2293
3170
|
if (!shouldWrite) {
|
|
2294
|
-
console.log(
|
|
3171
|
+
console.log(chalk14.dim("\n Opera\xE7\xE3o cancelada.\n"));
|
|
2295
3172
|
return;
|
|
2296
3173
|
}
|
|
2297
3174
|
const filePath = await writeAgentFile({ domain, role, description, systemPrompt, skills: skills2 }, agentsDir);
|
|
2298
3175
|
console.log();
|
|
2299
|
-
console.log(`${
|
|
2300
|
-
console.log(
|
|
2301
|
-
console.log(
|
|
3176
|
+
console.log(`${chalk14.green(" \u2713")} Agente criado: ${chalk14.cyan(filePath)}`);
|
|
3177
|
+
console.log(chalk14.dim(" Adicione ao omni-ai.yaml (se\xE7\xE3o agents:) ou coloque no agentsDir para uso autom\xE1tico."));
|
|
3178
|
+
console.log(chalk14.dim(` Testar: omni run ${domain}-${role} "sua tarefa aqui"`));
|
|
2302
3179
|
console.log();
|
|
2303
3180
|
}
|
|
2304
3181
|
|
|
2305
3182
|
// ../../packages/cli/dist/commands/new/scaffold-provider.js
|
|
2306
|
-
import { access as access3, mkdir as mkdir3, writeFile as
|
|
2307
|
-
import { join as
|
|
3183
|
+
import { access as access3, mkdir as mkdir3, writeFile as writeFile8 } from "fs/promises";
|
|
3184
|
+
import { join as join12, resolve as resolve15 } from "path";
|
|
2308
3185
|
import { confirm as confirm3, input as input3 } from "@inquirer/prompts";
|
|
2309
|
-
import
|
|
3186
|
+
import chalk15 from "chalk";
|
|
2310
3187
|
async function writeProviderFiles(params, providersDir) {
|
|
2311
3188
|
const dir = resolve15(process.cwd(), providersDir, `provider-${params.kebabName}`, "src");
|
|
2312
3189
|
const packageDir = resolve15(process.cwd(), providersDir, `provider-${params.kebabName}`);
|
|
2313
3190
|
const { indexTs, packageJson, tsconfigJson } = generateProviderFiles(params);
|
|
2314
3191
|
await mkdir3(dir, { recursive: true });
|
|
2315
|
-
await
|
|
2316
|
-
await
|
|
2317
|
-
await
|
|
3192
|
+
await writeFile8(join12(dir, "index.ts"), indexTs, "utf-8");
|
|
3193
|
+
await writeFile8(join12(packageDir, "package.json"), packageJson, "utf-8");
|
|
3194
|
+
await writeFile8(join12(packageDir, "tsconfig.json"), tsconfigJson, "utf-8");
|
|
2318
3195
|
return packageDir;
|
|
2319
3196
|
}
|
|
2320
3197
|
async function providerWizard(providersDir) {
|
|
@@ -2332,43 +3209,43 @@ async function providerWizard(providersDir) {
|
|
|
2332
3209
|
const hasEmbedding = await confirm3({ message: "Suporta embeddings?", default: false });
|
|
2333
3210
|
const outDir = resolve15(process.cwd(), providersDir, `provider-${kebabName}`);
|
|
2334
3211
|
console.log();
|
|
2335
|
-
console.log(
|
|
3212
|
+
console.log(chalk15.dim(` Destino: ${outDir}/`));
|
|
2336
3213
|
let shouldWrite = true;
|
|
2337
3214
|
try {
|
|
2338
3215
|
await access3(outDir);
|
|
2339
3216
|
shouldWrite = await confirm3({
|
|
2340
|
-
message:
|
|
3217
|
+
message: chalk15.yellow(`packages/provider-${kebabName}/ j\xE1 existe. Sobrescrever arquivos?`),
|
|
2341
3218
|
default: false
|
|
2342
3219
|
});
|
|
2343
3220
|
} catch {
|
|
2344
3221
|
}
|
|
2345
3222
|
if (!shouldWrite) {
|
|
2346
|
-
console.log(
|
|
3223
|
+
console.log(chalk15.dim("\n Opera\xE7\xE3o cancelada.\n"));
|
|
2347
3224
|
return;
|
|
2348
3225
|
}
|
|
2349
3226
|
const packageDir = await writeProviderFiles({ kebabName, displayName, hasVision, hasEmbedding }, providersDir);
|
|
2350
3227
|
console.log();
|
|
2351
|
-
console.log(`${
|
|
2352
|
-
console.log(
|
|
2353
|
-
console.log(
|
|
2354
|
-
console.log(
|
|
2355
|
-
console.log(
|
|
2356
|
-
console.log(
|
|
3228
|
+
console.log(`${chalk15.green(" \u2713")} Provider criado: ${chalk15.cyan(`${packageDir}/`)}`);
|
|
3229
|
+
console.log(chalk15.dim(" Pr\xF3ximos passos:"));
|
|
3230
|
+
console.log(chalk15.dim(` 1. Implemente complete() em src/index.ts`));
|
|
3231
|
+
console.log(chalk15.dim(` 2. Adicione \xE0 raiz tsconfig.json \u2192 references: { path: "./${providersDir}/provider-${kebabName}" }`));
|
|
3232
|
+
console.log(chalk15.dim(` 3. Importe em packages/cli/src/commands/run.ts: import "@omni-ai/provider-${kebabName}";`));
|
|
3233
|
+
console.log(chalk15.dim(` 4. Adicione a chave de API ao .env.example`));
|
|
2357
3234
|
console.log();
|
|
2358
3235
|
}
|
|
2359
3236
|
|
|
2360
3237
|
// ../../packages/cli/dist/commands/new/scaffold-skill.js
|
|
2361
|
-
import { access as access4, mkdir as mkdir4, writeFile as
|
|
2362
|
-
import { join as
|
|
3238
|
+
import { access as access4, mkdir as mkdir4, writeFile as writeFile9 } from "fs/promises";
|
|
3239
|
+
import { join as join13, resolve as resolve16 } from "path";
|
|
2363
3240
|
import { confirm as confirm4, input as input4, select as select3 } from "@inquirer/prompts";
|
|
2364
|
-
import
|
|
3241
|
+
import chalk16 from "chalk";
|
|
2365
3242
|
var DOMAINS = ["backend", "frontend", "qa", "fs", "git", "http", "multimodal", "ux"];
|
|
2366
3243
|
async function writeSkillFile(params, skillsDir) {
|
|
2367
3244
|
const dir = resolve16(process.cwd(), skillsDir, params.domain);
|
|
2368
|
-
const filePath =
|
|
3245
|
+
const filePath = join13(dir, `${params.kebabName}.ts`);
|
|
2369
3246
|
const content = generateSkillTs({ kebabName: params.kebabName, description: params.description });
|
|
2370
3247
|
await mkdir4(dir, { recursive: true });
|
|
2371
|
-
await
|
|
3248
|
+
await writeFile9(filePath, content, "utf-8");
|
|
2372
3249
|
return filePath;
|
|
2373
3250
|
}
|
|
2374
3251
|
async function skillWizard(skillsDir) {
|
|
@@ -2387,24 +3264,24 @@ async function skillWizard(skillsDir) {
|
|
|
2387
3264
|
});
|
|
2388
3265
|
const outPath = resolve16(process.cwd(), skillsDir, domain, `${kebabName}.ts`);
|
|
2389
3266
|
console.log();
|
|
2390
|
-
console.log(
|
|
3267
|
+
console.log(chalk16.dim(` Destino: ${outPath}`));
|
|
2391
3268
|
let shouldWrite = true;
|
|
2392
3269
|
try {
|
|
2393
3270
|
await access4(outPath);
|
|
2394
|
-
shouldWrite = await confirm4({ message:
|
|
3271
|
+
shouldWrite = await confirm4({ message: chalk16.yellow("Arquivo j\xE1 existe. Sobrescrever?"), default: false });
|
|
2395
3272
|
} catch {
|
|
2396
3273
|
}
|
|
2397
3274
|
if (!shouldWrite) {
|
|
2398
|
-
console.log(
|
|
3275
|
+
console.log(chalk16.dim("\n Opera\xE7\xE3o cancelada.\n"));
|
|
2399
3276
|
return;
|
|
2400
3277
|
}
|
|
2401
3278
|
const filePath = await writeSkillFile({ domain, kebabName, description }, skillsDir);
|
|
2402
3279
|
console.log();
|
|
2403
|
-
console.log(`${
|
|
2404
|
-
console.log(
|
|
2405
|
-
console.log(
|
|
2406
|
-
console.log(
|
|
2407
|
-
console.log(
|
|
3280
|
+
console.log(`${chalk16.green(" \u2713")} Skill criada: ${chalk16.cyan(filePath)}`);
|
|
3281
|
+
console.log(chalk16.dim(` Pr\xF3ximos passos:`));
|
|
3282
|
+
console.log(chalk16.dim(` 1. Implemente a l\xF3gica em execute()`));
|
|
3283
|
+
console.log(chalk16.dim(` 2. Exporte de ${skillsDir}/${domain}/index.ts`));
|
|
3284
|
+
console.log(chalk16.dim(` 3. Registre em packages/cli/src/commands/run.ts`));
|
|
2408
3285
|
console.log();
|
|
2409
3286
|
}
|
|
2410
3287
|
|
|
@@ -2416,7 +3293,7 @@ var DEFAULTS = {
|
|
|
2416
3293
|
};
|
|
2417
3294
|
async function loadScaffoldConfig() {
|
|
2418
3295
|
try {
|
|
2419
|
-
const raw = await
|
|
3296
|
+
const raw = await readFile16(join14(process.cwd(), "config", "omni-ai.yaml"), "utf-8");
|
|
2420
3297
|
const data = YAML.parse(raw);
|
|
2421
3298
|
if (!data)
|
|
2422
3299
|
return DEFAULTS;
|
|
@@ -2432,8 +3309,8 @@ async function loadScaffoldConfig() {
|
|
|
2432
3309
|
}
|
|
2433
3310
|
async function newCommand() {
|
|
2434
3311
|
console.log();
|
|
2435
|
-
console.log(
|
|
2436
|
-
console.log(
|
|
3312
|
+
console.log(chalk17.bold(" omni new \u2014 scaffold interativo"));
|
|
3313
|
+
console.log(chalk17.dim(" Cria um agente, skill ou provider a partir de template"));
|
|
2437
3314
|
const config = await loadScaffoldConfig();
|
|
2438
3315
|
const type = await select4({
|
|
2439
3316
|
message: "O que deseja criar?",
|
|
@@ -2457,7 +3334,7 @@ async function newCommand() {
|
|
|
2457
3334
|
}
|
|
2458
3335
|
|
|
2459
3336
|
// ../../packages/cli/dist/commands/run.js
|
|
2460
|
-
import { writeFile as
|
|
3337
|
+
import { writeFile as writeFile10 } from "fs/promises";
|
|
2461
3338
|
function parseSession(raw) {
|
|
2462
3339
|
const [resourceId, ...rest] = raw.split(":");
|
|
2463
3340
|
const threadId = rest.join(":") || "default";
|
|
@@ -2523,7 +3400,7 @@ ${result.output}
|
|
|
2523
3400
|
}
|
|
2524
3401
|
console.log(iterationLine(result.iterations));
|
|
2525
3402
|
if (opts.output) {
|
|
2526
|
-
await
|
|
3403
|
+
await writeFile10(opts.output, result.output, "utf-8");
|
|
2527
3404
|
console.log(savedLine(opts.output));
|
|
2528
3405
|
}
|
|
2529
3406
|
if (result.usage) {
|
|
@@ -2534,7 +3411,7 @@ ${result.output}
|
|
|
2534
3411
|
}
|
|
2535
3412
|
|
|
2536
3413
|
// ../../packages/cli/dist/commands/serve.js
|
|
2537
|
-
import
|
|
3414
|
+
import chalk18 from "chalk";
|
|
2538
3415
|
import express from "express";
|
|
2539
3416
|
function getDbPath3() {
|
|
2540
3417
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
|
|
@@ -2570,7 +3447,7 @@ async function serveCommand(opts) {
|
|
|
2570
3447
|
analyzeTestCoverageSkill
|
|
2571
3448
|
];
|
|
2572
3449
|
const runtime = await createRuntime({ configPath, skills: skills2 }).catch((err) => {
|
|
2573
|
-
console.error(
|
|
3450
|
+
console.error(chalk18.red(`\u2716 Failed to load config: ${err instanceof Error ? err.message : String(err)}`));
|
|
2574
3451
|
process.exit(1);
|
|
2575
3452
|
});
|
|
2576
3453
|
const app = express();
|
|
@@ -2638,21 +3515,21 @@ async function serveCommand(opts) {
|
|
|
2638
3515
|
}
|
|
2639
3516
|
});
|
|
2640
3517
|
app.listen(port, () => {
|
|
2641
|
-
console.log(
|
|
3518
|
+
console.log(chalk18.bold.cyan(`
|
|
2642
3519
|
\u25C6 omni serve`));
|
|
2643
|
-
console.log(
|
|
2644
|
-
console.log(
|
|
2645
|
-
console.log(
|
|
2646
|
-
console.log(
|
|
2647
|
-
console.log(
|
|
2648
|
-
console.log(
|
|
3520
|
+
console.log(chalk18.gray(` Listening on http://localhost:${port}`));
|
|
3521
|
+
console.log(chalk18.gray(` GET /health`));
|
|
3522
|
+
console.log(chalk18.gray(` GET /agents`));
|
|
3523
|
+
console.log(chalk18.gray(` POST /run \u2014 JSON response`));
|
|
3524
|
+
console.log(chalk18.gray(` POST /run/stream \u2014 SSE stream`));
|
|
3525
|
+
console.log(chalk18.gray("\n Press Ctrl+C to stop.\n"));
|
|
2649
3526
|
});
|
|
2650
3527
|
await new Promise(() => {
|
|
2651
3528
|
});
|
|
2652
3529
|
}
|
|
2653
3530
|
|
|
2654
3531
|
// ../../packages/cli/dist/commands/watch.js
|
|
2655
|
-
import
|
|
3532
|
+
import chalk19 from "chalk";
|
|
2656
3533
|
import chokidar from "chokidar";
|
|
2657
3534
|
function buildDebounce(fn, ms) {
|
|
2658
3535
|
let timer = null;
|
|
@@ -2704,28 +3581,28 @@ ${result.output}
|
|
|
2704
3581
|
}
|
|
2705
3582
|
async function watchCommand(agent, prompt, opts) {
|
|
2706
3583
|
const configPath = opts.config ?? resolveConfigPath();
|
|
2707
|
-
const
|
|
3584
|
+
const glob3 = opts.glob ?? "src/**/*.{ts,js,yaml,json}";
|
|
2708
3585
|
const debounceMs = opts.debounce ? Number.parseInt(opts.debounce, 10) : 500;
|
|
2709
|
-
console.log(
|
|
3586
|
+
console.log(chalk19.bold.cyan(`
|
|
2710
3587
|
\u25C6 omni watch`));
|
|
2711
|
-
console.log(
|
|
2712
|
-
console.log(
|
|
2713
|
-
console.log(
|
|
2714
|
-
console.log(
|
|
3588
|
+
console.log(chalk19.gray(` agent: ${agent}`));
|
|
3589
|
+
console.log(chalk19.gray(` glob: ${glob3}`));
|
|
3590
|
+
console.log(chalk19.gray(` debounce: ${debounceMs}ms`));
|
|
3591
|
+
console.log(chalk19.gray(" Press Ctrl+C to stop.\n"));
|
|
2715
3592
|
await runOnce(agent, prompt, configPath, opts.stream ?? false);
|
|
2716
3593
|
const trigger = buildDebounce(async () => {
|
|
2717
|
-
console.log(
|
|
3594
|
+
console.log(chalk19.gray(`
|
|
2718
3595
|
\u21BB Rerunning ${agent}...`));
|
|
2719
3596
|
await runOnce(agent, prompt, configPath, opts.stream ?? false);
|
|
2720
3597
|
}, debounceMs);
|
|
2721
|
-
const watcher = chokidar.watch(
|
|
3598
|
+
const watcher = chokidar.watch(glob3, { ignoreInitial: true, ignored: /node_modules/ });
|
|
2722
3599
|
watcher.on("change", (file) => {
|
|
2723
|
-
console.log(
|
|
3600
|
+
console.log(chalk19.gray(`
|
|
2724
3601
|
\u270E Changed: ${file}`));
|
|
2725
3602
|
trigger();
|
|
2726
3603
|
});
|
|
2727
3604
|
watcher.on("add", (file) => {
|
|
2728
|
-
console.log(
|
|
3605
|
+
console.log(chalk19.gray(`
|
|
2729
3606
|
+ Added: ${file}`));
|
|
2730
3607
|
trigger();
|
|
2731
3608
|
});
|
|
@@ -2733,7 +3610,7 @@ async function watchCommand(agent, prompt, opts) {
|
|
|
2733
3610
|
console.error(errorLine(`Watcher error: ${err}`));
|
|
2734
3611
|
});
|
|
2735
3612
|
process.on("SIGINT", async () => {
|
|
2736
|
-
console.log(
|
|
3613
|
+
console.log(chalk19.gray("\n\n Stopping watcher..."));
|
|
2737
3614
|
await watcher.close();
|
|
2738
3615
|
process.exit(0);
|
|
2739
3616
|
});
|
|
@@ -2742,7 +3619,7 @@ async function watchCommand(agent, prompt, opts) {
|
|
|
2742
3619
|
}
|
|
2743
3620
|
|
|
2744
3621
|
// ../../packages/cli/dist/bin.js
|
|
2745
|
-
var __dirname2 =
|
|
3622
|
+
var __dirname2 = dirname5(fileURLToPath3(import.meta.url));
|
|
2746
3623
|
loadDotenv({ path: resolve17(__dirname2, "..", "..", "..", ".env") });
|
|
2747
3624
|
var program = new Command();
|
|
2748
3625
|
program.name("omni").description("omni-ai \u2014 provider-agnostic AI agents for developer workflows").version("0.1.0");
|
|
@@ -2756,6 +3633,17 @@ program.command("serve").description("Start a local HTTP server to run agents vi
|
|
|
2756
3633
|
program.command("eval <agent> <dataset>").description("Evaluate an agent against a dataset of (input, expected) pairs").option("-c, --config <path>", "Path to omni-ai.yaml").option("--concurrency <n>", "Number of parallel evaluations (default: 3)").option("-o, --output <file>", "Save JSON report to file").action(evalCommand);
|
|
2757
3634
|
var mcp = program.command("mcp").description("MCP (Model Context Protocol) integration");
|
|
2758
3635
|
mcp.command("serve").description("Expose all registered skills as MCP tools over stdio").option("-c, --config <path>", "Path to omni-ai.yaml").action(mcpServeCommand);
|
|
3636
|
+
var history = program.command("history").description("Import, search and inspect third-party AI agent history");
|
|
3637
|
+
history.command("sources").description("List known history providers and whether they're importable on this machine").option("--json", "Output as JSON").action(historySourcesCommand);
|
|
3638
|
+
history.command("import").description("Import history from one or all registered providers").option("--provider <name>", "Import a single provider").option("--all", "Import every registered provider").option("--path <path>", "Override the discovered path (requires --provider)").action(historyImportCommand);
|
|
3639
|
+
history.command("search [query]").description('Full-text search over imported history, e.g. omni history search "retry handling"').option("--term <term>", "Search term (repeatable)", (value, prev) => [...prev, value], []).option("--session <id>", "Restrict search to one session").option("--scope <name>", "Restrict search to one project scope (default: current directory's project)").option("--all-projects", "Search across every imported project, not just the current one").option("--limit <n>", "Max results (default: 20)").option("--refresh <mode>", "auto | off | strict (default: auto)").option("--json", "Output as JSON").action(historySearchCommand);
|
|
3640
|
+
var historyShow = history.command("show").description("Show one event (with context) or a full session");
|
|
3641
|
+
historyShow.command("event <id>").description("Show one event with surrounding context").option("--window <n>", "Events of context before/after (default: 3)").action(historyShowEventCommand);
|
|
3642
|
+
historyShow.command("session <sessionId>").description("Show a full session").option("-f, --format <format>", "text | markdown (default: text)").option("-o, --out <path>", "Write to a file instead of stdout").action(historyShowSessionCommand);
|
|
3643
|
+
var historyLocate = history.command("locate").description("Report the original source location for an event/session");
|
|
3644
|
+
historyLocate.command("event <id>").description("Locate the source file/line an event was imported from").option("--json", "Output as JSON").action(historyLocateEventCommand);
|
|
3645
|
+
historyLocate.command("session <sessionId>").description("Locate the source file a session was imported from").option("--json", "Output as JSON").action(historyLocateSessionCommand);
|
|
3646
|
+
history.command("doctor").description("Diagnose non-importable sources and broken citations").option("--json", "Output as JSON").action(historyDoctorCommand);
|
|
2759
3647
|
var list = program.command("list").description("List available resources");
|
|
2760
3648
|
list.command("agents").description("List all available agents").option("-c, --config <path>", "Path to omni-ai.yaml").action((opts) => listCommand("agents", opts));
|
|
2761
3649
|
list.command("skills").description("List registered skills").option("-c, --config <path>", "Path to omni-ai.yaml").action((opts) => listCommand("skills", opts));
|