@sigrun/knowledge 0.0.0-stage → 0.1.2
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/CHANGELOG.md +93 -0
- package/LICENSE +21 -0
- package/README.md +83 -2
- package/dist/apply.d.ts +56 -0
- package/dist/apply.js +554 -0
- package/dist/audience.d.ts +12 -0
- package/dist/audience.js +26 -0
- package/dist/card.d.ts +15 -0
- package/dist/card.js +83 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +44 -0
- package/dist/db.d.ts +18 -0
- package/dist/db.js +156 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +52 -0
- package/dist/maintain.d.ts +21 -0
- package/dist/maintain.js +585 -0
- package/dist/mirror.d.ts +41 -0
- package/dist/mirror.js +59 -0
- package/dist/prompts.d.ts +6 -0
- package/dist/prompts.js +16 -0
- package/dist/research.d.ts +46 -0
- package/dist/research.js +87 -0
- package/dist/schema.d.ts +44 -0
- package/dist/schema.js +145 -0
- package/dist/target.d.ts +23 -0
- package/dist/target.js +29 -0
- package/dist/tool-executed.d.ts +15 -0
- package/dist/tool-executed.js +15 -0
- package/dist/tools.d.ts +45 -0
- package/dist/tools.js +357 -0
- package/dist/undo.d.ts +16 -0
- package/dist/undo.js +335 -0
- package/package.json +58 -5
package/dist/undo.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
function writeVersion(db, changeId, table, rowId, before, after, at) {
|
|
2
|
+
db.raw()
|
|
3
|
+
.prepare('INSERT INTO versions (changeId, "table", rowId, before, after, at) VALUES (?, ?, ?, ?, ?, ?)')
|
|
4
|
+
.run(changeId, table, rowId, before === undefined || before === null
|
|
5
|
+
? null
|
|
6
|
+
: JSON.stringify(before), after === undefined || after === null
|
|
7
|
+
? null
|
|
8
|
+
: JSON.stringify(after), at);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Undo a change: walk its versions newest-first and restore each row's
|
|
12
|
+
* `before` state — but only while the row still equals the change's
|
|
13
|
+
* `after`. A row a later change edited is skipped, so undo restores only
|
|
14
|
+
* what the change last wrote. Every restore is itself recorded as a
|
|
15
|
+
* version under `undo:<changeId>`, so nothing is lost.
|
|
16
|
+
*/
|
|
17
|
+
export function undoChange(db, changeId, now) {
|
|
18
|
+
return db.transaction(() => {
|
|
19
|
+
const undoId = `undo:${changeId}`;
|
|
20
|
+
const versions = db
|
|
21
|
+
.raw()
|
|
22
|
+
.prepare('SELECT seq, changeId, "table", rowId, before, after, at FROM versions WHERE changeId = ? ORDER BY seq DESC')
|
|
23
|
+
// SAFETY: the versions table columns are fixed by db.ts's schema;
|
|
24
|
+
// node:sqlite only types rows generically.
|
|
25
|
+
.all(changeId);
|
|
26
|
+
let restored = 0;
|
|
27
|
+
const skipped = [];
|
|
28
|
+
const touched = new Set();
|
|
29
|
+
for (const version of versions) {
|
|
30
|
+
switch (version.table) {
|
|
31
|
+
case "entities": {
|
|
32
|
+
const outcome = undoEntity(db, version, undoId, now);
|
|
33
|
+
if (outcome === "restored") {
|
|
34
|
+
restored += 1;
|
|
35
|
+
touched.add(version.rowId);
|
|
36
|
+
}
|
|
37
|
+
else if (outcome !== "unchanged") {
|
|
38
|
+
skipped.push(outcome);
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "roles": {
|
|
43
|
+
const outcome = undoRole(db, version, undoId, now);
|
|
44
|
+
if (outcome === "restored")
|
|
45
|
+
restored += 1;
|
|
46
|
+
else if (outcome !== "unchanged")
|
|
47
|
+
skipped.push(outcome);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "inquiries": {
|
|
51
|
+
const outcome = undoInquiry(db, version, undoId, now);
|
|
52
|
+
if (outcome === "restored")
|
|
53
|
+
restored += 1;
|
|
54
|
+
else if (outcome !== "unchanged")
|
|
55
|
+
skipped.push(outcome);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case "types": {
|
|
59
|
+
// Type rows are shared schema: undo restores them only while
|
|
60
|
+
// the row still equals what the change wrote (a later
|
|
61
|
+
// extension of the type blocks the revert, not other
|
|
62
|
+
// types). A type the change created is archived in turn.
|
|
63
|
+
const outcome = undoType(db, version, undoId, now);
|
|
64
|
+
if (outcome === "restored")
|
|
65
|
+
restored += 1;
|
|
66
|
+
else if (outcome !== "unchanged")
|
|
67
|
+
skipped.push(outcome);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "entity_keys": {
|
|
71
|
+
const outcome = undoEntityKey(db, version, undoId, now);
|
|
72
|
+
if (outcome === "restored")
|
|
73
|
+
restored += 1;
|
|
74
|
+
else if (outcome !== "unchanged")
|
|
75
|
+
skipped.push(outcome);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { restored, skipped, touched: [...touched] };
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function undoEntity(db, version, undoId, now) {
|
|
84
|
+
const row = db
|
|
85
|
+
.raw()
|
|
86
|
+
.prepare("SELECT id, typeId, name, keys, fields, attributes, cls, indexedAt, archived FROM entities WHERE id = ?")
|
|
87
|
+
.get(version.rowId);
|
|
88
|
+
if (row === undefined) {
|
|
89
|
+
return `entity ${version.rowId}: no longer present`;
|
|
90
|
+
}
|
|
91
|
+
if (version.before === null) {
|
|
92
|
+
// The change created this entity: undo archives it — but only
|
|
93
|
+
// while the row still equals what the change wrote; a later
|
|
94
|
+
// change's edits (rename, new fields, new keys) stand.
|
|
95
|
+
if (Number(row.archived) !== 0)
|
|
96
|
+
return "unchanged";
|
|
97
|
+
const afterCreate = JSON.parse(version.after ?? "null");
|
|
98
|
+
const differs = afterDiffersFromRow(afterCreate, row, [
|
|
99
|
+
"name",
|
|
100
|
+
"keys",
|
|
101
|
+
"fields",
|
|
102
|
+
"attributes",
|
|
103
|
+
"typeId",
|
|
104
|
+
]);
|
|
105
|
+
if (differs !== null) {
|
|
106
|
+
return `entity "${String(row.name)}" (${version.rowId}): ${differs}`;
|
|
107
|
+
}
|
|
108
|
+
writeVersion(db, undoId, "entities", version.rowId, row, { ...row, archived: 1 }, now);
|
|
109
|
+
db.raw()
|
|
110
|
+
.prepare("UPDATE entities SET archived = 1 WHERE id = ?")
|
|
111
|
+
.run(version.rowId);
|
|
112
|
+
return "restored";
|
|
113
|
+
}
|
|
114
|
+
const before = JSON.parse(version.before ?? "null");
|
|
115
|
+
const after = JSON.parse(version.after ?? "null");
|
|
116
|
+
// Whole-row equality: a later change touching anything the change
|
|
117
|
+
// wrote (name, keys, attributes, type — not just fields) blocks the
|
|
118
|
+
// undo, so undoing A can never silently revert B's rename.
|
|
119
|
+
const differs = afterDiffersFromRow(after, row, [
|
|
120
|
+
"name",
|
|
121
|
+
"keys",
|
|
122
|
+
"fields",
|
|
123
|
+
"attributes",
|
|
124
|
+
"typeId",
|
|
125
|
+
]);
|
|
126
|
+
if (before === null || after === null || differs !== null) {
|
|
127
|
+
return `entity "${String(row.name)}" (${version.rowId}): ${differs ?? "changed by a later change"}`;
|
|
128
|
+
}
|
|
129
|
+
const restoredRow = { ...row, ...before, id: row.id, archived: row.archived };
|
|
130
|
+
writeVersion(db, undoId, "entities", version.rowId, row, restoredRow, now);
|
|
131
|
+
db.raw()
|
|
132
|
+
.prepare("UPDATE entities SET typeId = ?, name = ?, keys = ?, fields = ?, attributes = ?, indexedAt = ? WHERE id = ?")
|
|
133
|
+
.run(restoredRow.typeId, restoredRow.name, restoredRow.keys, restoredRow.fields, restoredRow.attributes, restoredRow.indexedAt, version.rowId);
|
|
134
|
+
return "restored";
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* JSON-stable compare of a version's `after` against the current row for
|
|
138
|
+
* the given columns. Returns null when equal, otherwise a short text
|
|
139
|
+
* naming the first differing column.
|
|
140
|
+
*/
|
|
141
|
+
function afterDiffersFromRow(after, row, columns) {
|
|
142
|
+
if (after === null)
|
|
143
|
+
return "changed by a later change";
|
|
144
|
+
for (const column of columns) {
|
|
145
|
+
// Absent key = the version blob doesn't carry that column (partial
|
|
146
|
+
// blobs, e.g. inquiry updates store only conversations/outcome);
|
|
147
|
+
// undefined can only mean missing — a stored null is "null".
|
|
148
|
+
if (after[column] === undefined)
|
|
149
|
+
continue;
|
|
150
|
+
if (JSON.stringify(after[column]) !== JSON.stringify(row[column])) {
|
|
151
|
+
return `${column} changed by a later change`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
function undoRole(db, version, undoId, now) {
|
|
157
|
+
const row = db
|
|
158
|
+
.raw()
|
|
159
|
+
.prepare("SELECT id, inquiryId, entityId, role, reason FROM roles WHERE id = ?")
|
|
160
|
+
.get(Number(version.rowId));
|
|
161
|
+
if (row === undefined)
|
|
162
|
+
return "unchanged";
|
|
163
|
+
if (version.before === null) {
|
|
164
|
+
// The change created this role: undo deletes it.
|
|
165
|
+
const after = JSON.parse(version.after ?? "null");
|
|
166
|
+
const differs = afterDiffersFromRow(after, row, ["role", "reason"]);
|
|
167
|
+
if (differs !== null) {
|
|
168
|
+
return `role ${version.rowId}: ${differs}`;
|
|
169
|
+
}
|
|
170
|
+
writeVersion(db, undoId, "roles", version.rowId, row, null, now);
|
|
171
|
+
db.raw().prepare("DELETE FROM roles WHERE id = ?").run(Number(version.rowId));
|
|
172
|
+
return "restored";
|
|
173
|
+
}
|
|
174
|
+
const before = JSON.parse(version.before ?? "null");
|
|
175
|
+
const after = JSON.parse(version.after ?? "null");
|
|
176
|
+
const differs = afterDiffersFromRow(after, row, ["role", "reason"]);
|
|
177
|
+
if (before === null || after === null || differs !== null) {
|
|
178
|
+
return `role ${version.rowId}: ${differs ?? "changed by a later change"}`;
|
|
179
|
+
}
|
|
180
|
+
writeVersion(db, undoId, "roles", version.rowId, row, { ...row, ...before, id: row.id }, now);
|
|
181
|
+
db.raw()
|
|
182
|
+
.prepare("UPDATE roles SET role = ?, reason = ? WHERE id = ?")
|
|
183
|
+
.run(before.role, before.reason ?? null, Number(version.rowId));
|
|
184
|
+
return "restored";
|
|
185
|
+
}
|
|
186
|
+
function undoInquiry(db, version, undoId, now) {
|
|
187
|
+
const row = db
|
|
188
|
+
.raw()
|
|
189
|
+
.prepare("SELECT id, question, why, startedAt, touchedAt, conversations, outcome, archived FROM inquiries WHERE id = ?")
|
|
190
|
+
.get(Number(version.rowId));
|
|
191
|
+
if (row === undefined)
|
|
192
|
+
return "unchanged";
|
|
193
|
+
if (version.before === null) {
|
|
194
|
+
// The change created this inquiry: undo archives it (records are
|
|
195
|
+
// never deleted). Only while the row still equals what the change
|
|
196
|
+
// wrote.
|
|
197
|
+
if (Number(row.archived) !== 0)
|
|
198
|
+
return "unchanged";
|
|
199
|
+
const after = JSON.parse(version.after ?? "null");
|
|
200
|
+
const differs = afterDiffersFromRow(after, row, [
|
|
201
|
+
"question",
|
|
202
|
+
"why",
|
|
203
|
+
"outcome",
|
|
204
|
+
"conversations",
|
|
205
|
+
]);
|
|
206
|
+
if (differs !== null) {
|
|
207
|
+
return `inquiry "${String(row.question)}" (${version.rowId}): ${differs}`;
|
|
208
|
+
}
|
|
209
|
+
writeVersion(db, undoId, "inquiries", version.rowId, row, { ...row, archived: 1 }, now);
|
|
210
|
+
db.raw()
|
|
211
|
+
.prepare("UPDATE inquiries SET archived = 1, touchedAt = ? WHERE id = ?")
|
|
212
|
+
.run(now, Number(version.rowId));
|
|
213
|
+
return "restored";
|
|
214
|
+
}
|
|
215
|
+
const before = JSON.parse(version.before ?? "null");
|
|
216
|
+
const after = JSON.parse(version.after ?? "null");
|
|
217
|
+
const differs = afterDiffersFromRow(after, row, [
|
|
218
|
+
"question",
|
|
219
|
+
"why",
|
|
220
|
+
"outcome",
|
|
221
|
+
"conversations",
|
|
222
|
+
]);
|
|
223
|
+
if (before === null || after === null || differs !== null) {
|
|
224
|
+
return `inquiry "${String(row.question)}" (${version.rowId}): ${differs ?? "changed by a later change"}`;
|
|
225
|
+
}
|
|
226
|
+
const restored = { ...row, ...before, id: row.id };
|
|
227
|
+
writeVersion(db, undoId, "inquiries", version.rowId, row, restored, now);
|
|
228
|
+
db.raw()
|
|
229
|
+
.prepare("UPDATE inquiries SET conversations = ?, outcome = ?, archived = ?, touchedAt = ? WHERE id = ?")
|
|
230
|
+
.run(restored.conversations, restored.outcome ?? null, Number(restored.archived ?? 0), now, Number(version.rowId));
|
|
231
|
+
return "restored";
|
|
232
|
+
}
|
|
233
|
+
function undoEntityKey(db, version, undoId, now) {
|
|
234
|
+
const row = db
|
|
235
|
+
.raw()
|
|
236
|
+
.prepare("SELECT id, entityId, typeFamilyRoot, key, normalized FROM entity_keys WHERE id = ?")
|
|
237
|
+
.get(Number(version.rowId));
|
|
238
|
+
if (version.before !== null) {
|
|
239
|
+
// A re-root (retypeEntities / maintain): restore the old family
|
|
240
|
+
// root while the row still sits at the change's after root.
|
|
241
|
+
if (row === undefined)
|
|
242
|
+
return "unchanged";
|
|
243
|
+
const before = JSON.parse(version.before);
|
|
244
|
+
const after = JSON.parse(version.after ?? "null");
|
|
245
|
+
const differs = afterDiffersFromRow(after, row, ["typeFamilyRoot"]);
|
|
246
|
+
if (differs !== null)
|
|
247
|
+
return `entity_keys ${version.rowId}: ${differs}`;
|
|
248
|
+
writeVersion(db, undoId, "entity_keys", version.rowId, row, before, now);
|
|
249
|
+
db.raw()
|
|
250
|
+
.prepare("UPDATE entity_keys SET typeFamilyRoot = ? WHERE id = ?")
|
|
251
|
+
.run(before.typeFamilyRoot, Number(version.rowId));
|
|
252
|
+
return "restored";
|
|
253
|
+
}
|
|
254
|
+
// applyRecord only ever creates key rows; undo removes them.
|
|
255
|
+
if (row === undefined)
|
|
256
|
+
return "unchanged";
|
|
257
|
+
writeVersion(db, undoId, "entity_keys", version.rowId, row, null, now);
|
|
258
|
+
db.raw()
|
|
259
|
+
.prepare("DELETE FROM entity_keys WHERE id = ?")
|
|
260
|
+
.run(Number(version.rowId));
|
|
261
|
+
return "restored";
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Undo a type version: a type the change created is archived (while the
|
|
265
|
+
* row still equals the creation blob); a type the change edited gets its
|
|
266
|
+
* parentId/fields/description back (while the row still equals the
|
|
267
|
+
* change's after). Edits from a later change to the same row block the
|
|
268
|
+
* revert; other rows are never consulted (a type's schema is its own
|
|
269
|
+
* row, so undoing a generalization after a child was extended reverts
|
|
270
|
+
* the child alone).
|
|
271
|
+
*/
|
|
272
|
+
function undoType(db, version, undoId, now) {
|
|
273
|
+
// Schema rows written by knowledge_record are shared schema and stay
|
|
274
|
+
// audit-only; only the idle pass's own hierarchy edits (change ids
|
|
275
|
+
// prefixed "maintain:") are reverted, so a generalization is
|
|
276
|
+
// undoable without record-applied types ever being rewritten.
|
|
277
|
+
if (!version.changeId.startsWith("maintain:")) {
|
|
278
|
+
return `type ${version.rowId}: type schema changes are not reverted`;
|
|
279
|
+
}
|
|
280
|
+
const row = db
|
|
281
|
+
.raw()
|
|
282
|
+
.prepare("SELECT id, name, description, parentId, fields, version, archived FROM types WHERE id = ?")
|
|
283
|
+
.get(Number(version.rowId));
|
|
284
|
+
if (row === undefined)
|
|
285
|
+
return "unchanged";
|
|
286
|
+
if (version.before === null) {
|
|
287
|
+
// Created by this change: archive it (schema rows are never
|
|
288
|
+
// deleted) while the row still equals the creation blob.
|
|
289
|
+
if (Number(row.archived) !== 0)
|
|
290
|
+
return "unchanged";
|
|
291
|
+
const afterCreate = JSON.parse(version.after ?? "null");
|
|
292
|
+
const differs = afterDiffersFromRow(afterCreate, row, [
|
|
293
|
+
"name",
|
|
294
|
+
"description",
|
|
295
|
+
"parentId",
|
|
296
|
+
"fields",
|
|
297
|
+
]);
|
|
298
|
+
if (differs !== null) {
|
|
299
|
+
return `type "${String(row.name)}" (${version.rowId}): ${differs}`;
|
|
300
|
+
}
|
|
301
|
+
// A parent with live children still attached stays live: archiving
|
|
302
|
+
// it would orphan the hierarchy (the child revert was skipped
|
|
303
|
+
// because a later change edited that child).
|
|
304
|
+
const liveChildren = db
|
|
305
|
+
.raw()
|
|
306
|
+
.prepare("SELECT 1 AS x FROM types WHERE parentId = ? AND archived = 0 LIMIT 1")
|
|
307
|
+
.get(Number(version.rowId));
|
|
308
|
+
if (liveChildren !== undefined) {
|
|
309
|
+
return `type "${String(row.name)}" (${version.rowId}): live children still attached`;
|
|
310
|
+
}
|
|
311
|
+
writeVersion(db, undoId, "types", version.rowId, row, { ...row, archived: 1 }, now);
|
|
312
|
+
db.raw()
|
|
313
|
+
.prepare("UPDATE types SET archived = 1, version = version + 1 WHERE id = ?")
|
|
314
|
+
.run(Number(version.rowId));
|
|
315
|
+
return "restored";
|
|
316
|
+
}
|
|
317
|
+
const before = JSON.parse(version.before ?? "null");
|
|
318
|
+
const after = JSON.parse(version.after ?? "null");
|
|
319
|
+
const differs = afterDiffersFromRow(after, row, [
|
|
320
|
+
"name",
|
|
321
|
+
"description",
|
|
322
|
+
"parentId",
|
|
323
|
+
"fields",
|
|
324
|
+
"archived",
|
|
325
|
+
]);
|
|
326
|
+
if (before === null || after === null || differs !== null) {
|
|
327
|
+
return `type "${String(row.name)}" (${version.rowId}): ${differs ?? "changed by a later change"}`;
|
|
328
|
+
}
|
|
329
|
+
const restoredRow = { ...row, ...before, id: row.id };
|
|
330
|
+
writeVersion(db, undoId, "types", version.rowId, row, restoredRow, now);
|
|
331
|
+
db.raw()
|
|
332
|
+
.prepare("UPDATE types SET description = ?, parentId = ?, fields = ?, archived = ?, version = version + 1 WHERE id = ?")
|
|
333
|
+
.run(restoredRow.description, restoredRow.parentId ?? null, restoredRow.fields, Number(restoredRow.archived ?? 0), Number(version.rowId));
|
|
334
|
+
return "restored";
|
|
335
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@sigrun/knowledge",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Curated per-user knowledge extension for sigrun (pi-durable)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22.19.0"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"CHANGELOG.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "node scripts/check-manifest.mjs --expect-name @sigrun/knowledge && vitest run",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"build": "tsc -p tsconfig.build.json",
|
|
25
|
+
"prepare": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@earendil-works/chord": "~1.5.0",
|
|
29
|
+
"@earendil-works/pi-ai": "~1.5.0",
|
|
30
|
+
"@earendil-works/pi-durable": "~1.5.0",
|
|
31
|
+
"@sigrun/shared": "0.5.0 || 0.6.0 || 0.6.1 || 0.7.0 || 0.8.0 || 0.9.0 || 0.10.0 || 0.10.1 || 0.11.0",
|
|
32
|
+
"typebox": "1.3.27"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@earendil-works/chord": "1.5.0",
|
|
36
|
+
"@earendil-works/pi-ai": "1.5.0",
|
|
37
|
+
"@earendil-works/pi-durable": "1.5.0",
|
|
38
|
+
"@sigrun/shared": "file:../sigrun/shared",
|
|
39
|
+
"@sigrun/sigrun": "file:../sigrun",
|
|
40
|
+
"@types/node": "^26.6.4",
|
|
41
|
+
"tsx": "^4.23.15",
|
|
42
|
+
"typebox": "1.3.27",
|
|
43
|
+
"typescript": "^7.0.2",
|
|
44
|
+
"vitest": "^5.0.3"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "github",
|
|
49
|
+
"url": "git+https://github.com/sigrun-ai/sigrun-knowledge.git"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/sigrun-ai/sigrun-knowledge/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/sigrun-ai/sigrun-knowledge#readme",
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"provenance": true
|
|
58
|
+
}
|
|
59
|
+
}
|