ainize 0.1.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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/dist/bin.d.ts +10 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +711 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/client.d.ts +38 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +164 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/commands/auth.d.ts +30 -0
  12. package/dist/commands/auth.d.ts.map +1 -0
  13. package/dist/commands/auth.js +216 -0
  14. package/dist/commands/auth.js.map +1 -0
  15. package/dist/commands/branch.d.ts +326 -0
  16. package/dist/commands/branch.d.ts.map +1 -0
  17. package/dist/commands/branch.js +467 -0
  18. package/dist/commands/branch.js.map +1 -0
  19. package/dist/commands/chain.d.ts +43 -0
  20. package/dist/commands/chain.d.ts.map +1 -0
  21. package/dist/commands/chain.js +224 -0
  22. package/dist/commands/chain.js.map +1 -0
  23. package/dist/commands/chat.d.ts +157 -0
  24. package/dist/commands/chat.d.ts.map +1 -0
  25. package/dist/commands/chat.js +395 -0
  26. package/dist/commands/chat.js.map +1 -0
  27. package/dist/commands/dataset.d.ts +51 -0
  28. package/dist/commands/dataset.d.ts.map +1 -0
  29. package/dist/commands/dataset.js +157 -0
  30. package/dist/commands/dataset.js.map +1 -0
  31. package/dist/commands/drive.d.ts +32 -0
  32. package/dist/commands/drive.d.ts.map +1 -0
  33. package/dist/commands/drive.js +68 -0
  34. package/dist/commands/drive.js.map +1 -0
  35. package/dist/commands/huggingface-dataset.d.ts +63 -0
  36. package/dist/commands/huggingface-dataset.d.ts.map +1 -0
  37. package/dist/commands/huggingface-dataset.js +254 -0
  38. package/dist/commands/huggingface-dataset.js.map +1 -0
  39. package/dist/commands/init.d.ts +107 -0
  40. package/dist/commands/init.d.ts.map +1 -0
  41. package/dist/commands/init.js +538 -0
  42. package/dist/commands/init.js.map +1 -0
  43. package/dist/commands/ledger.d.ts +43 -0
  44. package/dist/commands/ledger.d.ts.map +1 -0
  45. package/dist/commands/ledger.js +125 -0
  46. package/dist/commands/ledger.js.map +1 -0
  47. package/dist/commands/node.d.ts +250 -0
  48. package/dist/commands/node.d.ts.map +1 -0
  49. package/dist/commands/node.js +651 -0
  50. package/dist/commands/node.js.map +1 -0
  51. package/dist/commands/patch.d.ts +852 -0
  52. package/dist/commands/patch.d.ts.map +1 -0
  53. package/dist/commands/patch.js +1527 -0
  54. package/dist/commands/patch.js.map +1 -0
  55. package/dist/commands/peers.d.ts +86 -0
  56. package/dist/commands/peers.d.ts.map +1 -0
  57. package/dist/commands/peers.js +143 -0
  58. package/dist/commands/peers.js.map +1 -0
  59. package/dist/commands/teach-dataset.d.ts +381 -0
  60. package/dist/commands/teach-dataset.d.ts.map +1 -0
  61. package/dist/commands/teach-dataset.js +780 -0
  62. package/dist/commands/teach-dataset.js.map +1 -0
  63. package/dist/commands/teach.d.ts +351 -0
  64. package/dist/commands/teach.d.ts.map +1 -0
  65. package/dist/commands/teach.js +435 -0
  66. package/dist/commands/teach.js.map +1 -0
  67. package/dist/context.d.ts +55 -0
  68. package/dist/context.d.ts.map +1 -0
  69. package/dist/context.js +102 -0
  70. package/dist/context.js.map +1 -0
  71. package/dist/ens.d.ts +50 -0
  72. package/dist/ens.d.ts.map +1 -0
  73. package/dist/ens.js +155 -0
  74. package/dist/ens.js.map +1 -0
  75. package/dist/help.d.ts +57 -0
  76. package/dist/help.d.ts.map +1 -0
  77. package/dist/help.js +227 -0
  78. package/dist/help.js.map +1 -0
  79. package/dist/index.d.ts +15 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +15 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/output.d.ts +104 -0
  84. package/dist/output.d.ts.map +1 -0
  85. package/dist/output.js +383 -0
  86. package/dist/output.js.map +1 -0
  87. package/dist/pid.d.ts +5 -0
  88. package/dist/pid.d.ts.map +1 -0
  89. package/dist/pid.js +25 -0
  90. package/dist/pid.js.map +1 -0
  91. package/dist/quiet.d.ts +2 -0
  92. package/dist/quiet.d.ts.map +1 -0
  93. package/dist/quiet.js +12 -0
  94. package/dist/quiet.js.map +1 -0
  95. package/package.json +55 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * `ainize dataset get <patch-id|sha>` — the TRAINING SET behind a published knowledge (lineage design §13, §12.3).
3
+ *
4
+ * Different from `ainize teach dataset get <id>`, which is one of MY datasets on this node: this asks a knowledge
5
+ * for the questions it was taught from, under the access level its creator chose (§6.1):
6
+ *
7
+ * public anyone may download and build on them
8
+ * derivative only people building on this knowledge — the CLI posts a signed derive intent and fetches with the
9
+ * token it gets back, which is also what the creator's "built on N times" counter is made of
10
+ * private nobody: the refusal says so in plain words and exits 3
11
+ *
12
+ * ainize dataset get krx-all-2761 # what it is: questions, licence, access, where it came from
13
+ * ainize dataset get krx-all-2761 -o questions.jsonl # the exact canonical bytes (re-uploadable as my own dataset)
14
+ * ainize dataset get krx-all-2761 --manifest # row origin, benchmark hash, PII scan, declaration
15
+ */
16
+ import { createHash } from 'node:crypto';
17
+ import { writeFileSync } from 'node:fs';
18
+ import { resolve } from 'node:path';
19
+ import { signMessage } from '@ainize/core';
20
+ import { CliError, PROG } from '../context.js';
21
+ import { c, emit, fmtBytes, kv, shortHash, warn } from '../output.js';
22
+ import { TeachSession } from './teach-dataset.js';
23
+ const sha256 = (b) => createHash('sha256').update(b).digest('hex');
24
+ const SHA_RE = /^[0-9a-f]{64}$/i;
25
+ /** A refusal a person can act on: the node's reason, plus what to do about it. Exit 3, like a missing login. */
26
+ function refusal(e) {
27
+ const err = e;
28
+ const msg = String(err?.message ?? e);
29
+ if (/^dataset_private/.test(msg))
30
+ throw new CliError(`${msg}\nOnly the verification questions on the record are public. Ask the creator, or build on a knowledge whose training set is shared.`, 3, err.details);
31
+ if (/^dataset_derivative_only/.test(msg))
32
+ throw new CliError(`${msg}\nSign the request with a teaching key (this CLI does) — if it still refuses, the creator's node no longer serves it.`, 3, err.details);
33
+ if (/^dataset_unavailable/.test(msg))
34
+ throw new CliError(`${msg}\nNo node here holds the bytes. Try again against a node that does: \`${PROG} dataset get <id> --node <url>\`.`, 3, err.details);
35
+ throw e;
36
+ }
37
+ /**
38
+ * The training set of a published knowledge. With `-o` the bytes are written: the public path is a plain download,
39
+ * a `derivative` set goes through a signed derive intent and `/p2p/dataset/<sha>` with the token it returns.
40
+ */
41
+ export async function datasetGetPublished(ctx, target, opts = {}) {
42
+ const s = await TeachSession.open(ctx, opts);
43
+ const { id, name } = await resolveTarget(s, target);
44
+ const dataset = await s.get(`/api/patches/${encodeURIComponent(id)}/dataset`).catch(refusal);
45
+ const out = { node: s.client.baseUrl, patch_id: id, ...(name ? { name } : {}), dataset };
46
+ if (opts.manifest)
47
+ out.manifest = (await s.get(`/api/patches/${encodeURIComponent(id)}/dataset/manifest`).catch(refusal)).manifest;
48
+ if (opts.out)
49
+ out.saved = await download(s, id, dataset, opts, ctx);
50
+ emit(ctx, out, renderPublishedDataset);
51
+ return out;
52
+ }
53
+ /** A sha256 names the bytes, not the knowledge: find the knowledge on this node that published them. */
54
+ async function resolveTarget(s, target) {
55
+ if (!SHA_RE.test(target))
56
+ return { id: target };
57
+ const sha = target.toLowerCase();
58
+ const cat = await s.client.get('/api/catalog?limit=200', { auth: false }).catch(() => ({ items: [] }));
59
+ const hit = cat.items.map((e) => e.anchor).find((a) => a.dataset?.sha256 === sha);
60
+ if (!hit)
61
+ throw new CliError(`no knowledge on ${s.client.baseUrl} published the training set ${shortHash(sha, 12)} — give the knowledge id instead`, 3);
62
+ return { id: hit.id, name: hit.name };
63
+ }
64
+ async function download(s, id, d, opts, ctx) {
65
+ let bytes = null;
66
+ let via = 'node';
67
+ const direct = await s.raw(`/api/patches/${encodeURIComponent(id)}/dataset/rows`);
68
+ if (direct.ok)
69
+ bytes = Buffer.from(await direct.arrayBuffer());
70
+ else if (direct.status === 403 && d.access === 'derivative') {
71
+ // the derive intent IS the record that someone is building on this knowledge (§6.1) — it is counted on the parent
72
+ const intent = await s.post(`/api/patches/${encodeURIComponent(id)}/derive-intent`, {}).catch(refusal);
73
+ // Item 312: the intent is a commitment, not a formality — say what was just promised, in the node's own words.
74
+ if (intent.terms)
75
+ warn(ctx, intent.terms);
76
+ const ts = Date.now();
77
+ const auth = `${s.key.address}:${ts}:${signMessage(`dataset:${intent.sha256}:${ts}`, s.key.privateKey)}`;
78
+ const res = await fetch(`${s.client.baseUrl}/p2p/dataset/${intent.sha256}`, { headers: { 'x-ainize-auth': auth, 'x-ainize-derive': intent.token } });
79
+ if (!res.ok)
80
+ throw new CliError(`the training set was not served: HTTP ${res.status} ${(await res.text()).slice(0, 200)}`, 3);
81
+ bytes = Buffer.from(await res.arrayBuffer());
82
+ via = 'derive';
83
+ }
84
+ else {
85
+ const body = await direct.text();
86
+ let msg = `HTTP ${direct.status}`;
87
+ try {
88
+ msg = String(JSON.parse(body).error ?? msg);
89
+ }
90
+ catch { /* not json */ }
91
+ refusal(new CliError(msg, 3));
92
+ }
93
+ // notes are the publisher's own words about a row; they are in the file only because the publisher opted in, and
94
+ // they are written to disk only if this caller asks for them too (§6.2)
95
+ let notesRemoved = 0;
96
+ let written = bytes;
97
+ if (!opts.includeNotes) {
98
+ const lines = written.toString('utf8').split('\n').filter((l) => l.trim());
99
+ const stripped = lines.map((l) => {
100
+ try {
101
+ const o = JSON.parse(l);
102
+ if (o.note === undefined)
103
+ return l;
104
+ notesRemoved++;
105
+ const { note: _n, ...rest } = o;
106
+ return JSON.stringify(rest);
107
+ }
108
+ catch {
109
+ return l;
110
+ }
111
+ });
112
+ if (notesRemoved)
113
+ written = Buffer.from(stripped.join('\n') + '\n', 'utf8');
114
+ }
115
+ const path = resolve(opts.out);
116
+ writeFileSync(path, written);
117
+ const verified = sha256(written) === d.sha256;
118
+ if (!verified && !notesRemoved)
119
+ warn(ctx, 'the bytes do not hash to the fingerprint on the record — do not build on this file');
120
+ return { path, bytes: written.length, sha256: sha256(written), verified, notes_removed: notesRemoved, via };
121
+ }
122
+ export function renderPublishedDataset(r) {
123
+ const d = r.dataset;
124
+ const access = d.access === 'public' ? 'public — anyone can download and build on them'
125
+ : d.access === 'derivative' ? 'shared with people building on this knowledge'
126
+ : 'private — nobody can build on this knowledge';
127
+ const lines = [
128
+ c.head(`training set of ${c.id(r.patch_id)}${r.name ? ` · ${r.name}` : ''}`),
129
+ kv([
130
+ ['questions', String(d.rows)],
131
+ ['access', access],
132
+ ['licence', d.license ?? '—'],
133
+ ['fingerprint', shortHash(d.sha256, 16)],
134
+ ['on this node', d.held ? 'yes' : 'no — fetched from a peer when needed'],
135
+ ...(d.parents.length ? [['built from', d.parents.map((p) => `${p.patch_id} (${p.rows} questions)`).join(', ')]] : []),
136
+ ...(d.benchmark_samples ? [['checked with', `${d.benchmark_samples} questions (the full list travels with the set)`]] : []),
137
+ ]),
138
+ ];
139
+ if (d.preview?.length) {
140
+ lines.push('', c.head(`first ${d.preview.length} questions`));
141
+ for (const row of d.preview)
142
+ lines.push(` ${c.dim('Q')} ${row.prompt}\n ${c.dim('A')} ${row.answer}`);
143
+ }
144
+ if (r.manifest)
145
+ lines.push('', c.head('manifest'), JSON.stringify(r.manifest, null, 1));
146
+ if (r.saved) {
147
+ lines.push('', c.ok('✓ ') + `saved ${r.saved.path} (${fmtBytes(r.saved.bytes)})${r.saved.via === 'derive' ? c.dim(' · fetched as a derivative — recorded against your teaching key') : ''}`);
148
+ if (r.saved.via === 'derive')
149
+ lines.push(c.dim(` a lesson trained on these questions must name ${r.patch_id} as its base (\`${PROG} teach train <dataset> --on ${r.patch_id}\`), or the node will refuse to publish it`));
150
+ if (r.saved.notes_removed)
151
+ lines.push(c.dim(` ${r.saved.notes_removed} note(s) left out — pass --include-notes to keep them (and the published fingerprint)`));
152
+ else if (r.saved.verified)
153
+ lines.push(c.dim(' fingerprint verified — uploading this file gives you the same questions to build on'));
154
+ }
155
+ return lines.join('\n');
156
+ }
157
+ //# sourceMappingURL=dataset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset.js","sourceRoot":"","sources":["../../src/commands/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAmB,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,MAAM,GAAG,CAAC,CAAkB,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpF,MAAM,MAAM,GAAG,iBAAiB,CAAC;AAyBjC,gHAAgH;AAChH,SAAS,OAAO,CAAC,CAAU;IACzB,MAAM,GAAG,GAAG,CAAa,CAAC;IAC1B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC;IACtC,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,oIAAoI,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACjN,IAAI,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,uHAAuH,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5M,IAAI,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,yEAAyE,IAAI,mCAAmC,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACjM,MAAM,CAAC,CAAC;AACV,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAe,EAAE,MAAc,EAAE,OAAuB,EAAE;IAClG,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAmB,gBAAgB,kBAAkB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/G,MAAM,GAAG,GAA2B,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;IACjH,IAAI,IAAI,CAAC,QAAQ;QAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAwC,gBAAgB,kBAAkB,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1K,IAAI,IAAI,CAAC,GAAG;QAAE,GAAG,CAAC,KAAK,GAAG,MAAM,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IACpE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;IACvC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wGAAwG;AACxG,KAAK,UAAU,aAAa,CAAC,CAAe,EAAE,MAAc;IAC1D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAuF,wBAAwB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7L,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC;IAClF,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,OAAO,+BAA+B,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAC;IACxJ,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,CAAe,EAAE,EAAU,EAAE,CAAmB,EAAE,IAAoB,EAAE,GAAe;IAC7G,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,GAAG,GAAsB,MAAM,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,gBAAgB,kBAAkB,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;IAClF,IAAI,MAAM,CAAC,EAAE;QAAE,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;SAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5D,kHAAkH;QAClH,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,IAAI,CAAoD,gBAAgB,kBAAkB,CAAC,EAAE,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1J,+GAA+G;QAC/G,IAAI,MAAM,CAAC,KAAK;YAAE,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,IAAI,WAAW,CAAC,WAAW,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACzG,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrJ,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,QAAQ,CAAC,yCAAyC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9H,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7C,GAAG,GAAG,QAAQ,CAAC;IACjB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,GAAG,GAAG,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI,CAAC;YAAC,GAAG,GAAG,MAAM,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;QACrG,OAAO,CAAC,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IACD,iHAAiH;IACjH,wEAAwE;IACxE,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,OAAO,GAAG,KAAM,CAAC;IACrB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC/B,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAA4B,CAAC;gBACnD,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;oBAAE,OAAO,CAAC,CAAC;gBACnC,YAAY,EAAE,CAAC;gBACf,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;gBAChC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,CAAC,CAAC;YAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,IAAI,YAAY;YAAE,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAI,CAAC,CAAC;IAChC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY;QAAE,IAAI,CAAC,GAAG,EAAE,oFAAoF,CAAC,CAAC;IAChI,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;AAC9G,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,CAAyB;IAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IACpB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,gDAAgD;QACrF,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,+CAA+C;YAC3E,CAAC,CAAC,8CAA8C,CAAC;IACrD,MAAM,KAAK,GAAG;QACZ,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC5E,EAAE,CAAC;YACD,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC,QAAQ,EAAE,MAAM,CAAC;YAClB,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC;YAC7B,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACxC,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,sCAAsC,CAAC;YACzE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzI,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,iBAAiB,iDAAiD,CAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAChJ,CAAC;KACH,CAAC;IACF,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC;QAC9D,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7L,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC,QAAQ,mBAAmB,IAAI,+BAA+B,CAAC,CAAC,QAAQ,4CAA4C,CAAC,CAAC,CAAC;QAC3N,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,aAAa,uFAAuF,CAAC,CAAC,CAAC;aAC3J,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC,CAAC;IACxI,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { type CliContext } from '../context.js';
2
+ import { ok } from '../output.js';
3
+ export declare const DEFAULT_AINDRIVE_SERVER: string;
4
+ export declare function aindriveBin(): string;
5
+ export interface DriveStatus {
6
+ configured: boolean;
7
+ running: boolean;
8
+ pid: number | null;
9
+ folder: string;
10
+ server: string | null;
11
+ drive_id: string | null;
12
+ url: string | null;
13
+ login_hint: string;
14
+ files: {
15
+ path: string;
16
+ size: number;
17
+ mtime: number;
18
+ }[];
19
+ cli?: string;
20
+ }
21
+ export declare function driveStatus(ctx: CliContext, a?: {
22
+ files?: boolean;
23
+ }): Promise<DriveStatus>;
24
+ export declare function driveAction(ctx: CliContext, action: 'up' | 'stop' | 'sync' | 'status'): Promise<unknown>;
25
+ /** One-time browser pairing: runs `aindrive login` interactively inside the node's drive folder. */
26
+ export declare function driveLogin(ctx: CliContext, a?: {
27
+ server?: string;
28
+ name?: string;
29
+ noOpen?: boolean;
30
+ }): Promise<number>;
31
+ export { ok };
32
+ //# sourceMappingURL=drive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../src/commands/drive.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAkC,EAAE,EAAS,MAAM,cAAc,CAAC;AAKzE,eAAO,MAAM,uBAAuB,QAAiE,CAAC;AAEtG,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,MAAM,WAAW,WAAW;IAAG,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CAAE;AAEzQ,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAYpG;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9G;AAED,oGAAoG;AACpG,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB/H;AAED,OAAO,EAAE,EAAE,EAAE,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * `ainize drive status|up|stop|sync|login` — aindrive integration (files & change history of the node).
3
+ */
4
+ import { spawn } from 'node:child_process';
5
+ import { existsSync, mkdirSync } from 'node:fs';
6
+ import { createRequire } from 'node:module';
7
+ import { join } from 'node:path';
8
+ import { NodeClient } from '../client.js';
9
+ import { CliError, PROG } from '../context.js';
10
+ import { c, emit, fmtBytes, fmtTime, kv, ok, table } from '../output.js';
11
+ import { requireConfig } from './init.js';
12
+ const require = createRequire(import.meta.url);
13
+ export const DEFAULT_AINDRIVE_SERVER = process.env.AINDRIVE_SERVER ?? 'https://aindrive.ainetwork.ai';
14
+ export function aindriveBin() {
15
+ try {
16
+ return require.resolve('aindrive/dist/aindrive.mjs');
17
+ }
18
+ catch {
19
+ throw new CliError('aindrive CLI not installed (npm install aindrive)');
20
+ }
21
+ }
22
+ export async function driveStatus(ctx, a = {}) {
23
+ const d = await new NodeClient(ctx).get('/api/drive', { auth: false });
24
+ emit(ctx, d, (x) => [
25
+ kv([
26
+ ['folder', x.folder], ['paired', x.configured ? c.ok('yes') : c.warn(`no — run \`${PROG} drive login\``)], ['agent', x.running ? c.ok(`running (pid ${x.pid})`) : c.dim('stopped')],
27
+ ['server', x.server ?? '-'], ['drive id', x.drive_id ?? '-'], ['url', x.url ? c.id(x.url) : '-'], ['files', x.files.length],
28
+ ]),
29
+ a.files ? '\n' + table(x.files.slice(0, 200), [
30
+ { key: 'p', title: 'PATH', get: (f) => f.path }, { key: 's', title: 'SIZE', get: (f) => fmtBytes(f.size), align: 'right' }, { key: 't', title: 'MODIFIED', get: (f) => fmtTime(f.mtime) },
31
+ ]) : '',
32
+ ].filter(Boolean).join('\n'));
33
+ return d;
34
+ }
35
+ export async function driveAction(ctx, action) {
36
+ const r = await new NodeClient(ctx).post('/api/drive', { action }, { timeoutMs: 120_000 });
37
+ emit(ctx, r, (x) => {
38
+ if (action === 'sync')
39
+ return c.ok('✓ ') + `drive folder synced (${x.written ?? 0} file(s) written)`;
40
+ return (x.ok === false ? c.warn('! ') : c.ok('✓ ')) + (x.message ?? JSON.stringify(x));
41
+ });
42
+ return r;
43
+ }
44
+ /** One-time browser pairing: runs `aindrive login` interactively inside the node's drive folder. */
45
+ export async function driveLogin(ctx, a = {}) {
46
+ const cfg = requireConfig(ctx);
47
+ const folder = join(cfg.dataDir, 'drive');
48
+ if (!existsSync(folder))
49
+ mkdirSync(folder, { recursive: true });
50
+ const server = a.server ?? DEFAULT_AINDRIVE_SERVER;
51
+ const args = [aindriveBin(), 'login', '--server', server];
52
+ if (a.name)
53
+ args.push('--name', a.name);
54
+ if (a.noOpen || !process.env.DISPLAY)
55
+ args.push('--no-open');
56
+ process.stdout.write([
57
+ c.head('aindrive pairing'),
58
+ ` folder : ${folder}`, ` server : ${server}`,
59
+ c.dim(' A browser sign-in link will be printed — open it, click Authorize, and this folder becomes a drive.'),
60
+ c.dim(` After pairing, Ctrl+C here and run \`${PROG} drive up\` to serve it in the background.`), '',
61
+ ].join('\n'));
62
+ return new Promise((resolve) => {
63
+ const child = spawn(process.execPath, args, { cwd: folder, stdio: 'inherit', env: { ...process.env, AINDRIVE_SERVER: server } });
64
+ child.on('exit', (code) => resolve(code ?? 0));
65
+ });
66
+ }
67
+ export { ok };
68
+ //# sourceMappingURL=drive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive.js","sourceRoot":"","sources":["../../src/commands/drive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type CliContext } from '../context.js';
2
+ import { type DatasetOpts, type TrainOpts } from './teach-dataset.js';
3
+ type Fetcher = typeof fetch;
4
+ export interface HuggingFaceOptions extends DatasetOpts, TrainOpts {
5
+ config?: string;
6
+ split?: string;
7
+ revision?: string;
8
+ file?: string;
9
+ limit?: number;
10
+ offset?: number;
11
+ hfTokenFile?: string;
12
+ train?: boolean;
13
+ }
14
+ export interface HuggingFaceSource {
15
+ kind: 'huggingface';
16
+ url: string;
17
+ repository: string;
18
+ revision: string;
19
+ config: string | null;
20
+ split: string | null;
21
+ file: string | null;
22
+ offset: number | null;
23
+ importedRows: number | null;
24
+ totalRows: number | null;
25
+ sampled: boolean | null;
26
+ format: string;
27
+ sha256: string;
28
+ bytes: number;
29
+ inputSha256: string;
30
+ inputBytes: number;
31
+ license: unknown;
32
+ columns: unknown;
33
+ }
34
+ export declare function parseHuggingFaceUrl(input: string): {
35
+ repository: string;
36
+ file?: string;
37
+ revision?: string;
38
+ config?: string;
39
+ split?: string;
40
+ };
41
+ export declare function mapHuggingFaceColumns(bytes: Buffer, format: string, columns?: string): Buffer;
42
+ export declare function readHuggingFaceDataset(input: string, opts?: HuggingFaceOptions, fetcher?: Fetcher): Promise<{
43
+ bytes: Buffer;
44
+ inputBytes: Buffer;
45
+ filename: string;
46
+ source: HuggingFaceSource;
47
+ }>;
48
+ export declare function datasetImportHuggingFace(ctx: CliContext, input: string, opts?: HuggingFaceOptions): Promise<{
49
+ dataset_id: string;
50
+ source: HuggingFaceSource;
51
+ provenance: string;
52
+ node: string;
53
+ file: string;
54
+ bytes: number;
55
+ sha256: string;
56
+ job?: import("./teach-dataset.js").CreateJobResult;
57
+ waited?: boolean;
58
+ dataset: import("@ainize/core").TeachDataset;
59
+ report: import("./teach-dataset.js").DatasetReport;
60
+ created: boolean;
61
+ }>;
62
+ export {};
63
+ //# sourceMappingURL=huggingface-dataset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"huggingface-dataset.d.ts","sourceRoot":"","sources":["../../src/commands/huggingface-dataset.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAA+B,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAOnG,KAAK,OAAO,GAAG,OAAO,KAAK,CAAC;AAG5B,MAAM,WAAW,kBAAmB,SAAQ,WAAW,EAAE,SAAS;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACxE;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IACvE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACtG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;CAC5H;AAOD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAe5I;AAgDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAoB7F;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAyFhN;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB;;;;;;;;;;;;;GAe3G"}
@@ -0,0 +1,254 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdirSync, mkdtempSync, readFileSync, statSync, writeFileSync } from 'node:fs';
3
+ import { extname, join } from 'node:path';
4
+ import { CliError } from '../context.js';
5
+ import { emit } from '../output.js';
6
+ import { datasetUpload, renderUpload } from './teach-dataset.js';
7
+ const HUB = 'https://huggingface.co';
8
+ const VIEWER = 'https://datasets-server.huggingface.co';
9
+ const MAX_BYTES = 32 * 1024 * 1024;
10
+ const MAX_ROWS = 10000;
11
+ const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex');
12
+ function object(value, label) {
13
+ if (!value || typeof value !== 'object' || Array.isArray(value))
14
+ throw new CliError(`invalid Hugging Face ${label}`);
15
+ return value;
16
+ }
17
+ export function parseHuggingFaceUrl(input) {
18
+ let url;
19
+ try {
20
+ url = new URL(input);
21
+ }
22
+ catch {
23
+ throw new CliError('expected https://huggingface.co/datasets/<owner>/<name>');
24
+ }
25
+ if (url.origin !== HUB || url.username || url.password || url.search || url.hash || /%2f|%5c|\\/i.test(url.pathname)) {
26
+ throw new CliError('use an HTTPS huggingface.co dataset URL without credentials, query parameters or fragments');
27
+ }
28
+ const parts = url.pathname.replace(/\/$/, '').split('/').slice(1).map(part => decodeURIComponent(part));
29
+ if (parts[0] !== 'datasets' || !parts[1] || !parts[2] || ![parts[1], parts[2]].every(part => /^[A-Za-z0-9_.-]+$/.test(part))) {
30
+ throw new CliError('expected a dataset URL, not a model or Space URL: https://huggingface.co/datasets/<owner>/<name>');
31
+ }
32
+ const repository = `${parts[1]}/${parts[2]}`;
33
+ if (parts.length === 3)
34
+ return { repository };
35
+ if (parts[3] === 'resolve' && parts.length >= 6 && parts[4])
36
+ return { repository, revision: parts[4], file: parts.slice(5).join('/') };
37
+ if (parts[3] === 'viewer' && parts.length === 6 && parts[4] && parts[5])
38
+ return { repository, config: parts[4], split: parts[5] };
39
+ throw new CliError('use the dataset repository URL, /viewer/<config>/<split>, or /resolve/<revision>/<file>');
40
+ }
41
+ function filePath(value) {
42
+ if (!value || value.includes('\\') || value.split('/').some(part => !part || part === '.' || part === '..'))
43
+ throw new CliError('invalid Hugging Face file path');
44
+ return value.split('/').map(encodeURIComponent).join('/');
45
+ }
46
+ async function download(url, fetcher, token) {
47
+ for (let redirects = 0; redirects <= 5; redirects++) {
48
+ const trusted = url.origin === HUB || url.origin === VIEWER;
49
+ const fileHost = url.hostname.endsWith('.hf.co') || url.hostname.endsWith('.huggingface.co');
50
+ if (url.protocol !== 'https:' || url.port || url.username || url.password || (!trusted && !fileHost))
51
+ throw new CliError('Hugging Face redirected to an unsupported host');
52
+ const headers = { accept: 'application/json, text/plain, */*' };
53
+ if (trusted && token)
54
+ headers.authorization = `Bearer ${token}`;
55
+ const response = await fetcher(url, { headers, redirect: 'manual', signal: AbortSignal.timeout(60000) });
56
+ if ([301, 302, 303, 307, 308].includes(response.status)) {
57
+ const location = response.headers.get('location');
58
+ await response.body?.cancel();
59
+ if (!location)
60
+ throw new CliError('Hugging Face redirect has no location');
61
+ url = new URL(location, url);
62
+ continue;
63
+ }
64
+ if (!response.ok) {
65
+ await response.body?.cancel();
66
+ throw new CliError(`Hugging Face HTTP ${response.status}${response.status === 401 || response.status === 403 ? '; use --hf-token-file for an account with access (gated terms must already be accepted)' : '; dataset viewer may be unavailable: use --file with a supported data file'}`);
67
+ }
68
+ if (Number(response.headers.get('content-length')) > MAX_BYTES) {
69
+ await response.body?.cancel();
70
+ throw new CliError('Hugging Face response exceeds the 32 MiB import limit');
71
+ }
72
+ if (!response.body)
73
+ throw new CliError('empty Hugging Face response');
74
+ const chunks = [];
75
+ let length = 0;
76
+ const reader = response.body.getReader();
77
+ try {
78
+ for (;;) {
79
+ const chunk = await reader.read();
80
+ if (chunk.done)
81
+ break;
82
+ length += chunk.value.byteLength;
83
+ if (length > MAX_BYTES)
84
+ throw new CliError('Hugging Face response exceeds the 32 MiB import limit');
85
+ chunks.push(Buffer.from(chunk.value));
86
+ }
87
+ }
88
+ finally {
89
+ await reader.cancel();
90
+ reader.releaseLock();
91
+ }
92
+ return { bytes: Buffer.concat(chunks), revision: response.headers.get('x-revision') };
93
+ }
94
+ throw new CliError('too many Hugging Face redirects');
95
+ }
96
+ export function mapHuggingFaceColumns(bytes, format, columns) {
97
+ if (!columns || !['jsonl', 'json'].includes(format))
98
+ return bytes;
99
+ const mapping = object(JSON.parse(columns), 'column mapping');
100
+ const fields = ['prompt', 'answer', 'alt_prompt', 'note'];
101
+ if (!mapping.prompt || !mapping.answer || Object.keys(mapping).some(key => !fields.includes(key)) || Object.values(mapping).some(value => typeof value !== 'string' || !value))
102
+ throw new CliError('--columns must map prompt/answer and optional alt_prompt/note to existing column names');
103
+ const parsed = format === 'jsonl' ? bytes.toString('utf8').trim().split('\n').map(line => JSON.parse(line)) : JSON.parse(bytes.toString('utf8'));
104
+ if (!Array.isArray(parsed))
105
+ throw new CliError('JSON column mapping requires an array of objects');
106
+ const rows = parsed.map((value, index) => {
107
+ const original = object(value, `row ${index}`);
108
+ const mapped = {};
109
+ for (const [field, column] of Object.entries(mapping)) {
110
+ if (!Object.hasOwn(original, column))
111
+ throw new CliError(`missing column ${column} at row ${index}`);
112
+ const cell = original[column];
113
+ if ((cell === null || cell === undefined) && !['prompt', 'answer'].includes(field))
114
+ continue;
115
+ if (typeof cell !== 'string' && typeof cell !== 'boolean' && !(typeof cell === 'number' && Number.isFinite(cell)))
116
+ throw new CliError(`column ${column} at row ${index} must be a scalar, not an object or array`);
117
+ mapped[field] = String(cell);
118
+ }
119
+ return mapped;
120
+ });
121
+ return Buffer.from(format === 'jsonl' ? rows.map(row => JSON.stringify(row)).join('\n') + '\n' : JSON.stringify(rows));
122
+ }
123
+ export async function readHuggingFaceDataset(input, opts = {}, fetcher = fetch) {
124
+ const target = parseHuggingFaceUrl(input);
125
+ for (const key of ['revision', 'file', 'config', 'split']) {
126
+ if (target[key] && opts[key] && target[key] !== opts[key])
127
+ throw new CliError(`URL and --${key} disagree`);
128
+ }
129
+ const selected = { ...target, ...Object.fromEntries(Object.entries(opts).filter(([, value]) => value !== undefined)) };
130
+ let token;
131
+ if (opts.hfTokenFile) {
132
+ const stats = statSync(opts.hfTokenFile);
133
+ if (!stats.isFile() || (stats.mode & 0o077) !== 0)
134
+ throw new CliError('--hf-token-file must be a private file (chmod 600)');
135
+ token = readFileSync(opts.hfTokenFile, 'utf8').trim();
136
+ if (!token || /\s/.test(token))
137
+ throw new CliError('invalid Hugging Face token file');
138
+ }
139
+ const request = (url) => download(url, fetcher, token);
140
+ const metadataUrl = new URL(`/api/datasets/${target.repository}/revision/${encodeURIComponent(selected.revision || 'main')}`, HUB);
141
+ const metadata = object(JSON.parse((await request(metadataUrl)).bytes.toString('utf8')), 'repository metadata');
142
+ if (typeof metadata.sha !== 'string' || !/^[a-f0-9]{40}$/.test(metadata.sha))
143
+ throw new CliError('Hugging Face did not return an immutable revision');
144
+ if (metadata.id !== target.repository)
145
+ throw new CliError('Hugging Face repository identity changed');
146
+ const source = { kind: 'huggingface', url: input, repository: target.repository, revision: metadata.sha,
147
+ config: null, split: null, file: null, offset: null, importedRows: null, totalRows: null, sampled: null,
148
+ format: '', sha256: '', bytes: 0, inputSha256: '', inputBytes: 0, license: metadata.cardData?.license ?? null,
149
+ columns: opts.columns ? JSON.parse(opts.columns) : null };
150
+ let bytes;
151
+ let filename;
152
+ if (selected.file) {
153
+ if (opts.offset !== undefined || opts.limit !== undefined || selected.config || selected.split)
154
+ throw new CliError('--file cannot be combined with config/split/offset/limit; it imports the file as supplied');
155
+ const encoded = filePath(selected.file);
156
+ source.format = opts.format || extname(selected.file).slice(1).toLowerCase();
157
+ if (!['jsonl', 'json', 'csv', 'tsv', 'txt'].includes(source.format))
158
+ throw new CliError('file imports support jsonl/json/csv/tsv/txt; use a repository URL and --config/--split for viewer-backed Parquet datasets');
159
+ bytes = (await request(new URL(`/datasets/${target.repository}/resolve/${metadata.sha}/${encoded}`, HUB))).bytes;
160
+ filename = `data.${source.format}`;
161
+ source.file = selected.file;
162
+ }
163
+ else {
164
+ const offset = opts.offset ?? 0;
165
+ if (!Number.isSafeInteger(offset) || offset < 0 || (opts.limit !== undefined && (!Number.isSafeInteger(opts.limit) || opts.limit < 1 || opts.limit > MAX_ROWS)))
166
+ throw new CliError('offset must be a nonnegative integer; limit must be 1..10000');
167
+ const splitsUrl = new URL('/splits', VIEWER);
168
+ splitsUrl.searchParams.set('dataset', target.repository);
169
+ const splitsResponse = await request(splitsUrl);
170
+ if (splitsResponse.revision !== metadata.sha)
171
+ throw new CliError('dataset viewer revision differs from the requested source; use --file for an immutable file import');
172
+ const splitData = object(JSON.parse(splitsResponse.bytes.toString('utf8')), 'splits');
173
+ if (!Array.isArray(splitData.splits))
174
+ throw new CliError('invalid Hugging Face split list');
175
+ const splits = splitData.splits.map(value => object(value, 'split'));
176
+ const configs = [...new Set(splits.map(split => split.config))];
177
+ const config = selected.config ?? (configs.length === 1 ? configs[0] : undefined);
178
+ if (typeof config !== 'string')
179
+ throw new CliError(`choose --config; available configurations: ${configs.slice(0, 12).join(', ') || 'not ready in the viewer; use --file'}`);
180
+ const candidates = splits.filter(split => split.config === config);
181
+ const splitName = selected.split ?? (candidates.some(split => split.split === 'train') ? 'train' : candidates.length === 1 ? candidates[0].split : undefined);
182
+ if (typeof splitName !== 'string' || !candidates.some(split => split.split === splitName))
183
+ throw new CliError('choose an available --split for the selected --config');
184
+ const rows = [];
185
+ let serializedBytes = 0;
186
+ let totalRows = null;
187
+ let targetRows = opts.limit ?? MAX_ROWS;
188
+ while (rows.length < targetRows) {
189
+ const pageOffset = offset + rows.length;
190
+ const pageLength = Math.min(100, targetRows - rows.length);
191
+ const rowsUrl = new URL('/rows', VIEWER);
192
+ for (const [key, value] of Object.entries({ dataset: target.repository, config, split: splitName, offset: pageOffset, length: pageLength }))
193
+ rowsUrl.searchParams.set(key, String(value));
194
+ const pageResponse = await request(rowsUrl);
195
+ if (pageResponse.revision !== metadata.sha)
196
+ throw new CliError('dataset revision changed during pagination; no dataset uploaded');
197
+ const page = object(JSON.parse(pageResponse.bytes.toString('utf8')), 'rows');
198
+ if (page.partial !== false || !Number.isSafeInteger(page.num_rows_total) || page.num_rows_total < 0 || !Array.isArray(page.rows))
199
+ throw new CliError('incomplete or invalid Hugging Face rows response');
200
+ if (totalRows !== null && totalRows !== page.num_rows_total)
201
+ throw new CliError('dataset row count changed during pagination');
202
+ totalRows = page.num_rows_total;
203
+ if (offset >= totalRows)
204
+ throw new CliError('offset selects no rows');
205
+ if (opts.limit === undefined && totalRows - offset > MAX_ROWS)
206
+ throw new CliError('dataset exceeds 10000 rows; choose an explicit --limit (and optionally --offset), or import a supported file');
207
+ targetRows = Math.min(opts.limit ?? totalRows - offset, totalRows - offset);
208
+ if (page.rows.length !== Math.min(pageLength, targetRows - rows.length))
209
+ throw new CliError('missing or unexpected Hugging Face rows');
210
+ for (const [index, value] of page.rows.entries()) {
211
+ const item = object(value, 'row wrapper');
212
+ if (item.row_idx !== pageOffset + index || !Array.isArray(item.truncated_cells) || item.truncated_cells.length)
213
+ throw new CliError('out-of-order or truncated Hugging Face row');
214
+ const row = object(item.row, 'row');
215
+ serializedBytes += Buffer.byteLength(JSON.stringify(row)) + 1;
216
+ if (serializedBytes > MAX_BYTES)
217
+ throw new CliError('import exceeds the 32 MiB limit; select fewer rows with --limit');
218
+ rows.push(row);
219
+ }
220
+ }
221
+ bytes = Buffer.from(rows.map(row => JSON.stringify(row)).join('\n') + '\n');
222
+ filename = `huggingface-${target.repository.replace('/', '-')}.jsonl`;
223
+ Object.assign(source, { config, split: splitName, offset, importedRows: rows.length, totalRows, sampled: offset > 0 || rows.length !== totalRows, format: 'jsonl' });
224
+ }
225
+ if (!bytes.length || bytes.length > MAX_BYTES)
226
+ throw new CliError('import must contain 1 byte..32 MiB');
227
+ const inputBytes = bytes;
228
+ source.inputSha256 = sha256(inputBytes);
229
+ source.inputBytes = inputBytes.length;
230
+ bytes = mapHuggingFaceColumns(inputBytes, source.format, opts.columns);
231
+ if (bytes.length > MAX_BYTES)
232
+ throw new CliError('mapped import exceeds the 32 MiB limit');
233
+ source.sha256 = sha256(bytes);
234
+ source.bytes = bytes.length;
235
+ return { bytes, inputBytes, filename, source };
236
+ }
237
+ export async function datasetImportHuggingFace(ctx, input, opts = {}) {
238
+ if (opts.wait && !opts.train)
239
+ throw new CliError('--wait requires --train');
240
+ const imported = await readHuggingFaceDataset(input, opts);
241
+ const cache = join(ctx.home, 'hf-imports');
242
+ mkdirSync(cache, { recursive: true, mode: 0o700 });
243
+ const folder = mkdtempSync(join(cache, 'import-'));
244
+ const filename = join(folder, imported.filename);
245
+ const provenance = join(folder, 'source.json');
246
+ writeFileSync(filename, imported.bytes, { flag: 'wx', mode: 0o600 });
247
+ writeFileSync(join(folder, `input.${imported.source.format}`), imported.inputBytes, { flag: 'wx', mode: 0o600 });
248
+ writeFileSync(provenance, JSON.stringify(imported.source, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
249
+ const result = await datasetUpload(ctx, filename, { ...opts, columns: ['json', 'jsonl'].includes(imported.source.format) ? undefined : opts.columns, format: imported.source.format, silent: true });
250
+ const output = { ...result, dataset_id: result.dataset.id, source: imported.source, provenance };
251
+ emit(ctx, output, value => `${renderUpload(value)}\nHugging Face: ${value.source.repository}@${value.source.revision}\nSource evidence: ${value.provenance}\nImported into this node; not published to Hugging Face or the public catalog.`);
252
+ return output;
253
+ }
254
+ //# sourceMappingURL=huggingface-dataset.js.map