@jbarket/loomai 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/CHANGELOG.md +475 -0
  2. package/LICENSE +661 -0
  3. package/README.md +702 -0
  4. package/assets/demo.cast +396 -0
  5. package/assets/skill/SKILL.md +192 -0
  6. package/dist/backends/embedding-runtime.d.ts +39 -0
  7. package/dist/backends/embedding-runtime.js +265 -0
  8. package/dist/backends/episodes.d.ts +36 -0
  9. package/dist/backends/episodes.js +126 -0
  10. package/dist/backends/fastembed.d.ts +18 -0
  11. package/dist/backends/fastembed.js +95 -0
  12. package/dist/backends/glob.d.ts +10 -0
  13. package/dist/backends/glob.js +16 -0
  14. package/dist/backends/index.d.ts +6 -0
  15. package/dist/backends/index.js +78 -0
  16. package/dist/backends/migrations.d.ts +38 -0
  17. package/dist/backends/migrations.js +157 -0
  18. package/dist/backends/mmr.d.ts +45 -0
  19. package/dist/backends/mmr.js +82 -0
  20. package/dist/backends/proposals.d.ts +65 -0
  21. package/dist/backends/proposals.js +182 -0
  22. package/dist/backends/recall-log.d.ts +42 -0
  23. package/dist/backends/recall-log.js +143 -0
  24. package/dist/backends/retry.d.ts +29 -0
  25. package/dist/backends/retry.js +60 -0
  26. package/dist/backends/salience.d.ts +57 -0
  27. package/dist/backends/salience.js +186 -0
  28. package/dist/backends/sqlite-knowledge.d.ts +37 -0
  29. package/dist/backends/sqlite-knowledge.js +788 -0
  30. package/dist/backends/sqlite-vec.d.ts +64 -0
  31. package/dist/backends/sqlite-vec.js +737 -0
  32. package/dist/backends/ttl.d.ts +24 -0
  33. package/dist/backends/ttl.js +50 -0
  34. package/dist/backends/types.d.ts +562 -0
  35. package/dist/backends/types.js +8 -0
  36. package/dist/blocks/harness.d.ts +45 -0
  37. package/dist/blocks/harness.js +142 -0
  38. package/dist/blocks/model.d.ts +4 -0
  39. package/dist/blocks/model.js +56 -0
  40. package/dist/blocks/types.d.ts +40 -0
  41. package/dist/blocks/types.js +34 -0
  42. package/dist/categories.d.ts +16 -0
  43. package/dist/categories.js +29 -0
  44. package/dist/cli/args.d.ts +21 -0
  45. package/dist/cli/args.js +47 -0
  46. package/dist/cli/bootstrap.d.ts +2 -0
  47. package/dist/cli/bootstrap.js +214 -0
  48. package/dist/cli/doctor.d.ts +2 -0
  49. package/dist/cli/doctor.js +206 -0
  50. package/dist/cli/forget.d.ts +2 -0
  51. package/dist/cli/forget.js +97 -0
  52. package/dist/cli/harness.d.ts +2 -0
  53. package/dist/cli/harness.js +91 -0
  54. package/dist/cli/index.d.ts +2 -0
  55. package/dist/cli/index.js +127 -0
  56. package/dist/cli/inject.d.ts +2 -0
  57. package/dist/cli/inject.js +298 -0
  58. package/dist/cli/install.d.ts +2 -0
  59. package/dist/cli/install.js +137 -0
  60. package/dist/cli/io.d.ts +14 -0
  61. package/dist/cli/io.js +63 -0
  62. package/dist/cli/knowledge.d.ts +2 -0
  63. package/dist/cli/knowledge.js +216 -0
  64. package/dist/cli/memory.d.ts +2 -0
  65. package/dist/cli/memory.js +608 -0
  66. package/dist/cli/migrate.d.ts +2 -0
  67. package/dist/cli/migrate.js +116 -0
  68. package/dist/cli/recall.d.ts +2 -0
  69. package/dist/cli/recall.js +91 -0
  70. package/dist/cli/remember.d.ts +2 -0
  71. package/dist/cli/remember.js +111 -0
  72. package/dist/cli/serve.d.ts +2 -0
  73. package/dist/cli/serve.js +71 -0
  74. package/dist/cli/subcommands.d.ts +7 -0
  75. package/dist/cli/subcommands.js +11 -0
  76. package/dist/cli/tui/multi-select.d.ts +53 -0
  77. package/dist/cli/tui/multi-select.js +116 -0
  78. package/dist/cli/update-identity.d.ts +2 -0
  79. package/dist/cli/update-identity.js +90 -0
  80. package/dist/cli/update.d.ts +2 -0
  81. package/dist/cli/update.js +87 -0
  82. package/dist/cli/wake.d.ts +2 -0
  83. package/dist/cli/wake.js +53 -0
  84. package/dist/clients.d.ts +8 -0
  85. package/dist/clients.js +63 -0
  86. package/dist/config.d.ts +59 -0
  87. package/dist/config.js +160 -0
  88. package/dist/index.d.ts +15 -0
  89. package/dist/index.js +75 -0
  90. package/dist/injection/harnesses.d.ts +17 -0
  91. package/dist/injection/harnesses.js +51 -0
  92. package/dist/injection/render.d.ts +17 -0
  93. package/dist/injection/render.js +50 -0
  94. package/dist/injection/writer.d.ts +25 -0
  95. package/dist/injection/writer.js +118 -0
  96. package/dist/install/harnesses.d.ts +26 -0
  97. package/dist/install/harnesses.js +90 -0
  98. package/dist/install/names.d.ts +16 -0
  99. package/dist/install/names.js +36 -0
  100. package/dist/install/render.d.ts +18 -0
  101. package/dist/install/render.js +42 -0
  102. package/dist/install/skill-source.d.ts +1 -0
  103. package/dist/install/skill-source.js +11 -0
  104. package/dist/path-safety.d.ts +19 -0
  105. package/dist/path-safety.js +62 -0
  106. package/dist/server.d.ts +8 -0
  107. package/dist/server.js +571 -0
  108. package/dist/tools/append-maintenance-log.d.ts +52 -0
  109. package/dist/tools/append-maintenance-log.js +103 -0
  110. package/dist/tools/archive.d.ts +2 -0
  111. package/dist/tools/archive.js +21 -0
  112. package/dist/tools/bootstrap.d.ts +11 -0
  113. package/dist/tools/bootstrap.js +161 -0
  114. package/dist/tools/dossier.d.ts +1 -0
  115. package/dist/tools/dossier.js +102 -0
  116. package/dist/tools/eurorack-import.d.ts +47 -0
  117. package/dist/tools/eurorack-import.js +199 -0
  118. package/dist/tools/find-similar.d.ts +3 -0
  119. package/dist/tools/find-similar.js +26 -0
  120. package/dist/tools/forget.d.ts +6 -0
  121. package/dist/tools/forget.js +70 -0
  122. package/dist/tools/harness.d.ts +18 -0
  123. package/dist/tools/harness.js +54 -0
  124. package/dist/tools/identity-scaffold.d.ts +22 -0
  125. package/dist/tools/identity-scaffold.js +142 -0
  126. package/dist/tools/identity.d.ts +4 -0
  127. package/dist/tools/identity.js +226 -0
  128. package/dist/tools/knowledge-archive.d.ts +5 -0
  129. package/dist/tools/knowledge-archive.js +24 -0
  130. package/dist/tools/knowledge-history.d.ts +6 -0
  131. package/dist/tools/knowledge-history.js +55 -0
  132. package/dist/tools/knowledge-maintain.d.ts +9 -0
  133. package/dist/tools/knowledge-maintain.js +113 -0
  134. package/dist/tools/knowledge-merge.d.ts +8 -0
  135. package/dist/tools/knowledge-merge.js +40 -0
  136. package/dist/tools/knowledge-move.d.ts +10 -0
  137. package/dist/tools/knowledge-move.js +48 -0
  138. package/dist/tools/knowledge-purge.d.ts +5 -0
  139. package/dist/tools/knowledge-purge.js +20 -0
  140. package/dist/tools/knowledge-recall.d.ts +20 -0
  141. package/dist/tools/knowledge-recall.js +142 -0
  142. package/dist/tools/knowledge-restore.d.ts +4 -0
  143. package/dist/tools/knowledge-restore.js +24 -0
  144. package/dist/tools/knowledge-supersede.d.ts +6 -0
  145. package/dist/tools/knowledge-supersede.js +36 -0
  146. package/dist/tools/knowledge-verify.d.ts +8 -0
  147. package/dist/tools/knowledge-verify.js +39 -0
  148. package/dist/tools/knowledge-write.d.ts +25 -0
  149. package/dist/tools/knowledge-write.js +87 -0
  150. package/dist/tools/memory-audit.d.ts +3 -0
  151. package/dist/tools/memory-audit.js +47 -0
  152. package/dist/tools/memory-list.d.ts +4 -0
  153. package/dist/tools/memory-list.js +23 -0
  154. package/dist/tools/prune.d.ts +4 -0
  155. package/dist/tools/prune.js +28 -0
  156. package/dist/tools/recall.d.ts +4 -0
  157. package/dist/tools/recall.js +24 -0
  158. package/dist/tools/remember.d.ts +10 -0
  159. package/dist/tools/remember.js +43 -0
  160. package/dist/tools/restore.d.ts +2 -0
  161. package/dist/tools/restore.js +20 -0
  162. package/dist/tools/update-identity.d.ts +34 -0
  163. package/dist/tools/update-identity.js +194 -0
  164. package/dist/tools/update.d.ts +2 -0
  165. package/dist/tools/update.js +16 -0
  166. package/dist/transport/guards.d.ts +35 -0
  167. package/dist/transport/guards.js +107 -0
  168. package/dist/transport/http-server.d.ts +17 -0
  169. package/dist/transport/http-server.js +198 -0
  170. package/dist/transport/mcp-app-hello.d.ts +3 -0
  171. package/dist/transport/mcp-app-hello.js +66 -0
  172. package/dist/widgets/display-modes.html +131 -0
  173. package/dist/widgets/hello.html +138 -0
  174. package/dist/widgets/proposals.html +131 -0
  175. package/dist/widgets/top-of-mind.html +131 -0
  176. package/package.json +73 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * loom knowledge — write / recall / maintain the knowledge store.
3
+ */
4
+ import { parseArgs } from 'node:util';
5
+ import { knowledgeWrite } from '../tools/knowledge-write.js';
6
+ import { knowledgeRecall } from '../tools/knowledge-recall.js';
7
+ import { knowledgeMaintain } from '../tools/knowledge-maintain.js';
8
+ import { createKnowledgeBackend } from '../backends/index.js';
9
+ import { extractGlobalFlags, resolveEnv } from './args.js';
10
+ import { renderJson } from './io.js';
11
+ const USAGE = `Usage: loom knowledge <subcommand> [options]
12
+
13
+ Subcommands:
14
+ write Upsert an entity page (create or append/revise body in place)
15
+ recall Search knowledge pages (LIKE over title+body+domain)
16
+ maintain Read-only health report (expansion candidates, cold pages, misfile audit)
17
+
18
+ Options (write):
19
+ --slug <slug> Entity key for upsert (default: derived from title)
20
+ --title <title> Page title (required)
21
+ --domain <domain> Domain tag, e.g. music/eurorack (required)
22
+ --body <text> Page body markdown (required)
23
+ --citation <json> Citation JSON: '{"claim":"...","source_kind":"web","source_locator":"...","excerpt":"..."}' (repeatable)
24
+ --json Emit KnowledgeWriteResult
25
+
26
+ Options (recall):
27
+ <query> Search terms (positional, optional)
28
+ --domain <domain> Filter by domain prefix
29
+ --limit <n> Max results (default 10)
30
+ --json Emit KnowledgePageWithCitations[]
31
+
32
+ Options (maintain):
33
+ --expansion-hit-threshold <n> hit_count floor for expansion candidates (default 3)
34
+ --thin-body-threshold <n> body char ceiling for thin pages (default 500)
35
+ --cold-days <n> days without access = cold (default 30)
36
+ --json Emit raw report object
37
+
38
+ Global: --context-dir, --help/-h
39
+ `;
40
+ const SUBCOMMANDS = new Set(['write', 'recall', 'maintain']);
41
+ export async function run(argv, io) {
42
+ const { flags: global, rest } = extractGlobalFlags(argv);
43
+ const sub = rest[0];
44
+ const subRest = rest.slice(1);
45
+ if (!sub || sub === '--help' || sub === '-h') {
46
+ io.stdout(USAGE);
47
+ return sub ? 0 : 2;
48
+ }
49
+ if (!SUBCOMMANDS.has(sub)) {
50
+ io.stderr(`Unknown knowledge subcommand: ${sub}\n${USAGE}`);
51
+ return 2;
52
+ }
53
+ // Subcommand-level --help, honoured before any side effect (see memory.ts).
54
+ if (subRest[0] === '--help' || subRest[0] === '-h') {
55
+ io.stdout(USAGE);
56
+ return 0;
57
+ }
58
+ const env = resolveEnv(global, io.env);
59
+ if (sub === 'write') {
60
+ let parsed;
61
+ try {
62
+ parsed = parseArgs({
63
+ args: subRest,
64
+ options: {
65
+ slug: { type: 'string' },
66
+ title: { type: 'string' },
67
+ domain: { type: 'string' },
68
+ body: { type: 'string' },
69
+ citation: { type: 'string', multiple: true },
70
+ },
71
+ strict: true,
72
+ allowPositionals: false,
73
+ });
74
+ }
75
+ catch (err) {
76
+ io.stderr(`${err.message}\n${USAGE}`);
77
+ return 2;
78
+ }
79
+ const { title, domain, body } = parsed.values;
80
+ if (!title || !domain || !body) {
81
+ io.stderr(`--title, --domain, and --body are required for knowledge write.\n`);
82
+ return 2;
83
+ }
84
+ const rawCitations = parsed.values.citation ?? [];
85
+ const citations = [];
86
+ for (const raw of rawCitations) {
87
+ try {
88
+ const cit = JSON.parse(raw);
89
+ if (!cit.claim || !cit.source_kind || !cit.excerpt) {
90
+ io.stderr(`Invalid citation JSON (missing claim, source_kind, or excerpt): ${raw}\n`);
91
+ return 2;
92
+ }
93
+ citations.push(cit);
94
+ }
95
+ catch {
96
+ io.stderr(`Could not parse --citation as JSON: ${raw}\n`);
97
+ return 2;
98
+ }
99
+ }
100
+ if (env.json) {
101
+ if (citations.length === 0) {
102
+ io.stderr('Error: at least one citation is required for knowledge write.\n');
103
+ return 1;
104
+ }
105
+ const sourcing = citations.every((c) => c.source_kind === 'conversation') ? 'provisional' : 'sourced';
106
+ const backend = createKnowledgeBackend(env.contextDir);
107
+ try {
108
+ const result = await backend.writePage({
109
+ slug: parsed.values.slug ?? title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''),
110
+ title,
111
+ domain,
112
+ body,
113
+ sourcing,
114
+ citations,
115
+ });
116
+ renderJson(io, result);
117
+ return 0;
118
+ }
119
+ finally {
120
+ backend.close();
121
+ }
122
+ }
123
+ const text = await knowledgeWrite(env.contextDir, {
124
+ slug: parsed.values.slug,
125
+ title,
126
+ domain,
127
+ body,
128
+ citations,
129
+ });
130
+ io.stdout(text.endsWith('\n') ? text : text + '\n');
131
+ return text.startsWith('Error') ? 1 : 0;
132
+ }
133
+ if (sub === 'recall') {
134
+ let parsed;
135
+ try {
136
+ parsed = parseArgs({
137
+ args: subRest,
138
+ options: {
139
+ domain: { type: 'string' },
140
+ limit: { type: 'string' },
141
+ },
142
+ strict: true,
143
+ allowPositionals: true,
144
+ });
145
+ }
146
+ catch (err) {
147
+ io.stderr(`${err.message}\n${USAGE}`);
148
+ return 2;
149
+ }
150
+ const query = parsed.positionals[0];
151
+ const limit = parsed.values.limit !== undefined
152
+ ? Number.parseInt(parsed.values.limit, 10)
153
+ : undefined;
154
+ if (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {
155
+ io.stderr(`--limit must be a positive integer.\n`);
156
+ return 2;
157
+ }
158
+ if (env.json) {
159
+ const backend = createKnowledgeBackend(env.contextDir);
160
+ try {
161
+ const pages = await backend.queryPages({
162
+ query,
163
+ domain: parsed.values.domain,
164
+ excludeStatus: 'archived',
165
+ limit: limit ?? 10,
166
+ });
167
+ renderJson(io, pages);
168
+ return 0;
169
+ }
170
+ finally {
171
+ backend.close();
172
+ }
173
+ }
174
+ const text = await knowledgeRecall(env.contextDir, {
175
+ query,
176
+ domain: parsed.values.domain,
177
+ limit,
178
+ });
179
+ io.stdout(text.endsWith('\n') ? text : text + '\n');
180
+ return 0;
181
+ }
182
+ // maintain
183
+ let parsed;
184
+ try {
185
+ parsed = parseArgs({
186
+ args: subRest,
187
+ options: {
188
+ 'expansion-hit-threshold': { type: 'string' },
189
+ 'thin-body-threshold': { type: 'string' },
190
+ 'cold-days': { type: 'string' },
191
+ },
192
+ strict: true,
193
+ allowPositionals: false,
194
+ });
195
+ }
196
+ catch (err) {
197
+ io.stderr(`${err.message}\n${USAGE}`);
198
+ return 2;
199
+ }
200
+ const expansionHitThreshold = parsed.values['expansion-hit-threshold'] !== undefined
201
+ ? Number.parseInt(parsed.values['expansion-hit-threshold'], 10)
202
+ : undefined;
203
+ const thinBodyThreshold = parsed.values['thin-body-threshold'] !== undefined
204
+ ? Number.parseInt(parsed.values['thin-body-threshold'], 10)
205
+ : undefined;
206
+ const coldDays = parsed.values['cold-days'] !== undefined
207
+ ? Number.parseInt(parsed.values['cold-days'], 10)
208
+ : undefined;
209
+ const text = await knowledgeMaintain(env.contextDir, {
210
+ expansionHitThreshold,
211
+ thinBodyThreshold,
212
+ coldDays,
213
+ });
214
+ io.stdout(text.endsWith('\n') ? text : text + '\n');
215
+ return 0;
216
+ }
@@ -0,0 +1,2 @@
1
+ import type { IOStreams } from './io.js';
2
+ export declare function run(argv: string[], io: IOStreams): Promise<number>;