@juli-os/ledger 0.1.7 → 0.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/dist/contracts/entities.d.ts +1 -0
- package/dist/index.js +40 -7
- package/dist/juli-ledger.js +40 -7
- package/dist/platform/ledger/store.d.ts +4 -2
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -241,6 +241,7 @@ var rowToWorkflow = (r) => ({
|
|
|
241
241
|
project: str(r["project"]),
|
|
242
242
|
path: str(r["path"]),
|
|
243
243
|
threadId: r["thread_id"] === null ? null : str(r["thread_id"]),
|
|
244
|
+
tenant: str(r["tenant"]) || "internal",
|
|
244
245
|
meta: asRecord(safeParse(str(r["meta"]))),
|
|
245
246
|
createdAt: str(r["created_at"]),
|
|
246
247
|
updatedAt: str(r["updated_at"])
|
|
@@ -307,7 +308,11 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
307
308
|
if (!wfCols.includes("thread_id")) {
|
|
308
309
|
db.exec("ALTER TABLE workflows ADD COLUMN thread_id TEXT");
|
|
309
310
|
}
|
|
311
|
+
if (!wfCols.includes("tenant")) {
|
|
312
|
+
db.exec("ALTER TABLE workflows ADD COLUMN tenant TEXT NOT NULL DEFAULT 'internal'");
|
|
313
|
+
}
|
|
310
314
|
db.exec("CREATE INDEX IF NOT EXISTS idx_workflows_thread ON workflows(thread_id)");
|
|
315
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_workflows_tenant ON workflows(tenant, created_at)");
|
|
311
316
|
const stepCols = db.prepare("PRAGMA table_info(workflow_steps)").all().map((c) => c.name);
|
|
312
317
|
if (!stepCols.includes("started_at")) db.exec("ALTER TABLE workflow_steps ADD COLUMN started_at TEXT");
|
|
313
318
|
if (!stepCols.includes("completed_at")) db.exec("ALTER TABLE workflow_steps ADD COLUMN completed_at TEXT");
|
|
@@ -349,19 +354,36 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
349
354
|
const id = ids.newId("wf");
|
|
350
355
|
const ts = now();
|
|
351
356
|
db.prepare(
|
|
352
|
-
`INSERT INTO workflows (id, parent_id, kind, title, status, owner, meta, created_at, updated_at)
|
|
353
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
354
|
-
).run(id, w.parentId ?? null, w.kind, w.title, w.status ?? "running", w.owner ?? null, JSON.stringify(w.meta ?? {}), ts, ts);
|
|
357
|
+
`INSERT INTO workflows (id, parent_id, kind, title, status, owner, tenant, meta, created_at, updated_at)
|
|
358
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
359
|
+
).run(id, w.parentId ?? null, w.kind, w.title, w.status ?? "running", w.owner ?? null, w.tenant || "internal", JSON.stringify(w.meta ?? {}), ts, ts);
|
|
355
360
|
return getWorkflowById(id);
|
|
356
361
|
},
|
|
357
362
|
getWorkflow(id) {
|
|
358
363
|
return getWorkflowById(id);
|
|
359
364
|
},
|
|
360
|
-
listWorkflows(limit = 100, status) {
|
|
365
|
+
listWorkflows(limit = 100, status, tenant) {
|
|
366
|
+
const where = [];
|
|
367
|
+
const params = [];
|
|
361
368
|
if (status !== void 0 && status !== "") {
|
|
362
|
-
|
|
369
|
+
where.push("status=?");
|
|
370
|
+
params.push(status);
|
|
371
|
+
}
|
|
372
|
+
if (tenant !== void 0 && tenant !== "") {
|
|
373
|
+
where.push("tenant=?");
|
|
374
|
+
params.push(tenant);
|
|
363
375
|
}
|
|
364
|
-
|
|
376
|
+
const sql = where.length > 0 ? `SELECT * FROM workflows WHERE ${where.join(" AND ")} ORDER BY created_at DESC, rowid DESC LIMIT ?` : "SELECT * FROM workflows ORDER BY created_at DESC, rowid DESC LIMIT ?";
|
|
377
|
+
return db.prepare(sql).all(...params, limit).map(rowToWorkflow);
|
|
378
|
+
},
|
|
379
|
+
setWorkflowTenant(id, tenant) {
|
|
380
|
+
const next = tenant === "" ? "internal" : tenant;
|
|
381
|
+
const cur = getWorkflowById(id);
|
|
382
|
+
if (cur === null || cur.tenant === next) return;
|
|
383
|
+
db.prepare("UPDATE workflows SET tenant=?, updated_at=? WHERE id=?").run(next, now(), id);
|
|
384
|
+
db.prepare(
|
|
385
|
+
"INSERT INTO events (entity_type, entity_id, type, payload, ts) VALUES ('workflow', ?, 'tenant_changed', ?, ?)"
|
|
386
|
+
).run(id, JSON.stringify({ from: cur.tenant, to: next }), now());
|
|
365
387
|
},
|
|
366
388
|
setWorkflowSession(id, session) {
|
|
367
389
|
db.prepare("UPDATE workflows SET session=?, updated_at=? WHERE id=?").run(session, now(), id);
|
|
@@ -523,7 +545,18 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
523
545
|
).run(now(), now(), id);
|
|
524
546
|
return Number(res.changes) === 1;
|
|
525
547
|
},
|
|
526
|
-
listSteps(status, limit = 100) {
|
|
548
|
+
listSteps(status, limit = 100, tenant) {
|
|
549
|
+
if (tenant !== void 0 && tenant !== "") {
|
|
550
|
+
return db.prepare(
|
|
551
|
+
`SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
|
|
552
|
+
st.title AS title, st.status AS status,
|
|
553
|
+
COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
|
|
554
|
+
COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at,
|
|
555
|
+
st.started_at AS started_at, st.completed_at AS completed_at
|
|
556
|
+
FROM workflow_steps st JOIN workflows w ON w.id = st.workflow_id
|
|
557
|
+
WHERE st.status=? AND w.tenant=? ORDER BY st.updated_at DESC LIMIT ?`
|
|
558
|
+
).all(status, tenant, limit).map(rowToStep);
|
|
559
|
+
}
|
|
527
560
|
return db.prepare(
|
|
528
561
|
`SELECT ${STEP_COLS} FROM workflow_steps WHERE status=? ORDER BY updated_at DESC LIMIT ?`
|
|
529
562
|
).all(status, limit).map(rowToStep);
|
package/dist/juli-ledger.js
CHANGED
|
@@ -199,6 +199,7 @@ var rowToWorkflow = (r) => ({
|
|
|
199
199
|
project: str(r["project"]),
|
|
200
200
|
path: str(r["path"]),
|
|
201
201
|
threadId: r["thread_id"] === null ? null : str(r["thread_id"]),
|
|
202
|
+
tenant: str(r["tenant"]) || "internal",
|
|
202
203
|
meta: asRecord(safeParse(str(r["meta"]))),
|
|
203
204
|
createdAt: str(r["created_at"]),
|
|
204
205
|
updatedAt: str(r["updated_at"])
|
|
@@ -265,7 +266,11 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
265
266
|
if (!wfCols.includes("thread_id")) {
|
|
266
267
|
db.exec("ALTER TABLE workflows ADD COLUMN thread_id TEXT");
|
|
267
268
|
}
|
|
269
|
+
if (!wfCols.includes("tenant")) {
|
|
270
|
+
db.exec("ALTER TABLE workflows ADD COLUMN tenant TEXT NOT NULL DEFAULT 'internal'");
|
|
271
|
+
}
|
|
268
272
|
db.exec("CREATE INDEX IF NOT EXISTS idx_workflows_thread ON workflows(thread_id)");
|
|
273
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_workflows_tenant ON workflows(tenant, created_at)");
|
|
269
274
|
const stepCols = db.prepare("PRAGMA table_info(workflow_steps)").all().map((c) => c.name);
|
|
270
275
|
if (!stepCols.includes("started_at")) db.exec("ALTER TABLE workflow_steps ADD COLUMN started_at TEXT");
|
|
271
276
|
if (!stepCols.includes("completed_at")) db.exec("ALTER TABLE workflow_steps ADD COLUMN completed_at TEXT");
|
|
@@ -307,19 +312,36 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
307
312
|
const id = ids.newId("wf");
|
|
308
313
|
const ts = now();
|
|
309
314
|
db.prepare(
|
|
310
|
-
`INSERT INTO workflows (id, parent_id, kind, title, status, owner, meta, created_at, updated_at)
|
|
311
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
312
|
-
).run(id, w.parentId ?? null, w.kind, w.title, w.status ?? "running", w.owner ?? null, JSON.stringify(w.meta ?? {}), ts, ts);
|
|
315
|
+
`INSERT INTO workflows (id, parent_id, kind, title, status, owner, tenant, meta, created_at, updated_at)
|
|
316
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
317
|
+
).run(id, w.parentId ?? null, w.kind, w.title, w.status ?? "running", w.owner ?? null, w.tenant || "internal", JSON.stringify(w.meta ?? {}), ts, ts);
|
|
313
318
|
return getWorkflowById(id);
|
|
314
319
|
},
|
|
315
320
|
getWorkflow(id) {
|
|
316
321
|
return getWorkflowById(id);
|
|
317
322
|
},
|
|
318
|
-
listWorkflows(limit = 100, status) {
|
|
323
|
+
listWorkflows(limit = 100, status, tenant) {
|
|
324
|
+
const where = [];
|
|
325
|
+
const params = [];
|
|
319
326
|
if (status !== void 0 && status !== "") {
|
|
320
|
-
|
|
327
|
+
where.push("status=?");
|
|
328
|
+
params.push(status);
|
|
329
|
+
}
|
|
330
|
+
if (tenant !== void 0 && tenant !== "") {
|
|
331
|
+
where.push("tenant=?");
|
|
332
|
+
params.push(tenant);
|
|
321
333
|
}
|
|
322
|
-
|
|
334
|
+
const sql = where.length > 0 ? `SELECT * FROM workflows WHERE ${where.join(" AND ")} ORDER BY created_at DESC, rowid DESC LIMIT ?` : "SELECT * FROM workflows ORDER BY created_at DESC, rowid DESC LIMIT ?";
|
|
335
|
+
return db.prepare(sql).all(...params, limit).map(rowToWorkflow);
|
|
336
|
+
},
|
|
337
|
+
setWorkflowTenant(id, tenant) {
|
|
338
|
+
const next = tenant === "" ? "internal" : tenant;
|
|
339
|
+
const cur = getWorkflowById(id);
|
|
340
|
+
if (cur === null || cur.tenant === next) return;
|
|
341
|
+
db.prepare("UPDATE workflows SET tenant=?, updated_at=? WHERE id=?").run(next, now(), id);
|
|
342
|
+
db.prepare(
|
|
343
|
+
"INSERT INTO events (entity_type, entity_id, type, payload, ts) VALUES ('workflow', ?, 'tenant_changed', ?, ?)"
|
|
344
|
+
).run(id, JSON.stringify({ from: cur.tenant, to: next }), now());
|
|
323
345
|
},
|
|
324
346
|
setWorkflowSession(id, session) {
|
|
325
347
|
db.prepare("UPDATE workflows SET session=?, updated_at=? WHERE id=?").run(session, now(), id);
|
|
@@ -481,7 +503,18 @@ var createLedgerStore = (dbPath, deps = {}) => {
|
|
|
481
503
|
).run(now(), now(), id);
|
|
482
504
|
return Number(res.changes) === 1;
|
|
483
505
|
},
|
|
484
|
-
listSteps(status, limit = 100) {
|
|
506
|
+
listSteps(status, limit = 100, tenant) {
|
|
507
|
+
if (tenant !== void 0 && tenant !== "") {
|
|
508
|
+
return db.prepare(
|
|
509
|
+
`SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
|
|
510
|
+
st.title AS title, st.status AS status,
|
|
511
|
+
COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
|
|
512
|
+
COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at,
|
|
513
|
+
st.started_at AS started_at, st.completed_at AS completed_at
|
|
514
|
+
FROM workflow_steps st JOIN workflows w ON w.id = st.workflow_id
|
|
515
|
+
WHERE st.status=? AND w.tenant=? ORDER BY st.updated_at DESC LIMIT ?`
|
|
516
|
+
).all(status, tenant, limit).map(rowToStep);
|
|
517
|
+
}
|
|
485
518
|
return db.prepare(
|
|
486
519
|
`SELECT ${STEP_COLS} FROM workflow_steps WHERE status=? ORDER BY updated_at DESC LIMIT ?`
|
|
487
520
|
).all(status, limit).map(rowToStep);
|
|
@@ -12,11 +12,13 @@ export interface LifecycleStore {
|
|
|
12
12
|
parentId?: string;
|
|
13
13
|
status?: WorkflowStatus;
|
|
14
14
|
owner?: string;
|
|
15
|
+
tenant?: string;
|
|
15
16
|
}): Workflow;
|
|
16
17
|
getWorkflow(id: string): Workflow | null;
|
|
17
|
-
listWorkflows(limit?: number, status?: string): readonly Workflow[];
|
|
18
|
+
listWorkflows(limit?: number, status?: string, tenant?: string): readonly Workflow[];
|
|
18
19
|
setWorkflowStatus(id: string, status: WorkflowStatus): void;
|
|
19
20
|
setWorkflowSession(id: string, session: string): void;
|
|
21
|
+
setWorkflowTenant(id: string, tenant: string): void;
|
|
20
22
|
updateWorkflowMeta(id: string, patch: JsonRecord): JsonRecord;
|
|
21
23
|
setWorkflowRouting(id: string, session: string, project: string): void;
|
|
22
24
|
assignThread(workflowId: string, threadId: string): void;
|
|
@@ -64,7 +66,7 @@ export interface LifecycleStore {
|
|
|
64
66
|
setStepOutput(id: string, patch: JsonRecord): void;
|
|
65
67
|
appendStepOutputItem(id: string, key: string, entry: JsonValue, cap: number): void;
|
|
66
68
|
claimRunningStep(id: string): boolean;
|
|
67
|
-
listSteps(status: StepStatus, limit?: number): readonly Step[];
|
|
69
|
+
listSteps(status: StepStatus, limit?: number, tenant?: string): readonly Step[];
|
|
68
70
|
runningAgentStepForSession(session: string): Step | null;
|
|
69
71
|
sessionHasOpenWork(session: string, excludeWorkflowId?: string): boolean;
|
|
70
72
|
appendEvent(entityType: 'workflow' | 'step' | 'judgment' | 'agent', entityId: string, type: string, payload?: JsonRecord): LedgerEvent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juli-os/ledger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "juli-os L1 layer: the ledger of record for agent work — workflows, steps, case files, and token usage in one zero-dependency SQLite layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,11 +27,15 @@
|
|
|
27
27
|
"build": "tsc -p tsconfig.build.json && esbuild src/index.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/index.js && esbuild bin/juli-ledger.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/juli-ledger.js && chmod +x dist/juli-ledger.js && python3 scripts/postbuild.py",
|
|
28
28
|
"test": "node --test \"test/*.test.ts\"",
|
|
29
29
|
"smoke:dist": "node --input-type=module -e \"import('./dist/index.js').then(async m => { const { join } = await import('node:path'); const { tmpdir } = await import('node:os'); const s = m.createLedgerStore(join(tmpdir(), 'peel-dist-' + Date.now() + '.db')); const wf = s.createWorkflow({kind:'case',title:'dist smoke'}); if (!s.getWorkflow(wf.id)) process.exit(1); console.log('DIST SMOKE OK'); })\"",
|
|
30
|
+
"docs:gen": "node scripts/gen-docs.mjs && typedoc",
|
|
31
|
+
"docs:build": "npm run docs:gen && mkdocs build --strict",
|
|
30
32
|
"prepublishOnly": "npm run build"
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
33
35
|
"@types/node": "^22.0.0",
|
|
34
36
|
"esbuild": "^0.24.0",
|
|
37
|
+
"typedoc": "^0.28.20",
|
|
38
|
+
"typedoc-plugin-markdown": "^4.14.1",
|
|
35
39
|
"typescript": "^5.6.0"
|
|
36
40
|
},
|
|
37
41
|
"publishConfig": {
|