@phamvuhoang/otto-core 0.22.0 → 0.24.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.
@@ -0,0 +1,417 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
+ import { join, relative, sep } from "node:path";
4
+ import { skillDir, skillExists, toSkillName, writeSkill, } from "./skills.js";
5
+ const SOURCES_REL = join(".otto", "skills", "sources.json");
6
+ const LOCK_REL = join(".otto", "skills.lock.json");
7
+ const SKILL_MD = "SKILL.md";
8
+ const MAX_DEPTH = 8;
9
+ /** Absolute path to the sources config (`.otto/skills/sources.json`). */
10
+ export function sourcesPath(workspaceDir) {
11
+ return join(workspaceDir, SOURCES_REL);
12
+ }
13
+ /** Absolute path to the import lockfile (`.otto/skills.lock.json`). */
14
+ export function lockPath(workspaceDir) {
15
+ return join(workspaceDir, LOCK_REL);
16
+ }
17
+ const SOURCE_TYPES = new Set([
18
+ "git",
19
+ "local",
20
+ "archive",
21
+ "registry",
22
+ ]);
23
+ function stringArray(raw) {
24
+ return Array.isArray(raw)
25
+ ? raw.filter((s) => typeof s === "string")
26
+ : [];
27
+ }
28
+ /** Normalize one untrusted source entry; null when it lacks the required shape. */
29
+ export function parseSource(raw) {
30
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
31
+ return null;
32
+ const o = raw;
33
+ if (typeof o.name !== "string" || o.name.length === 0)
34
+ return null;
35
+ if (typeof o.location !== "string" || o.location.length === 0)
36
+ return null;
37
+ const type = typeof o.type === "string" && SOURCE_TYPES.has(o.type)
38
+ ? o.type
39
+ : "local";
40
+ const src = { name: o.name, type, location: o.location };
41
+ if (typeof o.ref === "string" && o.ref.length > 0)
42
+ src.ref = o.ref;
43
+ return src;
44
+ }
45
+ /** Read configured sources; absent/malformed → `[]` (never throws). */
46
+ export function readSources(workspaceDir) {
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(readFileSync(sourcesPath(workspaceDir), "utf8"));
50
+ }
51
+ catch {
52
+ return [];
53
+ }
54
+ const list = parsed && typeof parsed === "object" && !Array.isArray(parsed)
55
+ ? parsed.sources
56
+ : parsed;
57
+ if (!Array.isArray(list))
58
+ return [];
59
+ const out = [];
60
+ for (const r of list) {
61
+ const s = parseSource(r);
62
+ if (s)
63
+ out.push(s);
64
+ }
65
+ return out;
66
+ }
67
+ /** Write the sources config, sorted by name for deterministic diffs. */
68
+ export function writeSources(workspaceDir, sources) {
69
+ const sorted = [...sources].sort((a, b) => a.name.localeCompare(b.name));
70
+ writeFileSync(sourcesPath(workspaceDir), JSON.stringify({ sources: sorted }, null, 2) + "\n");
71
+ }
72
+ function parseLockEntry(raw) {
73
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
74
+ return null;
75
+ const o = raw;
76
+ if (typeof o.skill !== "string" || typeof o.source !== "string")
77
+ return null;
78
+ if (typeof o.checksum !== "string" || typeof o.importedAt !== "string") {
79
+ return null;
80
+ }
81
+ const type = typeof o.type === "string" && SOURCE_TYPES.has(o.type)
82
+ ? o.type
83
+ : "local";
84
+ const e = {
85
+ skill: o.skill,
86
+ source: o.source,
87
+ type,
88
+ upstreamPath: typeof o.upstreamPath === "string" ? o.upstreamPath : "",
89
+ checksum: o.checksum,
90
+ importedAt: o.importedAt,
91
+ capabilities: stringArray(o.capabilities),
92
+ };
93
+ if (typeof o.ref === "string")
94
+ e.ref = o.ref;
95
+ if (typeof o.license === "string")
96
+ e.license = o.license;
97
+ return e;
98
+ }
99
+ /** Read the import lock; absent/malformed → `{ entries: [] }` (never throws). */
100
+ export function readLock(workspaceDir) {
101
+ let parsed;
102
+ try {
103
+ parsed = JSON.parse(readFileSync(lockPath(workspaceDir), "utf8"));
104
+ }
105
+ catch {
106
+ return { entries: [] };
107
+ }
108
+ const list = parsed && typeof parsed === "object" && !Array.isArray(parsed)
109
+ ? parsed.entries
110
+ : parsed;
111
+ if (!Array.isArray(list))
112
+ return { entries: [] };
113
+ const entries = [];
114
+ for (const r of list) {
115
+ const e = parseLockEntry(r);
116
+ if (e)
117
+ entries.push(e);
118
+ }
119
+ return { entries };
120
+ }
121
+ /** Write the lock, entries sorted by skill name for deterministic diffs. */
122
+ export function writeLock(workspaceDir, lock) {
123
+ const entries = [...lock.entries].sort((a, b) => a.skill.localeCompare(b.skill));
124
+ writeFileSync(lockPath(workspaceDir), JSON.stringify({ entries }, null, 2) + "\n");
125
+ }
126
+ /** Add (or replace by name) a source. Pure — returns a new array. */
127
+ export function addSource(sources, source) {
128
+ return [...sources.filter((s) => s.name !== source.name), source];
129
+ }
130
+ /** Remove a source by name. Pure — returns a new array. */
131
+ export function removeSource(sources, name) {
132
+ return sources.filter((s) => s.name !== name);
133
+ }
134
+ /** sha256 of a buffer/string, hex (stable content checksum). */
135
+ function checksum(content) {
136
+ return createHash("sha256").update(content).digest("hex");
137
+ }
138
+ /**
139
+ * Parse a leading `--- … ---` frontmatter block into flat string fields plus the
140
+ * remaining body. Minimal `key: value` parsing (no nested YAML) — enough for the
141
+ * `name`/`description`/`license`/`capabilities` fields skill packs declare.
142
+ */
143
+ export function parseFrontmatter(text) {
144
+ const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
145
+ if (!m)
146
+ return { fields: {}, body: text };
147
+ const fields = {};
148
+ for (const line of m[1].split(/\r?\n/)) {
149
+ const kv = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
150
+ if (kv)
151
+ fields[kv[1].toLowerCase()] = kv[2].trim();
152
+ }
153
+ return { fields, body: text.slice(m[0].length) };
154
+ }
155
+ function splitList(raw) {
156
+ if (!raw)
157
+ return [];
158
+ return raw
159
+ .replace(/^\[|\]$/g, "")
160
+ .split(",")
161
+ .map((s) => s.trim().replace(/^["']|["']$/g, ""))
162
+ .filter((s) => s.length > 0);
163
+ }
164
+ function listDirs(dir) {
165
+ try {
166
+ return readdirSync(dir, { withFileTypes: true })
167
+ .filter((e) => e.isDirectory())
168
+ .map((e) => e.name);
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ }
174
+ /**
175
+ * Find every `SKILL.md` package under a local source directory (recursively,
176
+ * depth-bounded). Covers the `skills/<name>/SKILL.md` Superpowers/PM-Skills shape
177
+ * and `.codex-plugin`/`.claude-plugin` bundles that nest the same file. Each
178
+ * package's skill name comes from its SKILL.md `name:` frontmatter, else its
179
+ * containing directory name, slugified. Returns packages sorted by name. Absent/
180
+ * unreadable dir → `[]` (never throws).
181
+ */
182
+ export function discoverPackages(sourceDir) {
183
+ const found = [];
184
+ const walk = (dir, depth) => {
185
+ if (depth > MAX_DEPTH)
186
+ return;
187
+ const mdPath = join(dir, SKILL_MD);
188
+ if (existsSync(mdPath)) {
189
+ let raw;
190
+ try {
191
+ raw = readFileSync(mdPath, "utf8");
192
+ }
193
+ catch {
194
+ raw = "";
195
+ }
196
+ const { fields } = parseFrontmatter(raw);
197
+ const rel = relative(sourceDir, dir);
198
+ const name = toSkillName(fields.name ?? "") ||
199
+ toSkillName(rel.split(sep).pop() ?? "") ||
200
+ toSkillName(rel);
201
+ if (name) {
202
+ found.push({
203
+ name,
204
+ upstreamPath: rel === "" ? "." : rel.split(sep).join("/"),
205
+ raw,
206
+ });
207
+ }
208
+ return; // a package directory is a leaf; don't descend into it
209
+ }
210
+ for (const child of listDirs(dir))
211
+ walk(join(dir, child), depth + 1);
212
+ };
213
+ walk(sourceDir, 0);
214
+ return found.sort((a, b) => a.name.localeCompare(b.name));
215
+ }
216
+ /**
217
+ * Normalize a discovered package + its source into an unverified, inert
218
+ * {@link Skill} plus the resolved {@link ExternalSkillLockEntry}. The skill body
219
+ * is the SKILL.md content minus frontmatter; capabilities come from a
220
+ * `capabilities:` frontmatter field when present (else empty); trust is always
221
+ * `unverified` and validation empty so the loop cannot apply it. `now` is the
222
+ * import timestamp (injected for deterministic tests).
223
+ */
224
+ export function normalizePackage(source, pkg, now) {
225
+ const { fields, body } = parseFrontmatter(pkg.raw);
226
+ const capabilities = splitList(fields.capabilities);
227
+ const license = fields.license;
228
+ // Checksum the persisted body (what lands in instructions.md) so a later audit
229
+ // can recompute it from disk and detect hand-edits after import.
230
+ const instructions = body.trim() + "\n";
231
+ const sum = checksum(instructions);
232
+ const provenance = {
233
+ source: source.name,
234
+ upstreamPath: pkg.upstreamPath,
235
+ checksum: sum,
236
+ };
237
+ if (source.ref)
238
+ provenance.upstreamRef = source.ref;
239
+ if (license)
240
+ provenance.license = license;
241
+ const skill = {
242
+ name: pkg.name,
243
+ version: typeof fields.version === "string" ? fields.version : "0.0.0",
244
+ capabilities,
245
+ constraints: [],
246
+ scope: [],
247
+ instructions,
248
+ scripts: {},
249
+ tests: [],
250
+ validation: {},
251
+ trust: "unverified",
252
+ createdAt: now.toISOString(),
253
+ useCount: 0,
254
+ provenance,
255
+ };
256
+ const entry = {
257
+ skill: pkg.name,
258
+ source: source.name,
259
+ type: source.type,
260
+ upstreamPath: pkg.upstreamPath,
261
+ checksum: sum,
262
+ importedAt: now.toISOString(),
263
+ capabilities,
264
+ };
265
+ if (source.ref)
266
+ entry.ref = source.ref;
267
+ if (license)
268
+ entry.license = license;
269
+ return { skill, entry };
270
+ }
271
+ /**
272
+ * Compute a deterministic sync plan over the given local sources without writing
273
+ * anything — the engine behind both `sync --dry-run` and `sync`. For each source
274
+ * (in name order) every discovered package is classified:
275
+ *
276
+ * - `conflict` — a different source earlier in the plan already claims the name;
277
+ * - `add` — the skill is not present on disk;
278
+ * - `update` — present, but the lock's recorded checksum differs (drift);
279
+ * - `unchanged` — present and the checksum matches the lock.
280
+ *
281
+ * Only `local` sources resolve in this slice; other types are skipped (a later
282
+ * slice adds git/archive fetch ahead of this same planner).
283
+ */
284
+ export function planSync(workspaceDir, sources, now) {
285
+ const lock = readLock(workspaceDir);
286
+ const lockBySkill = new Map(lock.entries.map((e) => [e.skill, e]));
287
+ const claimedBy = new Map();
288
+ const items = [];
289
+ for (const source of [...sources].sort((a, b) => a.name.localeCompare(b.name))) {
290
+ if (source.type !== "local")
291
+ continue;
292
+ for (const pkg of discoverPackages(source.location)) {
293
+ const resolved = normalizePackage(source, pkg, now);
294
+ const claimer = claimedBy.get(pkg.name);
295
+ if (claimer && claimer !== source.name) {
296
+ items.push({
297
+ skill: pkg.name,
298
+ source: source.name,
299
+ action: "conflict",
300
+ conflictWith: claimer,
301
+ resolved,
302
+ });
303
+ continue;
304
+ }
305
+ claimedBy.set(pkg.name, source.name);
306
+ let action;
307
+ const locked = lockBySkill.get(pkg.name);
308
+ if (!skillExists(workspaceDir, pkg.name) || !locked) {
309
+ action = "add";
310
+ }
311
+ else if (locked.checksum !== resolved.entry.checksum) {
312
+ action = "update";
313
+ }
314
+ else {
315
+ action = "unchanged";
316
+ }
317
+ items.push({ skill: pkg.name, source: source.name, action, resolved });
318
+ }
319
+ }
320
+ return { items };
321
+ }
322
+ /**
323
+ * Apply a sync plan: write each `add`/`update` skill package and refresh the lock
324
+ * to exactly the set of resolved (non-conflict) packages. `conflict` items are
325
+ * skipped (logged by the caller). Returns the persisted lock. Side-effecting
326
+ * counterpart to {@link planSync}; the dry-run path calls `planSync` only.
327
+ */
328
+ export function applySync(workspaceDir, plan) {
329
+ const entries = [];
330
+ for (const item of plan.items) {
331
+ if (item.action === "conflict")
332
+ continue;
333
+ if (item.action === "add" || item.action === "update") {
334
+ writeSkill(workspaceDir, item.resolved.skill);
335
+ }
336
+ entries.push(item.resolved.entry);
337
+ }
338
+ const lock = { entries };
339
+ writeLock(workspaceDir, lock);
340
+ return lock;
341
+ }
342
+ /**
343
+ * Audit the external registry (`otto-skills audit --external`). Surfaces:
344
+ * unpinned source refs, lock entries with no license, duplicate skill names
345
+ * across sources, sources whose type this slice cannot resolve, and stale
346
+ * imported copies (on-disk skill checksum drifted from the lock). Pure over the
347
+ * given sources/lock + a checksum probe; deterministic, sorted by kind+subject.
348
+ */
349
+ export function auditExternal(sources, lock, onDiskChecksum) {
350
+ const findings = [];
351
+ for (const s of sources) {
352
+ if ((s.type === "git" || s.type === "archive") && !s.ref) {
353
+ findings.push({
354
+ kind: "unpinned-ref",
355
+ subject: s.name,
356
+ detail: `source "${s.name}" (${s.type}) has no pinned ref`,
357
+ });
358
+ }
359
+ if (s.type === "registry") {
360
+ findings.push({
361
+ kind: "unsupported-format",
362
+ subject: s.name,
363
+ detail: `source type "registry" is not resolvable yet`,
364
+ });
365
+ }
366
+ }
367
+ const bySkill = new Map();
368
+ for (const e of lock.entries) {
369
+ (bySkill.get(e.skill) ?? bySkill.set(e.skill, []).get(e.skill)).push(e);
370
+ }
371
+ for (const [skill, es] of bySkill) {
372
+ if (es.length > 1) {
373
+ const srcs = [...new Set(es.map((e) => e.source))].sort();
374
+ if (srcs.length > 1) {
375
+ findings.push({
376
+ kind: "duplicate-name",
377
+ subject: skill,
378
+ detail: `skill "${skill}" imported from multiple sources: ${srcs.join(", ")}`,
379
+ });
380
+ }
381
+ }
382
+ }
383
+ for (const e of lock.entries) {
384
+ if (!e.license) {
385
+ findings.push({
386
+ kind: "missing-license",
387
+ subject: e.skill,
388
+ detail: `imported skill "${e.skill}" (from ${e.source}) has no license`,
389
+ });
390
+ }
391
+ const disk = onDiskChecksum(e.skill);
392
+ if (disk !== null && disk !== e.checksum) {
393
+ findings.push({
394
+ kind: "stale-copy",
395
+ subject: e.skill,
396
+ detail: `on-disk "${e.skill}" drifted from lock (re-run sync)`,
397
+ });
398
+ }
399
+ }
400
+ return findings.sort((a, b) => a.kind.localeCompare(b.kind) || a.subject.localeCompare(b.subject));
401
+ }
402
+ /**
403
+ * Recompute the checksum of an imported skill's on-disk body (`instructions.md`)
404
+ * so {@link auditExternal} can compare it to the lock and flag a `stale-copy`
405
+ * when the package was hand-edited after import. Returns null when the skill or
406
+ * its body is absent. The hash domain matches {@link normalizePackage}.
407
+ */
408
+ export function importedChecksum(workspaceDir, skill) {
409
+ try {
410
+ const body = readFileSync(join(skillDir(workspaceDir, skill), "instructions.md"), "utf8");
411
+ return checksum(body);
412
+ }
413
+ catch {
414
+ return null;
415
+ }
416
+ }
417
+ //# sourceMappingURL=external-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-skills.js","sourceRoot":"","sources":["../src/external-skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { CompressInput, ContextCompressor } from "./context-compressor.js";
2
+ import type { ToolDefinition } from "./tools.js";
3
+ /**
4
+ * Headroom adapter (issue #112 P20) behind P19's external-tool contract.
5
+ * [Headroom](https://github.com/headroomlabs-ai/headroom) compresses token-heavy
6
+ * content (tool outputs, logs, RAG chunks, files, history). Otto talks to it as a
7
+ * governed {@link ToolDefinition}, so the same registry/policy authority that
8
+ * gates any tool gates the compressor — it can only run in allowed stages, with
9
+ * the declared scope.
10
+ *
11
+ * This slice implements **local-first command mode** (the roadmap's preferred,
12
+ * service-free path): Otto shells out to a local `headroom` binary, piping the
13
+ * content on stdin and reading the compressed result on stdout. MCP mode and the
14
+ * TypeScript library path slot in behind the same {@link ContextCompressor}
15
+ * interface without changing callers; proxy/wrapper mode stays an explicit
16
+ * advanced option because it alters provider transport.
17
+ *
18
+ * Everything is injectable ({@link HeadroomRunner}) so tests never spawn a real
19
+ * process, and a missing binary degrades cleanly (the compressor reports
20
+ * unavailable and the orchestrator keeps the original content).
21
+ */
22
+ /** The default binary, overridable via `OTTO_HEADROOM_BIN`. */
23
+ export declare const HEADROOM_VERSION = "headroom-cmd-1";
24
+ /**
25
+ * The low-level transport the adapter drives. The default shells out to the
26
+ * `headroom` CLI; tests inject a double. `available` is the health probe;
27
+ * `run` performs one compression.
28
+ */
29
+ export type HeadroomRunner = {
30
+ available: () => boolean;
31
+ run: (input: CompressInput) => {
32
+ ok: boolean;
33
+ text: string;
34
+ note?: string;
35
+ };
36
+ };
37
+ /**
38
+ * Default command-mode runner: `headroom --version` for availability, and
39
+ * `headroom compress --category <c>` (content on stdin → compressed stdout) for
40
+ * one compression. A non-zero exit / spawn error is a recoverable failure
41
+ * (`ok: false`), which the orchestrator turns into a degraded passthrough.
42
+ */
43
+ export declare function defaultHeadroomRunner(env?: NodeJS.ProcessEnv, timeoutMs?: number): HeadroomRunner;
44
+ /**
45
+ * Build a {@link ContextCompressor} over a {@link HeadroomRunner}. Availability
46
+ * is cached per instance after the first probe so a run does not re-spawn
47
+ * `headroom --version` for every compression.
48
+ */
49
+ export declare function createHeadroomCompressor(runner?: HeadroomRunner): ContextCompressor;
50
+ /**
51
+ * The {@link ToolDefinition} a repo drops into `.otto/tools/headroom.json` to put
52
+ * the compressor under registry/policy authority. `stages: []` keeps it opt-in
53
+ * (a repo enables it per stage); no network/write scope by default — local
54
+ * command mode touches neither. Returned as a value so `otto-extensions`
55
+ * (P21 `context-saver`) can generate it.
56
+ */
57
+ export declare function headroomToolDefinition(): ToolDefinition;
58
+ //# sourceMappingURL=headroom-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headroom-adapter.d.ts","sourceRoot":"","sources":["../src/headroom-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,GAAG,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E,CAAC;AAQF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,SAAS,GACjB,cAAc,CA2BhB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,cAAwC,GAC/C,iBAAiB,CAWnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,cAAc,CAiBvD"}
@@ -0,0 +1,106 @@
1
+ import { spawnSync } from "node:child_process";
2
+ /**
3
+ * Headroom adapter (issue #112 P20) behind P19's external-tool contract.
4
+ * [Headroom](https://github.com/headroomlabs-ai/headroom) compresses token-heavy
5
+ * content (tool outputs, logs, RAG chunks, files, history). Otto talks to it as a
6
+ * governed {@link ToolDefinition}, so the same registry/policy authority that
7
+ * gates any tool gates the compressor — it can only run in allowed stages, with
8
+ * the declared scope.
9
+ *
10
+ * This slice implements **local-first command mode** (the roadmap's preferred,
11
+ * service-free path): Otto shells out to a local `headroom` binary, piping the
12
+ * content on stdin and reading the compressed result on stdout. MCP mode and the
13
+ * TypeScript library path slot in behind the same {@link ContextCompressor}
14
+ * interface without changing callers; proxy/wrapper mode stays an explicit
15
+ * advanced option because it alters provider transport.
16
+ *
17
+ * Everything is injectable ({@link HeadroomRunner}) so tests never spawn a real
18
+ * process, and a missing binary degrades cleanly (the compressor reports
19
+ * unavailable and the orchestrator keeps the original content).
20
+ */
21
+ /** The default binary, overridable via `OTTO_HEADROOM_BIN`. */
22
+ export const HEADROOM_VERSION = "headroom-cmd-1";
23
+ /** Resolve the headroom binary name (env override, else `headroom`). */
24
+ function headroomBin(env) {
25
+ const b = env.OTTO_HEADROOM_BIN;
26
+ return typeof b === "string" && b.length > 0 ? b : "headroom";
27
+ }
28
+ /**
29
+ * Default command-mode runner: `headroom --version` for availability, and
30
+ * `headroom compress --category <c>` (content on stdin → compressed stdout) for
31
+ * one compression. A non-zero exit / spawn error is a recoverable failure
32
+ * (`ok: false`), which the orchestrator turns into a degraded passthrough.
33
+ */
34
+ export function defaultHeadroomRunner(env = process.env, timeoutMs = 30_000) {
35
+ const bin = headroomBin(env);
36
+ return {
37
+ available: () => {
38
+ try {
39
+ return spawnSync(bin, ["--version"], { timeout: 5_000 }).status === 0;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ },
45
+ run: (input) => {
46
+ const r = spawnSync(bin, ["compress", "--category", input.category], {
47
+ input: input.text,
48
+ encoding: "utf8",
49
+ timeout: timeoutMs,
50
+ maxBuffer: 64 * 1024 * 1024,
51
+ });
52
+ if (r.status !== 0 || typeof r.stdout !== "string") {
53
+ return {
54
+ ok: false,
55
+ text: input.text,
56
+ note: r.error?.message ?? `headroom exit ${r.status}`,
57
+ };
58
+ }
59
+ return { ok: true, text: r.stdout };
60
+ },
61
+ };
62
+ }
63
+ /**
64
+ * Build a {@link ContextCompressor} over a {@link HeadroomRunner}. Availability
65
+ * is cached per instance after the first probe so a run does not re-spawn
66
+ * `headroom --version` for every compression.
67
+ */
68
+ export function createHeadroomCompressor(runner = defaultHeadroomRunner()) {
69
+ let probed;
70
+ return {
71
+ name: "headroom",
72
+ version: HEADROOM_VERSION,
73
+ isAvailable: () => {
74
+ if (probed === undefined)
75
+ probed = runner.available();
76
+ return probed;
77
+ },
78
+ compress: (input) => Promise.resolve(runner.run(input)),
79
+ };
80
+ }
81
+ /**
82
+ * The {@link ToolDefinition} a repo drops into `.otto/tools/headroom.json` to put
83
+ * the compressor under registry/policy authority. `stages: []` keeps it opt-in
84
+ * (a repo enables it per stage); no network/write scope by default — local
85
+ * command mode touches neither. Returned as a value so `otto-extensions`
86
+ * (P21 `context-saver`) can generate it.
87
+ */
88
+ export function headroomToolDefinition() {
89
+ return {
90
+ name: "headroom",
91
+ kind: "command",
92
+ description: "Local-first context compressor (Headroom command mode).",
93
+ capabilities: ["compression", "context-engineering"],
94
+ stages: [],
95
+ command: "headroom compress",
96
+ env: ["OTTO_HEADROOM_BIN"],
97
+ networkDomains: [],
98
+ writeRoots: [],
99
+ secretRefs: [],
100
+ approvalActions: [],
101
+ timeoutMs: 30_000,
102
+ healthCheck: "headroom --version",
103
+ enabled: true,
104
+ };
105
+ }
106
+ //# sourceMappingURL=headroom-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headroom-adapter.js","sourceRoot":"","sources":["../src/headroom-adapter.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -13,11 +13,13 @@ export { analyzeContext, estimateTokens, formatContextReport, type ContextBreakd
13
13
  export { DEFAULT_COMMITS_BUDGET_CHARS, compactCommits, formatCompactedCommits, parseCommitLog, type CommitEntry, type CompactedCommits, } from "./iteration-compaction.js";
14
14
  export { DEFAULT_CONTEXT_BUDGET_FRACTION, DEFAULT_CONTEXT_WINDOW_TOKENS, assessContextBudget, formatContextBudget, modelContextBudget, modelContextWindow, type BudgetRecommendation, type ContextBudgetAssessment, type ContextBudgetContext, } from "./context-budget.js";
15
15
  export { emptyReadLedger, fingerprintContent, formatReadReference, recordRead, summarizeReads, type DedupResult, type DedupSummary, type ReadFingerprint, type ReadLedger, type ReadStatus, } from "./read-dedup.js";
16
- export { allocateRunId, hasRunReport, listRunIds, readManifest, readRunReport, readStageRecords, runReportDir, runsDir, writeManifest, writeRunReport, writeStageRecord, type RunArtifact, type RunManifest, type SafetyEvent, type SkillUsage, type StageRecord, } from "./run-report.js";
16
+ export { allocateRunId, hasRunReport, listRunIds, readManifest, readRunReport, readStageRecords, runReportDir, runsDir, writeManifest, writeRunReport, writeStageRecord, type RunArtifact, type RunManifest, type SafetyEvent, type SkillUsage, type StageRecord, type ToolUsage, } from "./run-report.js";
17
17
  export { formatRunReport, runInspect, type InspectDeps } from "./inspect.js";
18
18
  export { formatPlainReport, runExplain, type ExplainDeps, } from "./report-explain.js";
19
19
  export { formatRunsList, runRuns, summarizeManifest, type RunsDeps, type RunSummary, } from "./runs-cli.js";
20
20
  export { formatContextReportRun, runContextReport, type ContextReportDeps, } from "./context-report-cli.js";
21
+ export { compressContent, compressionToolUsage, formatCompressionSummary, readCompressorMode, resolveCompressorMode, runRetrievalStore, summarizeCompression, summarizeToolCompression, type CompressInput, type CompressOutput, type CompressionCategory, type CompressionSummary, type CompressorMode, type ContextCompressor, type RetrievalStore, } from "./context-compressor.js";
22
+ export { HEADROOM_VERSION, createHeadroomCompressor, defaultHeadroomRunner, headroomToolDefinition, type HeadroomRunner, } from "./headroom-adapter.js";
21
23
  export { formatPlanReport, readTaskPlans, runPlanReport, type PlanReportDeps, type TaskPlanScore, } from "./plan-report-cli.js";
22
24
  export { formatAuditReport, runMemory, type MemoryDeps } from "./memory-cli.js";
23
25
  export { allocateMemoryId, auditMemory, boundLearnings, detectConflicts, DEFAULT_FREQUENT_USE, DEFAULT_LEARNINGS_BUDGET_CHARS, formatBoundedLearnings, listMemoryIds, memoryDir, memoryRecordPath, memoryStatus, parseMemoryRecord, projectLearnings, readMemoryRecord, readMemoryRecords, selectRelevantMemory, supersede, touchMemory, writeMemoryRecord, type AuditReport, type BoundedMemory, type MemoryRecord, type MemorySelectionContext, type MemoryStatus, type MemoryTrust, type Supersession, } from "./memory.js";
@@ -27,8 +29,11 @@ export { deriveProgress, type IterationObservation, type ProgressSignals, } from
27
29
  export { decide, type PolicyAction, type PolicyContext, type PolicyDecision, } from "./policy.js";
28
30
  export { checkApprovalRequired, checkCommand, checkNetworkDomain, checkWritePath, DEFAULT_POLICY, parseSafetyPolicy, readSafetyPolicy, type PolicyViolation, type PolicyViolationKind, type SafetyPolicy, } from "./safety-policy.js";
29
31
  export { TAINT_SOURCES, UNTRUSTED_WARNING, wrapUntrusted, type TaintSource, } from "./taint.js";
30
- export { findSkillCandidates, globMatch, listSkillIds, parseSkill, readSkill, readSkills, recordValidation, selectSkills, skillDir, skillExists, skillInstructionsPath, skillManifestPath, skillsDir, skillStatus, toSkillName, writeSkill, type CandidateRun, type Skill, type SkillCandidate, type SkillMatch, type SkillMatchContext, type SkillStatus, type SkillTrust, type SkillValidation, } from "./skills.js";
31
- export { formatCandidates, formatSkillsAudit, formatSkillsReport, formatWhy, runSkills, type SkillsDeps, } from "./skills-cli.js";
32
+ export { authorizeToolInvocation, parseTool, readToolConfig, readTools, selectToolsForStage, toolEnabledForStage, toolPath, toolsDir, type ToolAuthorization, type ToolConfig, type ToolDefinition, type ToolInvocation, type ToolKind, type ToolOverride, type ToolResult, type ToolSelection, } from "./tools.js";
33
+ export { auditTools, auditToolPolicyConflicts, formatToolsAudit, formatToolsList, formatToolsWhy, runTools, type ToolAuditFinding, type ToolsDeps, } from "./tools-cli.js";
34
+ export { findSkillCandidates, globMatch, listSkillIds, parseSkill, readSkill, readSkills, recordValidation, selectSkills, skillDir, skillExists, skillInstructionsPath, skillManifestPath, skillsDir, skillStatus, toSkillName, writeSkill, type CandidateRun, type Skill, type SkillCandidate, type SkillMatch, type SkillMatchContext, type ImportedSkillProvenance, type SkillStatus, type SkillTrust, type SkillValidation, } from "./skills.js";
35
+ export { addSource, applySync, auditExternal, discoverPackages, importedChecksum, lockPath, normalizePackage, parseFrontmatter, parseSource, planSync, readLock, readSources, removeSource, sourcesPath, writeLock, writeSources, type DiscoveredPackage, type ExternalAuditFinding, type ExternalSkillLock, type ExternalSkillLockEntry, type ExternalSkillSource, type ExternalSourceType, type SyncAction, type SyncPlan, type SyncPlanItem, } from "./external-skills.js";
36
+ export { formatCandidates, formatExternalAudit, formatSkillsAudit, formatSkillsReport, formatSources, formatSyncPlan, formatWhy, runSkills, type SkillsDeps, } from "./skills-cli.js";
32
37
  export { compareTrajectories, scoreTrajectory, type EvalSignals, type LabelledSignals, } from "./eval.js";
33
38
  export { PLAN_CRITERIA, detectScopeDrift, extractPlanFileMap, formatPlanDepthRubric, formatPlanRubric, scorePlanDepth, scorePlanQuality, type PlanDepthCriterion, type PlanDepthCriterionResult, type PlanDepthScore, type PlanCriterion, type PlanCriterionResult, type PlanRubricScore, type ScopeDriftResult, } from "./plan-rubric.js";
34
39
  export { buildFallbackRunReport, extractRunReport, finalizeReportText, summarizeReviewSeverity, type FinalizeReportContext, type ReviewSeveritySummary, type ScopeDriftSummary, } from "./report-finalize.js";