skein-cli 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +180 -0
- package/bin/skein.mjs +7 -0
- package/dist/adapters/aider/conv-reader.d.ts +7 -0
- package/dist/adapters/aider/conv-reader.js +203 -0
- package/dist/adapters/aider/conv-reader.js.map +1 -0
- package/dist/adapters/aider/index.d.ts +2 -0
- package/dist/adapters/aider/index.js +123 -0
- package/dist/adapters/aider/index.js.map +1 -0
- package/dist/adapters/base.d.ts +71 -0
- package/dist/adapters/base.js +38 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude-code/conv-reader.d.ts +2 -0
- package/dist/adapters/claude-code/conv-reader.js +155 -0
- package/dist/adapters/claude-code/conv-reader.js.map +1 -0
- package/dist/adapters/claude-code/index.d.ts +3 -0
- package/dist/adapters/claude-code/index.js +517 -0
- package/dist/adapters/claude-code/index.js.map +1 -0
- package/dist/adapters/claude-desktop/index.d.ts +2 -0
- package/dist/adapters/claude-desktop/index.js +95 -0
- package/dist/adapters/claude-desktop/index.js.map +1 -0
- package/dist/adapters/codex/index.d.ts +2 -0
- package/dist/adapters/codex/index.js +472 -0
- package/dist/adapters/codex/index.js.map +1 -0
- package/dist/adapters/cursor/index.d.ts +2 -0
- package/dist/adapters/cursor/index.js +255 -0
- package/dist/adapters/cursor/index.js.map +1 -0
- package/dist/adapters/opencode/conv-reader.d.ts +3 -0
- package/dist/adapters/opencode/conv-reader.js +190 -0
- package/dist/adapters/opencode/conv-reader.js.map +1 -0
- package/dist/adapters/opencode/index.d.ts +2 -0
- package/dist/adapters/opencode/index.js +349 -0
- package/dist/adapters/opencode/index.js.map +1 -0
- package/dist/adapters/registry.d.ts +4 -0
- package/dist/adapters/registry.js +26 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +54 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/conv.d.ts +2 -0
- package/dist/commands/conv.js +261 -0
- package/dist/commands/conv.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +85 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +38 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/memory.d.ts +2 -0
- package/dist/commands/memory.js +197 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.js +102 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +183 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/redact.d.ts +2 -0
- package/dist/commands/redact.js +73 -0
- package/dist/commands/redact.js.map +1 -0
- package/dist/commands/trace.d.ts +2 -0
- package/dist/commands/trace.js +181 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/view.d.ts +13 -0
- package/dist/commands/view.js +184 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.js +61 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/wrap.d.ts +2 -0
- package/dist/commands/wrap.js +131 -0
- package/dist/commands/wrap.js.map +1 -0
- package/dist/conv/chatgpt-import.d.ts +33 -0
- package/dist/conv/chatgpt-import.js +145 -0
- package/dist/conv/chatgpt-import.js.map +1 -0
- package/dist/conv/cursor.d.ts +12 -0
- package/dist/conv/cursor.js +55 -0
- package/dist/conv/cursor.js.map +1 -0
- package/dist/conv/export.d.ts +40 -0
- package/dist/conv/export.js +215 -0
- package/dist/conv/export.js.map +1 -0
- package/dist/conv/replay/aider.d.ts +24 -0
- package/dist/conv/replay/aider.js +56 -0
- package/dist/conv/replay/aider.js.map +1 -0
- package/dist/conv/replay/claude-code.d.ts +38 -0
- package/dist/conv/replay/claude-code.js +80 -0
- package/dist/conv/replay/claude-code.js.map +1 -0
- package/dist/conv/replay/context.d.ts +25 -0
- package/dist/conv/replay/context.js +63 -0
- package/dist/conv/replay/context.js.map +1 -0
- package/dist/conv/replay/index.d.ts +22 -0
- package/dist/conv/replay/index.js +84 -0
- package/dist/conv/replay/index.js.map +1 -0
- package/dist/conv/search.d.ts +67 -0
- package/dist/conv/search.js +379 -0
- package/dist/conv/search.js.map +1 -0
- package/dist/conv/sink.d.ts +26 -0
- package/dist/conv/sink.js +76 -0
- package/dist/conv/sink.js.map +1 -0
- package/dist/conv/sources/aider.d.ts +13 -0
- package/dist/conv/sources/aider.js +95 -0
- package/dist/conv/sources/aider.js.map +1 -0
- package/dist/conv/sources/claude-code.d.ts +13 -0
- package/dist/conv/sources/claude-code.js +189 -0
- package/dist/conv/sources/claude-code.js.map +1 -0
- package/dist/conv/sources/codex.d.ts +15 -0
- package/dist/conv/sources/codex.js +175 -0
- package/dist/conv/sources/codex.js.map +1 -0
- package/dist/conv/sources/opencode.d.ts +12 -0
- package/dist/conv/sources/opencode.js +92 -0
- package/dist/conv/sources/opencode.js.map +1 -0
- package/dist/conv/store.d.ts +10 -0
- package/dist/conv/store.js +75 -0
- package/dist/conv/store.js.map +1 -0
- package/dist/conv/title.d.ts +9 -0
- package/dist/conv/title.js +74 -0
- package/dist/conv/title.js.map +1 -0
- package/dist/conv/watcher.d.ts +28 -0
- package/dist/conv/watcher.js +75 -0
- package/dist/conv/watcher.js.map +1 -0
- package/dist/conv/zip.d.ts +11 -0
- package/dist/conv/zip.js +82 -0
- package/dist/conv/zip.js.map +1 -0
- package/dist/hf/client.d.ts +41 -0
- package/dist/hf/client.js +87 -0
- package/dist/hf/client.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/index.d.ts +24 -0
- package/dist/ir/index.js +23 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/profile.d.ts +55 -0
- package/dist/ir/profile.js +177 -0
- package/dist/ir/profile.js.map +1 -0
- package/dist/memory/index.d.ts +41 -0
- package/dist/memory/index.js +109 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/search.d.ts +24 -0
- package/dist/memory/search.js +114 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/sinks/claude-mem.d.ts +13 -0
- package/dist/memory/sinks/claude-mem.js +100 -0
- package/dist/memory/sinks/claude-mem.js.map +1 -0
- package/dist/memory/sinks/codex.d.ts +12 -0
- package/dist/memory/sinks/codex.js +82 -0
- package/dist/memory/sinks/codex.js.map +1 -0
- package/dist/memory/sinks/context.d.ts +21 -0
- package/dist/memory/sinks/context.js +42 -0
- package/dist/memory/sinks/context.js.map +1 -0
- package/dist/memory/sources/chatgpt.d.ts +22 -0
- package/dist/memory/sources/chatgpt.js +98 -0
- package/dist/memory/sources/chatgpt.js.map +1 -0
- package/dist/memory/sources/claude-mem.d.ts +8 -0
- package/dist/memory/sources/claude-mem.js +104 -0
- package/dist/memory/sources/claude-mem.js.map +1 -0
- package/dist/memory/sources/codex.d.ts +8 -0
- package/dist/memory/sources/codex.js +77 -0
- package/dist/memory/sources/codex.js.map +1 -0
- package/dist/memory/store.d.ts +19 -0
- package/dist/memory/store.js +82 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/proxy/http.d.ts +21 -0
- package/dist/proxy/http.js +205 -0
- package/dist/proxy/http.js.map +1 -0
- package/dist/proxy/recorder.d.ts +35 -0
- package/dist/proxy/recorder.js +221 -0
- package/dist/proxy/recorder.js.map +1 -0
- package/dist/proxy/streaming.d.ts +33 -0
- package/dist/proxy/streaming.js +185 -0
- package/dist/proxy/streaming.js.map +1 -0
- package/dist/redactor/entropy.d.ts +29 -0
- package/dist/redactor/entropy.js +98 -0
- package/dist/redactor/entropy.js.map +1 -0
- package/dist/redactor/index.d.ts +52 -0
- package/dist/redactor/index.js +152 -0
- package/dist/redactor/index.js.map +1 -0
- package/dist/redactor/ner.d.ts +53 -0
- package/dist/redactor/ner.js +97 -0
- package/dist/redactor/ner.js.map +1 -0
- package/dist/redactor/pii-patterns.d.ts +22 -0
- package/dist/redactor/pii-patterns.js +187 -0
- package/dist/redactor/pii-patterns.js.map +1 -0
- package/dist/redactor/secret-patterns.d.ts +27 -0
- package/dist/redactor/secret-patterns.js +475 -0
- package/dist/redactor/secret-patterns.js.map +1 -0
- package/dist/schema/conv.d.ts +698 -0
- package/dist/schema/conv.js +85 -0
- package/dist/schema/conv.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/manifest.d.ts +1531 -0
- package/dist/schema/manifest.js +179 -0
- package/dist/schema/manifest.js.map +1 -0
- package/dist/schema/memory.d.ts +107 -0
- package/dist/schema/memory.js +45 -0
- package/dist/schema/memory.js.map +1 -0
- package/dist/schema/trace.d.ts +164 -0
- package/dist/schema/trace.js +89 -0
- package/dist/schema/trace.js.map +1 -0
- package/dist/trace/consent.d.ts +30 -0
- package/dist/trace/consent.js +60 -0
- package/dist/trace/consent.js.map +1 -0
- package/dist/trace/extract.d.ts +22 -0
- package/dist/trace/extract.js +168 -0
- package/dist/trace/extract.js.map +1 -0
- package/dist/trace/ml-pii.d.ts +33 -0
- package/dist/trace/ml-pii.js +35 -0
- package/dist/trace/ml-pii.js.map +1 -0
- package/dist/trace/push.d.ts +59 -0
- package/dist/trace/push.js +141 -0
- package/dist/trace/push.js.map +1 -0
- package/dist/trace/serialize.d.ts +23 -0
- package/dist/trace/serialize.js +67 -0
- package/dist/trace/serialize.js.map +1 -0
- package/dist/ui/banner.d.ts +2 -0
- package/dist/ui/banner.js +17 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/box.d.ts +4 -0
- package/dist/ui/box.js +38 -0
- package/dist/ui/box.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/spinner.d.ts +10 -0
- package/dist/ui/spinner.js +44 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/table.d.ts +9 -0
- package/dist/ui/table.js +55 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/util/frontmatter.d.ts +6 -0
- package/dist/util/frontmatter.js +20 -0
- package/dist/util/frontmatter.js.map +1 -0
- package/dist/util/fs.d.ts +5 -0
- package/dist/util/fs.js +41 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/ids.d.ts +3 -0
- package/dist/util/ids.js +16 -0
- package/dist/util/ids.js.map +1 -0
- package/dist/util/log.d.ts +13 -0
- package/dist/util/log.js +33 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/paths.d.ts +18 -0
- package/dist/util/paths.js +36 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +32 -0
- package/dist/version.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { CursorStore } from '../cursor.js';
|
|
3
|
+
import { opencodeConvReader, opencodeDbPath } from '../../adapters/opencode/conv-reader.js';
|
|
4
|
+
/**
|
|
5
|
+
* Live tee source for OpenCode.
|
|
6
|
+
*
|
|
7
|
+
* OpenCode persists sessions in a SQLite database at
|
|
8
|
+
* `~/.local/share/opencode/opencode.db`. There's no rowid-style append
|
|
9
|
+
* marker we can rely on (sessions can be updated in place), so the
|
|
10
|
+
* source instead remembers which session ids have already been emitted
|
|
11
|
+
* to disk and re-emits only what's new on each tick.
|
|
12
|
+
*/
|
|
13
|
+
const POLL_INTERVAL_MS = 2_000;
|
|
14
|
+
export function startOpencodeWatcher(sink, opts) {
|
|
15
|
+
const interval = opts.intervalMs ?? POLL_INTERVAL_MS;
|
|
16
|
+
const prefix = opts.cursorPrefix ?? 'opencode:';
|
|
17
|
+
const cursors = new CursorStore();
|
|
18
|
+
const dbPath = opencodeDbPath(opts.homeDir);
|
|
19
|
+
let timer;
|
|
20
|
+
let running = false;
|
|
21
|
+
let totalEvents = 0;
|
|
22
|
+
const emittedSessions = new Set();
|
|
23
|
+
return {
|
|
24
|
+
async start() {
|
|
25
|
+
if (running)
|
|
26
|
+
return;
|
|
27
|
+
running = true;
|
|
28
|
+
await cursors.load();
|
|
29
|
+
const tick = async () => {
|
|
30
|
+
if (!running)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
totalEvents += await poll(opts.homeDir, dbPath, sink, cursors, prefix, emittedSessions);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
process.emit('warning', err);
|
|
37
|
+
}
|
|
38
|
+
if (running)
|
|
39
|
+
timer = setTimeout(tick, interval);
|
|
40
|
+
};
|
|
41
|
+
await tick();
|
|
42
|
+
},
|
|
43
|
+
async stop() {
|
|
44
|
+
running = false;
|
|
45
|
+
if (timer)
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
timer = undefined;
|
|
48
|
+
},
|
|
49
|
+
tally() {
|
|
50
|
+
return totalEvents;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function poll(homeDir, dbPath, sink, cursors, prefix, emittedSessions) {
|
|
55
|
+
try {
|
|
56
|
+
await fs.access(dbPath);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
let total = 0;
|
|
62
|
+
for await (const summary of opencodeConvReader.listSessions({ homeDir })) {
|
|
63
|
+
const key = `${prefix}${summary.id}`;
|
|
64
|
+
if (cursors.get(key) > 0 || emittedSessions.has(summary.id))
|
|
65
|
+
continue;
|
|
66
|
+
let seq = 0;
|
|
67
|
+
let opened = false;
|
|
68
|
+
for await (const event of opencodeConvReader.readSession(summary.id, { homeDir })) {
|
|
69
|
+
if (event.type === 'session.start') {
|
|
70
|
+
await sink.openSession(event.id, {
|
|
71
|
+
tool: event.tool,
|
|
72
|
+
...(event.toolVersion ? { toolVersion: event.toolVersion } : {}),
|
|
73
|
+
...(event.model ? { model: event.model } : {}),
|
|
74
|
+
...(event.project ? { project: event.project } : {}),
|
|
75
|
+
...(event.title ? { title: event.title } : {}),
|
|
76
|
+
startedAt: event.ts,
|
|
77
|
+
});
|
|
78
|
+
opened = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (event.type === 'message' && opened) {
|
|
82
|
+
await sink.write(event.session, event);
|
|
83
|
+
seq += 1;
|
|
84
|
+
total += 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
emittedSessions.add(summary.id);
|
|
88
|
+
await cursors.set(key, Math.max(seq, 1));
|
|
89
|
+
}
|
|
90
|
+
return total;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/conv/sources/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConvEvent, ConvSessionSummary } from '../schema/conv.js';
|
|
2
|
+
export interface ConvStorePaths {
|
|
3
|
+
root: string;
|
|
4
|
+
sessions: string;
|
|
5
|
+
attachments: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function storePaths(): ConvStorePaths;
|
|
8
|
+
export declare function ensureStore(): Promise<ConvStorePaths>;
|
|
9
|
+
export declare function writeSession(summary: ConvSessionSummary, events: AsyncIterable<ConvEvent>): Promise<string>;
|
|
10
|
+
export declare function listStoredSessions(): Promise<string[]>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { ensureDir } from '../util/fs.js';
|
|
5
|
+
import { getToolPaths, SKEIN_SUBDIRS } from '../util/paths.js';
|
|
6
|
+
export function storePaths() {
|
|
7
|
+
const paths = getToolPaths();
|
|
8
|
+
return {
|
|
9
|
+
root: join(paths.skeinDir, SKEIN_SUBDIRS.conv),
|
|
10
|
+
sessions: join(paths.skeinDir, SKEIN_SUBDIRS.convSessions),
|
|
11
|
+
attachments: join(paths.skeinDir, SKEIN_SUBDIRS.convAttachments),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function ensureStore() {
|
|
15
|
+
const paths = storePaths();
|
|
16
|
+
await ensureDir(paths.sessions);
|
|
17
|
+
await ensureDir(paths.attachments);
|
|
18
|
+
return paths;
|
|
19
|
+
}
|
|
20
|
+
export async function writeSession(summary, events) {
|
|
21
|
+
const paths = await ensureStore();
|
|
22
|
+
const yyyymm = monthSlug(summary.startedAt);
|
|
23
|
+
const dir = join(paths.sessions, yyyymm);
|
|
24
|
+
await ensureDir(dir);
|
|
25
|
+
const filePath = join(dir, `${sanitize(summary.id)}.jsonl`);
|
|
26
|
+
const stream = createWriteStream(filePath, { flags: 'w' });
|
|
27
|
+
try {
|
|
28
|
+
for await (const event of events) {
|
|
29
|
+
stream.write(`${JSON.stringify(event)}\n`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
await new Promise(resolve => stream.end(resolve));
|
|
34
|
+
}
|
|
35
|
+
return filePath;
|
|
36
|
+
}
|
|
37
|
+
function monthSlug(iso) {
|
|
38
|
+
if (!iso)
|
|
39
|
+
return 'unknown';
|
|
40
|
+
const d = new Date(iso);
|
|
41
|
+
if (Number.isNaN(d.getTime()))
|
|
42
|
+
return 'unknown';
|
|
43
|
+
return `${d.getUTCFullYear()}/${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
|
|
44
|
+
}
|
|
45
|
+
function sanitize(id) {
|
|
46
|
+
return id.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
47
|
+
}
|
|
48
|
+
export async function listStoredSessions() {
|
|
49
|
+
const paths = storePaths();
|
|
50
|
+
if (!(await pathExists(paths.sessions)))
|
|
51
|
+
return [];
|
|
52
|
+
const out = [];
|
|
53
|
+
await walkSessions(paths.sessions, out);
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
async function walkSessions(dir, acc) {
|
|
57
|
+
const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
const path = join(dir, entry.name);
|
|
60
|
+
if (entry.isDirectory())
|
|
61
|
+
await walkSessions(path, acc);
|
|
62
|
+
else if (entry.name.endsWith('.jsonl'))
|
|
63
|
+
acc.push(path);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function pathExists(path) {
|
|
67
|
+
try {
|
|
68
|
+
await fs.access(path);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/conv/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a session JSONL and return the best available title.
|
|
3
|
+
*
|
|
4
|
+
* Priority:
|
|
5
|
+
* 1. Explicit title on session.start
|
|
6
|
+
* 2. First user message text trimmed to MAX_LEN
|
|
7
|
+
* 3. Tool + model fallback
|
|
8
|
+
*/
|
|
9
|
+
export declare function deriveTitle(path: string): Promise<string | undefined>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
const MAX_LEN = 80;
|
|
4
|
+
/**
|
|
5
|
+
* Read a session JSONL and return the best available title.
|
|
6
|
+
*
|
|
7
|
+
* Priority:
|
|
8
|
+
* 1. Explicit title on session.start
|
|
9
|
+
* 2. First user message text trimmed to MAX_LEN
|
|
10
|
+
* 3. Tool + model fallback
|
|
11
|
+
*/
|
|
12
|
+
export async function deriveTitle(path) {
|
|
13
|
+
let explicitTitle;
|
|
14
|
+
let firstUserText;
|
|
15
|
+
let tool;
|
|
16
|
+
let model;
|
|
17
|
+
for await (const line of readLines(path)) {
|
|
18
|
+
const event = safeJson(line);
|
|
19
|
+
if (!event)
|
|
20
|
+
continue;
|
|
21
|
+
if (event.type === 'session.start') {
|
|
22
|
+
if (event.title)
|
|
23
|
+
explicitTitle = event.title;
|
|
24
|
+
tool = event.tool;
|
|
25
|
+
if (event.model)
|
|
26
|
+
model = event.model;
|
|
27
|
+
if (explicitTitle)
|
|
28
|
+
return explicitTitle;
|
|
29
|
+
}
|
|
30
|
+
if (event.type === 'message' && event.role === 'user' && !firstUserText) {
|
|
31
|
+
for (const block of event.content) {
|
|
32
|
+
if (block.type === 'text' && block.text.trim().length > 0) {
|
|
33
|
+
firstUserText = sanitize(block.text);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (firstUserText)
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (explicitTitle)
|
|
42
|
+
return explicitTitle;
|
|
43
|
+
if (firstUserText)
|
|
44
|
+
return firstUserText;
|
|
45
|
+
if (tool && model)
|
|
46
|
+
return `${tool} · ${model}`;
|
|
47
|
+
return tool;
|
|
48
|
+
}
|
|
49
|
+
function sanitize(raw) {
|
|
50
|
+
const collapsed = raw
|
|
51
|
+
.replace(/<[^>]+>/g, '')
|
|
52
|
+
.replace(/\s+/g, ' ')
|
|
53
|
+
.trim();
|
|
54
|
+
if (collapsed.length <= MAX_LEN)
|
|
55
|
+
return collapsed;
|
|
56
|
+
return `${collapsed.slice(0, MAX_LEN - 1)}…`;
|
|
57
|
+
}
|
|
58
|
+
async function* readLines(path) {
|
|
59
|
+
const stream = createReadStream(path, { encoding: 'utf8' });
|
|
60
|
+
const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
61
|
+
for await (const line of rl) {
|
|
62
|
+
if (line.trim())
|
|
63
|
+
yield line;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function safeJson(raw) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(raw);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.js","sourceRoot":"","sources":["../../src/conv/title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAG/C,MAAM,OAAO,GAAG,EAAE,CAAA;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,IAAI,aAAiC,CAAA;IACrC,IAAI,aAAiC,CAAA;IACrC,IAAI,IAAwB,CAAA;IAC5B,IAAI,KAAyB,CAAA;IAE7B,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,QAAQ,CAAY,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,KAAK;gBAAE,aAAa,GAAG,KAAK,CAAC,KAAK,CAAA;YAC5C,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;YACjB,IAAI,KAAK,CAAC,KAAK;gBAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;YACpC,IAAI,aAAa;gBAAE,OAAO,aAAa,CAAA;QACzC,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YACxE,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1D,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;oBACpC,MAAK;gBACP,CAAC;YACH,CAAC;YACD,IAAI,aAAa;gBAAE,MAAK;QAC1B,CAAC;IACH,CAAC;IACD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAA;IACvC,IAAI,aAAa;QAAE,OAAO,aAAa,CAAA;IACvC,IAAI,IAAI,IAAI,KAAK;QAAE,OAAO,GAAG,IAAI,MAAM,KAAK,EAAE,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,MAAM,SAAS,GAAG,GAAG;SAClB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;IACT,IAAI,SAAS,CAAC,MAAM,IAAI,OAAO;QAAE,OAAO,SAAS,CAAA;IACjD,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,CAAA;AAC9C,CAAC;AAED,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,IAAY;IACpC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;IAC3D,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAA;IAClF,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,CAAA;IAC7B,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAI,GAAW;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAA;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type SourceName = 'claude-code' | 'codex' | 'opencode' | 'aider';
|
|
2
|
+
export interface WatcherOptions {
|
|
3
|
+
homeDir: string;
|
|
4
|
+
sources?: SourceName[];
|
|
5
|
+
intervalMs?: number;
|
|
6
|
+
/** Project path for Aider (defaults to cwd). */
|
|
7
|
+
projectPath?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface WatcherTally {
|
|
10
|
+
source: SourceName;
|
|
11
|
+
events: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Composite watcher that fans out to every requested source and aggregates
|
|
15
|
+
* the per-source event tallies. Each source writes to the shared sink so
|
|
16
|
+
* every captured event ends up in the same `~/.skein/conv/sessions/` layout.
|
|
17
|
+
*/
|
|
18
|
+
export declare class Watcher {
|
|
19
|
+
private readonly opts;
|
|
20
|
+
private readonly sink;
|
|
21
|
+
private readonly sources;
|
|
22
|
+
private started;
|
|
23
|
+
constructor(opts: WatcherOptions);
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
stop(): Promise<void>;
|
|
26
|
+
tallies(): WatcherTally[];
|
|
27
|
+
private buildSource;
|
|
28
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { JsonlSink } from './sink.js';
|
|
2
|
+
import { startClaudeCodeWatcher } from './sources/claude-code.js';
|
|
3
|
+
import { startCodexWatcher } from './sources/codex.js';
|
|
4
|
+
import { startOpencodeWatcher } from './sources/opencode.js';
|
|
5
|
+
import { startAiderWatcher } from './sources/aider.js';
|
|
6
|
+
const ALL_SOURCES = ['claude-code', 'codex', 'opencode', 'aider'];
|
|
7
|
+
/**
|
|
8
|
+
* Composite watcher that fans out to every requested source and aggregates
|
|
9
|
+
* the per-source event tallies. Each source writes to the shared sink so
|
|
10
|
+
* every captured event ends up in the same `~/.skein/conv/sessions/` layout.
|
|
11
|
+
*/
|
|
12
|
+
export class Watcher {
|
|
13
|
+
opts;
|
|
14
|
+
sink = new JsonlSink();
|
|
15
|
+
sources = new Map();
|
|
16
|
+
started = false;
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
}
|
|
20
|
+
async start() {
|
|
21
|
+
if (this.started)
|
|
22
|
+
return;
|
|
23
|
+
this.started = true;
|
|
24
|
+
const requested = this.opts.sources ?? ALL_SOURCES;
|
|
25
|
+
for (const name of requested) {
|
|
26
|
+
const source = this.buildSource(name);
|
|
27
|
+
if (source)
|
|
28
|
+
this.sources.set(name, source);
|
|
29
|
+
}
|
|
30
|
+
await Promise.all([...this.sources.values()].map(s => s.start()));
|
|
31
|
+
}
|
|
32
|
+
async stop() {
|
|
33
|
+
if (!this.started)
|
|
34
|
+
return;
|
|
35
|
+
this.started = false;
|
|
36
|
+
await Promise.all([...this.sources.values()].map(s => s.stop()));
|
|
37
|
+
await this.sink.closeAll();
|
|
38
|
+
}
|
|
39
|
+
tallies() {
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const [name, source] of this.sources) {
|
|
42
|
+
out.push({ source: name, events: source.tally() });
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
buildSource(name) {
|
|
47
|
+
if (name === 'claude-code') {
|
|
48
|
+
return startClaudeCodeWatcher(this.sink, {
|
|
49
|
+
homeDir: this.opts.homeDir,
|
|
50
|
+
...(this.opts.intervalMs ? { intervalMs: this.opts.intervalMs } : {}),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (name === 'codex') {
|
|
54
|
+
return startCodexWatcher(this.sink, {
|
|
55
|
+
homeDir: this.opts.homeDir,
|
|
56
|
+
...(this.opts.intervalMs ? { intervalMs: this.opts.intervalMs } : {}),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (name === 'opencode') {
|
|
60
|
+
return startOpencodeWatcher(this.sink, {
|
|
61
|
+
homeDir: this.opts.homeDir,
|
|
62
|
+
...(this.opts.intervalMs ? { intervalMs: this.opts.intervalMs } : {}),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (name === 'aider') {
|
|
66
|
+
return startAiderWatcher(this.sink, {
|
|
67
|
+
homeDir: this.opts.homeDir,
|
|
68
|
+
...(this.opts.projectPath ? { projectPath: this.opts.projectPath } : {}),
|
|
69
|
+
...(this.opts.intervalMs ? { intervalMs: this.opts.intervalMs } : {}),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/conv/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ZipEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
method: number;
|
|
4
|
+
uncompressedSize: number;
|
|
5
|
+
compressedSize: number;
|
|
6
|
+
body: Buffer;
|
|
7
|
+
}
|
|
8
|
+
export declare function readZipFile(path: string): Promise<ZipEntry[]>;
|
|
9
|
+
export declare function parseZip(buffer: Buffer): ZipEntry[];
|
|
10
|
+
export declare function findEntry(entries: ZipEntry[], name: string): ZipEntry | undefined;
|
|
11
|
+
export declare function findEntriesByExt(entries: ZipEntry[], ext: string): ZipEntry[];
|
package/dist/conv/zip.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { inflateRawSync } from 'node:zlib';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal PKZIP central-directory reader.
|
|
5
|
+
*
|
|
6
|
+
* Supports STORED (method 0) and DEFLATE (method 8) — the two methods
|
|
7
|
+
* used by every real-world ZIP file. No streaming, no encryption, no
|
|
8
|
+
* ZIP64. The largest ChatGPT export the author has seen is ~50 MB; we
|
|
9
|
+
* read into memory, which is fine for the v0.4 acceptance target.
|
|
10
|
+
*
|
|
11
|
+
* Reference: PKWARE APPNOTE.TXT (Application Note) §4.3.
|
|
12
|
+
*/
|
|
13
|
+
const LFH_SIGNATURE = 0x04034b50; // 'PK\x03\x04'
|
|
14
|
+
const CDH_SIGNATURE = 0x02014b50; // 'PK\x01\x02'
|
|
15
|
+
const EOCD_SIGNATURE = 0x06054b50; // 'PK\x05\x06'
|
|
16
|
+
export async function readZipFile(path) {
|
|
17
|
+
const buffer = await fs.readFile(path);
|
|
18
|
+
return parseZip(buffer);
|
|
19
|
+
}
|
|
20
|
+
export function parseZip(buffer) {
|
|
21
|
+
const eocdOffset = findEocd(buffer);
|
|
22
|
+
if (eocdOffset < 0)
|
|
23
|
+
throw new Error('zip: end-of-central-directory record not found');
|
|
24
|
+
const totalEntries = buffer.readUInt16LE(eocdOffset + 10);
|
|
25
|
+
const centralDirOffset = buffer.readUInt32LE(eocdOffset + 16);
|
|
26
|
+
if (centralDirOffset === 0xffffffff) {
|
|
27
|
+
throw new Error('zip: ZIP64 archive — not supported in skein v0.4');
|
|
28
|
+
}
|
|
29
|
+
const entries = [];
|
|
30
|
+
let cursor = centralDirOffset;
|
|
31
|
+
for (let i = 0; i < totalEntries; i++) {
|
|
32
|
+
if (buffer.readUInt32LE(cursor) !== CDH_SIGNATURE) {
|
|
33
|
+
throw new Error(`zip: bad central directory entry at offset ${cursor}`);
|
|
34
|
+
}
|
|
35
|
+
const method = buffer.readUInt16LE(cursor + 10);
|
|
36
|
+
const compressedSize = buffer.readUInt32LE(cursor + 20);
|
|
37
|
+
const uncompressedSize = buffer.readUInt32LE(cursor + 24);
|
|
38
|
+
const nameLen = buffer.readUInt16LE(cursor + 28);
|
|
39
|
+
const extraLen = buffer.readUInt16LE(cursor + 30);
|
|
40
|
+
const commentLen = buffer.readUInt16LE(cursor + 32);
|
|
41
|
+
const localHeaderOffset = buffer.readUInt32LE(cursor + 42);
|
|
42
|
+
const name = buffer.toString('utf8', cursor + 46, cursor + 46 + nameLen);
|
|
43
|
+
cursor += 46 + nameLen + extraLen + commentLen;
|
|
44
|
+
if (compressedSize === 0xffffffff || uncompressedSize === 0xffffffff) {
|
|
45
|
+
throw new Error(`zip: ZIP64-sized entry "${name}" — not supported in skein v0.4`);
|
|
46
|
+
}
|
|
47
|
+
if (buffer.readUInt32LE(localHeaderOffset) !== LFH_SIGNATURE) {
|
|
48
|
+
throw new Error(`zip: bad local file header for "${name}"`);
|
|
49
|
+
}
|
|
50
|
+
const lfhNameLen = buffer.readUInt16LE(localHeaderOffset + 26);
|
|
51
|
+
const lfhExtraLen = buffer.readUInt16LE(localHeaderOffset + 28);
|
|
52
|
+
const dataStart = localHeaderOffset + 30 + lfhNameLen + lfhExtraLen;
|
|
53
|
+
const dataEnd = dataStart + compressedSize;
|
|
54
|
+
const compressed = buffer.subarray(dataStart, dataEnd);
|
|
55
|
+
const body = method === 0 ? compressed : method === 8 ? inflateRawSync(compressed) : panic(method, name);
|
|
56
|
+
entries.push({ name, method, uncompressedSize, compressedSize, body: Buffer.from(body) });
|
|
57
|
+
}
|
|
58
|
+
return entries;
|
|
59
|
+
}
|
|
60
|
+
function findEocd(buffer) {
|
|
61
|
+
// EOCD has a 22-byte fixed prefix + a variable-length comment up to 65,535
|
|
62
|
+
// bytes. We scan backwards from the end of the buffer to find the
|
|
63
|
+
// signature, capping the search at 65,557 bytes.
|
|
64
|
+
const maxScan = Math.min(buffer.length, 65_557);
|
|
65
|
+
for (let i = buffer.length - 22; i >= buffer.length - maxScan; i--) {
|
|
66
|
+
if (i < 0)
|
|
67
|
+
break;
|
|
68
|
+
if (buffer.readUInt32LE(i) === EOCD_SIGNATURE)
|
|
69
|
+
return i;
|
|
70
|
+
}
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
function panic(method, name) {
|
|
74
|
+
throw new Error(`zip: unsupported compression method ${method} for entry "${name}"`);
|
|
75
|
+
}
|
|
76
|
+
export function findEntry(entries, name) {
|
|
77
|
+
return entries.find(e => e.name === name || e.name.endsWith(`/${name}`));
|
|
78
|
+
}
|
|
79
|
+
export function findEntriesByExt(entries, ext) {
|
|
80
|
+
return entries.filter(e => e.name.endsWith(ext));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=zip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/conv/zip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
export interface HfFileOp {
|
|
3
|
+
path: string;
|
|
4
|
+
content: Buffer;
|
|
5
|
+
}
|
|
6
|
+
export interface CommitRequest {
|
|
7
|
+
repoId: string;
|
|
8
|
+
branch?: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
files: HfFileOp[];
|
|
12
|
+
}
|
|
13
|
+
export interface CreateRepoRequest {
|
|
14
|
+
name: string;
|
|
15
|
+
organization?: string;
|
|
16
|
+
private?: boolean;
|
|
17
|
+
type?: 'dataset' | 'model' | 'space';
|
|
18
|
+
}
|
|
19
|
+
export declare class HfClient {
|
|
20
|
+
private readonly endpoint;
|
|
21
|
+
private readonly token;
|
|
22
|
+
constructor(token: string, endpoint?: string);
|
|
23
|
+
/**
|
|
24
|
+
* Create a dataset repo. Returns true if newly created, false if it already
|
|
25
|
+
* exists (HTTP 409). Re-throws other errors.
|
|
26
|
+
*/
|
|
27
|
+
ensureDataset(req: CreateRepoRequest): Promise<{
|
|
28
|
+
created: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Commit a batch of files to a dataset via the NDJSON commit API.
|
|
32
|
+
* Files <10MB are sent inline as base64; anything larger throws and asks
|
|
33
|
+
* the caller to chunk further or use LFS (not yet implemented in Skein v0.2).
|
|
34
|
+
*/
|
|
35
|
+
commitFiles(req: CommitRequest): Promise<void>;
|
|
36
|
+
whoami(): Promise<{
|
|
37
|
+
name: string;
|
|
38
|
+
type: string;
|
|
39
|
+
} | undefined>;
|
|
40
|
+
private authHeaders;
|
|
41
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export class HfClient {
|
|
2
|
+
endpoint;
|
|
3
|
+
token;
|
|
4
|
+
constructor(token, endpoint = 'https://huggingface.co') {
|
|
5
|
+
if (!token)
|
|
6
|
+
throw new Error('HfClient: token is required');
|
|
7
|
+
this.endpoint = endpoint.replace(/\/+$/, '');
|
|
8
|
+
this.token = token;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a dataset repo. Returns true if newly created, false if it already
|
|
12
|
+
* exists (HTTP 409). Re-throws other errors.
|
|
13
|
+
*/
|
|
14
|
+
async ensureDataset(req) {
|
|
15
|
+
const res = await fetch(`${this.endpoint}/api/repos/create`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: this.authHeaders('application/json'),
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
name: req.name,
|
|
20
|
+
...(req.organization ? { organization: req.organization } : {}),
|
|
21
|
+
type: req.type ?? 'dataset',
|
|
22
|
+
private: req.private ?? false,
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
if (res.ok)
|
|
26
|
+
return { created: true };
|
|
27
|
+
if (res.status === 409)
|
|
28
|
+
return { created: false };
|
|
29
|
+
throw new Error(await formatError('create repo', res));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Commit a batch of files to a dataset via the NDJSON commit API.
|
|
33
|
+
* Files <10MB are sent inline as base64; anything larger throws and asks
|
|
34
|
+
* the caller to chunk further or use LFS (not yet implemented in Skein v0.2).
|
|
35
|
+
*/
|
|
36
|
+
async commitFiles(req) {
|
|
37
|
+
const branch = req.branch ?? 'main';
|
|
38
|
+
const url = `${this.endpoint}/api/datasets/${req.repoId}/commit/${encodeURIComponent(branch)}`;
|
|
39
|
+
const lines = [];
|
|
40
|
+
lines.push(JSON.stringify({
|
|
41
|
+
key: 'header',
|
|
42
|
+
value: {
|
|
43
|
+
summary: req.summary,
|
|
44
|
+
...(req.description ? { description: req.description } : {}),
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
for (const file of req.files) {
|
|
48
|
+
if (file.content.byteLength > 10 * 1024 * 1024) {
|
|
49
|
+
throw new Error(`HfClient: file ${file.path} is ${file.content.byteLength} bytes — LFS upload is not yet supported in Skein v0.2 (cap is 10 MB).`);
|
|
50
|
+
}
|
|
51
|
+
lines.push(JSON.stringify({
|
|
52
|
+
key: 'file',
|
|
53
|
+
value: {
|
|
54
|
+
path: file.path,
|
|
55
|
+
content: file.content.toString('base64'),
|
|
56
|
+
encoding: 'base64',
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
const res = await fetch(url, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: this.authHeaders('application/x-ndjson'),
|
|
63
|
+
body: `${lines.join('\n')}\n`,
|
|
64
|
+
});
|
|
65
|
+
if (!res.ok)
|
|
66
|
+
throw new Error(await formatError('commit files', res));
|
|
67
|
+
}
|
|
68
|
+
async whoami() {
|
|
69
|
+
const res = await fetch(`${this.endpoint}/api/whoami-v2`, {
|
|
70
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
71
|
+
});
|
|
72
|
+
if (!res.ok)
|
|
73
|
+
return undefined;
|
|
74
|
+
return (await res.json());
|
|
75
|
+
}
|
|
76
|
+
authHeaders(contentType) {
|
|
77
|
+
return {
|
|
78
|
+
Authorization: `Bearer ${this.token}`,
|
|
79
|
+
'Content-Type': contentType,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function formatError(label, res) {
|
|
84
|
+
const text = await res.text().catch(() => '<no body>');
|
|
85
|
+
return `HfClient ${label}: HTTP ${res.status} ${res.statusText} — ${text.slice(0, 500)}`;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/hf/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './ir/index.js';
|
|
2
|
+
export * from './adapters/base.js';
|
|
3
|
+
export { ADAPTERS, getAdapter, getAdapterOrThrow } from './adapters/registry.js';
|
|
4
|
+
export { redactText, hasSecret } from './redactor/index.js';
|
|
5
|
+
export { VERSION } from './version.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
|