@newtype-ai/nit 0.4.8 → 0.4.10

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.
@@ -1,1601 +0,0 @@
1
- // nit — version control for agent cards
2
-
3
- // src/index.ts
4
- import { promises as fs7, statSync } from "fs";
5
- import { join as join7, basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
6
-
7
- // src/objects.ts
8
- import { createHash } from "crypto";
9
- import { promises as fs } from "fs";
10
- import { join } from "path";
11
- function hashObject(type, content) {
12
- const buf = Buffer.from(content, "utf-8");
13
- const header = `${type} ${buf.byteLength}\0`;
14
- const hash = createHash("sha256");
15
- hash.update(header);
16
- hash.update(buf);
17
- return hash.digest("hex");
18
- }
19
- async function writeObject(nitDir, type, content) {
20
- const hex = hashObject(type, content);
21
- const dir = join(nitDir, "objects", hex.slice(0, 2));
22
- const file = join(dir, hex.slice(2));
23
- try {
24
- await fs.access(file);
25
- return hex;
26
- } catch {
27
- }
28
- await fs.mkdir(dir, { recursive: true });
29
- await fs.writeFile(file, content, "utf-8");
30
- return hex;
31
- }
32
- async function readObject(nitDir, hash) {
33
- const file = join(nitDir, "objects", hash.slice(0, 2), hash.slice(2));
34
- try {
35
- return await fs.readFile(file, "utf-8");
36
- } catch {
37
- throw new Error(`Object not found: ${hash}`);
38
- }
39
- }
40
- function serializeCommit(commit2) {
41
- const lines = [];
42
- lines.push(`card ${commit2.card}`);
43
- if (commit2.parent !== null) {
44
- lines.push(`parent ${commit2.parent}`);
45
- }
46
- lines.push(`author ${commit2.author} ${commit2.timestamp}`);
47
- lines.push("");
48
- lines.push(commit2.message);
49
- return lines.join("\n");
50
- }
51
- function parseCommit(hash, raw) {
52
- const lines = raw.split("\n");
53
- let card = "";
54
- let parent = null;
55
- let author = "";
56
- let timestamp = 0;
57
- let messageStart = -1;
58
- for (let i = 0; i < lines.length; i++) {
59
- const line = lines[i];
60
- if (line === "") {
61
- messageStart = i + 1;
62
- break;
63
- }
64
- if (line.startsWith("card ")) {
65
- card = line.slice(5);
66
- } else if (line.startsWith("parent ")) {
67
- parent = line.slice(7);
68
- } else if (line.startsWith("author ")) {
69
- const authorPart = line.slice(7);
70
- const lastSpace = authorPart.lastIndexOf(" ");
71
- author = authorPart.slice(0, lastSpace);
72
- timestamp = parseInt(authorPart.slice(lastSpace + 1), 10);
73
- }
74
- }
75
- if (!card) {
76
- throw new Error(`Malformed commit object ${hash}: missing card hash`);
77
- }
78
- const message = messageStart >= 0 ? lines.slice(messageStart).join("\n") : "";
79
- return {
80
- type: "commit",
81
- hash,
82
- card,
83
- parent,
84
- author,
85
- timestamp,
86
- message
87
- };
88
- }
89
-
90
- // src/refs.ts
91
- import { promises as fs2 } from "fs";
92
- import { join as join2 } from "path";
93
- async function getHead(nitDir) {
94
- const headPath = join2(nitDir, "HEAD");
95
- const content = (await fs2.readFile(headPath, "utf-8")).trim();
96
- if (!content.startsWith("ref: ")) {
97
- throw new Error(
98
- `HEAD is in an unexpected state: "${content}". Only symbolic refs are supported.`
99
- );
100
- }
101
- return { type: "ref", ref: content.slice(5) };
102
- }
103
- async function resolveHead(nitDir) {
104
- const head = await getHead(nitDir);
105
- const refPath = join2(nitDir, head.ref);
106
- try {
107
- return (await fs2.readFile(refPath, "utf-8")).trim();
108
- } catch {
109
- throw new Error(
110
- `Branch ref ${head.ref} does not exist. Repository may be empty.`
111
- );
112
- }
113
- }
114
- async function getCurrentBranch(nitDir) {
115
- const head = await getHead(nitDir);
116
- const prefix = "refs/heads/";
117
- if (!head.ref.startsWith(prefix)) {
118
- throw new Error(`HEAD ref has unexpected format: ${head.ref}`);
119
- }
120
- return head.ref.slice(prefix.length);
121
- }
122
- async function setBranch(nitDir, branch2, commitHash) {
123
- const refPath = join2(nitDir, "refs", "heads", branch2);
124
- await fs2.mkdir(join2(nitDir, "refs", "heads"), { recursive: true });
125
- await fs2.writeFile(refPath, commitHash + "\n", "utf-8");
126
- }
127
- async function getBranch(nitDir, branch2) {
128
- const refPath = join2(nitDir, "refs", "heads", branch2);
129
- try {
130
- return (await fs2.readFile(refPath, "utf-8")).trim();
131
- } catch {
132
- return null;
133
- }
134
- }
135
- async function listBranches(nitDir) {
136
- const headsDir = join2(nitDir, "refs", "heads");
137
- const branches = [];
138
- try {
139
- const entries = await fs2.readdir(headsDir);
140
- for (const name of entries) {
141
- const refPath = join2(headsDir, name);
142
- const stat = await fs2.stat(refPath);
143
- if (stat.isFile()) {
144
- const commitHash = (await fs2.readFile(refPath, "utf-8")).trim();
145
- branches.push({ name, commitHash });
146
- }
147
- }
148
- } catch {
149
- }
150
- return branches.sort((a, b) => a.name.localeCompare(b.name));
151
- }
152
- async function setHead(nitDir, branch2) {
153
- const headPath = join2(nitDir, "HEAD");
154
- await fs2.writeFile(headPath, `ref: refs/heads/${branch2}
155
- `, "utf-8");
156
- }
157
- async function setRemoteRef(nitDir, remote2, branch2, commitHash) {
158
- const dir = join2(nitDir, "refs", "remote", remote2);
159
- await fs2.mkdir(dir, { recursive: true });
160
- await fs2.writeFile(join2(dir, branch2), commitHash + "\n", "utf-8");
161
- }
162
- async function getRemoteRef(nitDir, remote2, branch2) {
163
- const refPath = join2(nitDir, "refs", "remote", remote2, branch2);
164
- try {
165
- return (await fs2.readFile(refPath, "utf-8")).trim();
166
- } catch {
167
- return null;
168
- }
169
- }
170
-
171
- // src/identity.ts
172
- import {
173
- createHash as createHash2,
174
- generateKeyPairSync,
175
- createPrivateKey,
176
- createPublicKey,
177
- sign,
178
- verify
179
- } from "crypto";
180
- import { promises as fs3 } from "fs";
181
- import { join as join3 } from "path";
182
- function base64urlToBase64(b64url) {
183
- let s = b64url.replace(/-/g, "+").replace(/_/g, "/");
184
- while (s.length % 4 !== 0) s += "=";
185
- return s;
186
- }
187
- function base64ToBase64url(b64) {
188
- return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
189
- }
190
- async function generateKeypair(nitDir) {
191
- const identityDir = join3(nitDir, "identity");
192
- await fs3.mkdir(identityDir, { recursive: true });
193
- const { publicKey, privateKey } = generateKeyPairSync("ed25519");
194
- const pubJwk = publicKey.export({ format: "jwk" });
195
- const privJwk = privateKey.export({ format: "jwk" });
196
- const pubBase64 = base64urlToBase64(pubJwk.x);
197
- const privBase64 = base64urlToBase64(privJwk.d);
198
- const pubPath = join3(identityDir, "agent.pub");
199
- const keyPath = join3(identityDir, "agent.key");
200
- await fs3.writeFile(pubPath, pubBase64 + "\n", "utf-8");
201
- await fs3.writeFile(keyPath, privBase64 + "\n", {
202
- mode: 384,
203
- encoding: "utf-8"
204
- });
205
- return { publicKey: pubBase64, privateKey: privBase64 };
206
- }
207
- async function loadPublicKey(nitDir) {
208
- const pubPath = join3(nitDir, "identity", "agent.pub");
209
- try {
210
- return (await fs3.readFile(pubPath, "utf-8")).trim();
211
- } catch {
212
- throw new Error(
213
- "No identity found. Run `nit init` to generate a keypair."
214
- );
215
- }
216
- }
217
- async function loadPrivateKey(nitDir) {
218
- const pubBase64 = await loadPublicKey(nitDir);
219
- const keyPath = join3(nitDir, "identity", "agent.key");
220
- let privBase64;
221
- try {
222
- privBase64 = (await fs3.readFile(keyPath, "utf-8")).trim();
223
- } catch {
224
- throw new Error(
225
- "Private key not found at .nit/identity/agent.key. Regenerate with `nit init`."
226
- );
227
- }
228
- const xB64url = base64ToBase64url(pubBase64);
229
- const dB64url = base64ToBase64url(privBase64);
230
- return createPrivateKey({
231
- key: { kty: "OKP", crv: "Ed25519", x: xB64url, d: dB64url },
232
- format: "jwk"
233
- });
234
- }
235
- async function loadRawKeyPair(nitDir) {
236
- const pubBase64 = await loadPublicKey(nitDir);
237
- const keyPath = join3(nitDir, "identity", "agent.key");
238
- let privBase64;
239
- try {
240
- privBase64 = (await fs3.readFile(keyPath, "utf-8")).trim();
241
- } catch {
242
- throw new Error(
243
- "Private key not found at .nit/identity/agent.key. Regenerate with `nit init`."
244
- );
245
- }
246
- const seed = Buffer.from(privBase64, "base64");
247
- const pubkey = Buffer.from(pubBase64, "base64");
248
- const keypair = new Uint8Array(64);
249
- keypair.set(seed, 0);
250
- keypair.set(pubkey, 32);
251
- return keypair;
252
- }
253
- function formatPublicKeyField(pubBase64) {
254
- return `ed25519:${pubBase64}`;
255
- }
256
- function parsePublicKeyField(field) {
257
- const prefix = "ed25519:";
258
- if (!field.startsWith(prefix)) {
259
- throw new Error(
260
- `Invalid publicKey format: expected "ed25519:<base64>", got "${field}"`
261
- );
262
- }
263
- return field.slice(prefix.length);
264
- }
265
- async function signChallenge(nitDir, challenge) {
266
- const privateKey = await loadPrivateKey(nitDir);
267
- const sig = sign(null, Buffer.from(challenge, "utf-8"), privateKey);
268
- return sig.toString("base64");
269
- }
270
- async function signMessage(nitDir, message) {
271
- const privateKey = await loadPrivateKey(nitDir);
272
- const sig = sign(null, Buffer.from(message, "utf-8"), privateKey);
273
- return sig.toString("base64");
274
- }
275
- var NIT_NAMESPACE = "801ba518-f326-47e5-97c9-d1efd1865a19";
276
- function deriveAgentId(publicKeyField) {
277
- return uuidv5(publicKeyField, NIT_NAMESPACE);
278
- }
279
- async function loadAgentId(nitDir) {
280
- const idPath = join3(nitDir, "identity", "agent-id");
281
- try {
282
- return (await fs3.readFile(idPath, "utf-8")).trim();
283
- } catch {
284
- throw new Error(
285
- "No agent ID found. Run `nit init` to generate identity."
286
- );
287
- }
288
- }
289
- async function saveAgentId(nitDir, agentId) {
290
- const idPath = join3(nitDir, "identity", "agent-id");
291
- await fs3.writeFile(idPath, agentId + "\n", "utf-8");
292
- }
293
- function parseUuid(uuid) {
294
- const hex = uuid.replace(/-/g, "");
295
- return Buffer.from(hex, "hex");
296
- }
297
- function formatUuid(bytes) {
298
- const hex = bytes.toString("hex");
299
- return [
300
- hex.slice(0, 8),
301
- hex.slice(8, 12),
302
- hex.slice(12, 16),
303
- hex.slice(16, 20),
304
- hex.slice(20, 32)
305
- ].join("-");
306
- }
307
- function uuidv5(name, namespace) {
308
- const namespaceBytes = parseUuid(namespace);
309
- const nameBytes = Buffer.from(name, "utf-8");
310
- const data = Buffer.concat([namespaceBytes, nameBytes]);
311
- const hash = createHash2("sha1").update(data).digest();
312
- const uuid = Buffer.from(hash.subarray(0, 16));
313
- uuid[6] = uuid[6] & 15 | 80;
314
- uuid[8] = uuid[8] & 63 | 128;
315
- return formatUuid(uuid);
316
- }
317
-
318
- // src/skills.ts
319
- import { promises as fs4 } from "fs";
320
- import { join as join4, resolve } from "path";
321
- import { homedir } from "os";
322
- var FRAMEWORK_MARKERS = [
323
- { marker: ".claude", skillsPath: ".claude/skills", innerSkillsPath: "skills" },
324
- { marker: ".cursor", skillsPath: ".cursor/skills", innerSkillsPath: "skills" },
325
- { marker: ".codex", skillsPath: ".codex/skills", innerSkillsPath: "skills" },
326
- { marker: ".windsurf", skillsPath: ".windsurf/skills", innerSkillsPath: "skills" },
327
- { marker: ".openclaw", skillsPath: ".openclaw/workspace/skills", innerSkillsPath: ".agent/skills" }
328
- ];
329
- var GLOBAL_SKILLS_DIRS = [
330
- { marker: ".claude", skillsPath: ".claude/skills" },
331
- { marker: ".codex", skillsPath: ".codex/skills" },
332
- { marker: ".codeium", skillsPath: ".codeium/windsurf/skills" }
333
- ];
334
- async function discoverSkillsDir(projectDir2) {
335
- const absProject = resolve(projectDir2);
336
- const home = homedir();
337
- for (const { marker, innerSkillsPath } of FRAMEWORK_MARKERS) {
338
- if (absProject.includes(`/${marker}/`) || absProject.includes(`/${marker}`)) {
339
- return join4(absProject, innerSkillsPath);
340
- }
341
- }
342
- for (const { marker, skillsPath } of FRAMEWORK_MARKERS) {
343
- try {
344
- const stat = await fs4.stat(join4(absProject, marker));
345
- if (stat.isDirectory()) {
346
- return join4(absProject, skillsPath);
347
- }
348
- } catch {
349
- }
350
- }
351
- for (const { marker, skillsPath } of GLOBAL_SKILLS_DIRS) {
352
- try {
353
- const stat = await fs4.stat(join4(home, marker));
354
- if (stat.isDirectory()) {
355
- return join4(home, skillsPath);
356
- }
357
- } catch {
358
- }
359
- }
360
- return join4(absProject, ".agents", "skills");
361
- }
362
- async function createSkillTemplate(skillsDir, domain) {
363
- const skillId = domain.replace(/\./g, "-");
364
- const skillDir = join4(skillsDir, skillId);
365
- const skillPath = join4(skillDir, "SKILL.md");
366
- let localVersion;
367
- try {
368
- const existing = await fs4.readFile(skillPath, "utf-8");
369
- localVersion = parseVersion(existing);
370
- } catch {
371
- }
372
- let remoteContent = null;
373
- let remoteVersion;
374
- try {
375
- const res = await fetch(`https://${domain}/skill.md`, {
376
- headers: { "Accept": "text/markdown, text/plain" },
377
- signal: AbortSignal.timeout(5e3)
378
- });
379
- if (res.ok) {
380
- const text = await res.text();
381
- if (text.startsWith("---")) {
382
- remoteContent = text;
383
- remoteVersion = parseVersion(text);
384
- }
385
- }
386
- } catch {
387
- }
388
- if (localVersion !== void 0) {
389
- if (!remoteVersion || !isNewerVersion(remoteVersion, localVersion)) {
390
- return skillId;
391
- }
392
- }
393
- await fs4.mkdir(skillDir, { recursive: true });
394
- await fs4.writeFile(
395
- skillPath,
396
- remoteContent ?? fallbackTemplate(skillId, domain),
397
- "utf-8"
398
- );
399
- return skillId;
400
- }
401
- function parseVersion(content) {
402
- const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
403
- if (!fmMatch) return void 0;
404
- const versionMatch = fmMatch[1].match(/^version:\s*(.+)$/m);
405
- return versionMatch ? versionMatch[1].trim() : void 0;
406
- }
407
- function isNewerVersion(remote2, local) {
408
- const r = remote2.split(".").map(Number);
409
- const l = local.split(".").map(Number);
410
- const len = Math.max(r.length, l.length);
411
- for (let i = 0; i < len; i++) {
412
- const rv = r[i] ?? 0;
413
- const lv = l[i] ?? 0;
414
- if (rv > lv) return true;
415
- if (rv < lv) return false;
416
- }
417
- return false;
418
- }
419
- function fallbackTemplate(skillId, domain) {
420
- return `---
421
- name: ${skillId}
422
- description: Skills and context for ${domain}
423
- ---
424
-
425
- # ${skillId}
426
-
427
- Configure your skills and context for ${domain} here.
428
- `;
429
- }
430
- async function discoverSkills(projectDir2) {
431
- const home = homedir();
432
- const searchDirs = [
433
- // Project-local (all known agent frameworks)
434
- join4(projectDir2, ".claude", "skills"),
435
- join4(projectDir2, ".cursor", "skills"),
436
- join4(projectDir2, ".windsurf", "skills"),
437
- join4(projectDir2, ".codex", "skills"),
438
- join4(projectDir2, ".agent", "skills"),
439
- // OpenClaw
440
- join4(projectDir2, ".agents", "skills"),
441
- // User-global
442
- join4(home, ".claude", "skills"),
443
- // Claude Code + Cursor (shared)
444
- join4(home, ".codex", "skills"),
445
- // Codex CLI
446
- join4(home, ".codeium", "windsurf", "skills")
447
- // Windsurf
448
- ];
449
- const seen = /* @__PURE__ */ new Set();
450
- const skills = [];
451
- for (const searchDir of searchDirs) {
452
- const found = await scanSkillDir(searchDir);
453
- for (const skill of found) {
454
- if (!seen.has(skill.id)) {
455
- seen.add(skill.id);
456
- skills.push(skill);
457
- }
458
- }
459
- }
460
- return skills;
461
- }
462
- async function resolveSkillPointers(card, projectDir2) {
463
- const discovered = await discoverSkills(projectDir2);
464
- const skillMap = new Map(discovered.map((s) => [s.id, s]));
465
- const resolvedSkills = card.skills.map((skill) => {
466
- const meta = skillMap.get(skill.id);
467
- if (!meta) return skill;
468
- return {
469
- ...skill,
470
- name: meta.name,
471
- description: meta.description
472
- };
473
- });
474
- return { ...card, skills: resolvedSkills };
475
- }
476
- async function scanSkillDir(dir) {
477
- let entries;
478
- try {
479
- entries = await fs4.readdir(dir);
480
- } catch {
481
- return [];
482
- }
483
- const skills = [];
484
- for (const entry of entries) {
485
- const skillMdPath = join4(dir, entry, "SKILL.md");
486
- try {
487
- const content = await fs4.readFile(skillMdPath, "utf-8");
488
- const meta = parseFrontmatter(content, entry, skillMdPath);
489
- if (meta) skills.push(meta);
490
- } catch {
491
- }
492
- }
493
- return skills;
494
- }
495
- function parseFrontmatter(content, dirName, filePath) {
496
- const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
497
- if (!fmMatch) return null;
498
- const fmBlock = fmMatch[1];
499
- const fields = {};
500
- let inMetadata = false;
501
- let metadataVersion;
502
- for (const line of fmBlock.split("\n")) {
503
- const trimmed = line.trimEnd();
504
- if (trimmed === "metadata:") {
505
- inMetadata = true;
506
- continue;
507
- }
508
- if (inMetadata) {
509
- const nestedMatch = trimmed.match(/^\s+(\w+):\s*(.+)$/);
510
- if (nestedMatch) {
511
- if (nestedMatch[1] === "version") {
512
- metadataVersion = nestedMatch[2].trim();
513
- }
514
- continue;
515
- }
516
- inMetadata = false;
517
- }
518
- const kvMatch = trimmed.match(/^(\w+):\s*(.+)$/);
519
- if (kvMatch) {
520
- fields[kvMatch[1]] = kvMatch[2].trim();
521
- }
522
- }
523
- const name = fields["name"];
524
- const description = fields["description"];
525
- if (!name || !description) return null;
526
- return {
527
- id: dirName,
528
- name,
529
- description,
530
- version: metadataVersion,
531
- path: filePath
532
- };
533
- }
534
-
535
- // src/wallet.ts
536
- import { createHmac, createECDH } from "crypto";
537
- import { promises as fs5 } from "fs";
538
- import { join as join5 } from "path";
539
-
540
- // node_modules/@noble/hashes/_u64.js
541
- var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
542
- var _32n = /* @__PURE__ */ BigInt(32);
543
- function fromBig(n, le = false) {
544
- if (le)
545
- return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
546
- return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
547
- }
548
- function split(lst, le = false) {
549
- const len = lst.length;
550
- let Ah = new Uint32Array(len);
551
- let Al = new Uint32Array(len);
552
- for (let i = 0; i < len; i++) {
553
- const { h, l } = fromBig(lst[i], le);
554
- [Ah[i], Al[i]] = [h, l];
555
- }
556
- return [Ah, Al];
557
- }
558
- var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
559
- var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
560
- var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
561
- var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
562
-
563
- // node_modules/@noble/hashes/utils.js
564
- function isBytes(a) {
565
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
566
- }
567
- function anumber(n, title = "") {
568
- if (!Number.isSafeInteger(n) || n < 0) {
569
- const prefix = title && `"${title}" `;
570
- throw new Error(`${prefix}expected integer >= 0, got ${n}`);
571
- }
572
- }
573
- function abytes(value, length, title = "") {
574
- const bytes = isBytes(value);
575
- const len = value?.length;
576
- const needsLen = length !== void 0;
577
- if (!bytes || needsLen && len !== length) {
578
- const prefix = title && `"${title}" `;
579
- const ofLen = needsLen ? ` of length ${length}` : "";
580
- const got = bytes ? `length=${len}` : `type=${typeof value}`;
581
- throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
582
- }
583
- return value;
584
- }
585
- function aexists(instance, checkFinished = true) {
586
- if (instance.destroyed)
587
- throw new Error("Hash instance has been destroyed");
588
- if (checkFinished && instance.finished)
589
- throw new Error("Hash#digest() has already been called");
590
- }
591
- function aoutput(out, instance) {
592
- abytes(out, void 0, "digestInto() output");
593
- const min = instance.outputLen;
594
- if (out.length < min) {
595
- throw new Error('"digestInto() output" expected to be of length >=' + min);
596
- }
597
- }
598
- function u32(arr) {
599
- return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
600
- }
601
- function clean(...arrays) {
602
- for (let i = 0; i < arrays.length; i++) {
603
- arrays[i].fill(0);
604
- }
605
- }
606
- var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
607
- function byteSwap(word) {
608
- return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
609
- }
610
- function byteSwap32(arr) {
611
- for (let i = 0; i < arr.length; i++) {
612
- arr[i] = byteSwap(arr[i]);
613
- }
614
- return arr;
615
- }
616
- var swap32IfBE = isLE ? (u) => u : byteSwap32;
617
- function createHasher(hashCons, info = {}) {
618
- const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
619
- const tmp = hashCons(void 0);
620
- hashC.outputLen = tmp.outputLen;
621
- hashC.blockLen = tmp.blockLen;
622
- hashC.create = (opts) => hashCons(opts);
623
- Object.assign(hashC, info);
624
- return Object.freeze(hashC);
625
- }
626
-
627
- // node_modules/@noble/hashes/sha3.js
628
- var _0n = BigInt(0);
629
- var _1n = BigInt(1);
630
- var _2n = BigInt(2);
631
- var _7n = BigInt(7);
632
- var _256n = BigInt(256);
633
- var _0x71n = BigInt(113);
634
- var SHA3_PI = [];
635
- var SHA3_ROTL = [];
636
- var _SHA3_IOTA = [];
637
- for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
638
- [x, y] = [y, (2 * x + 3 * y) % 5];
639
- SHA3_PI.push(2 * (5 * y + x));
640
- SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
641
- let t = _0n;
642
- for (let j = 0; j < 7; j++) {
643
- R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
644
- if (R & _2n)
645
- t ^= _1n << (_1n << BigInt(j)) - _1n;
646
- }
647
- _SHA3_IOTA.push(t);
648
- }
649
- var IOTAS = split(_SHA3_IOTA, true);
650
- var SHA3_IOTA_H = IOTAS[0];
651
- var SHA3_IOTA_L = IOTAS[1];
652
- var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
653
- var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
654
- function keccakP(s, rounds = 24) {
655
- const B = new Uint32Array(5 * 2);
656
- for (let round = 24 - rounds; round < 24; round++) {
657
- for (let x = 0; x < 10; x++)
658
- B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
659
- for (let x = 0; x < 10; x += 2) {
660
- const idx1 = (x + 8) % 10;
661
- const idx0 = (x + 2) % 10;
662
- const B0 = B[idx0];
663
- const B1 = B[idx0 + 1];
664
- const Th = rotlH(B0, B1, 1) ^ B[idx1];
665
- const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
666
- for (let y = 0; y < 50; y += 10) {
667
- s[x + y] ^= Th;
668
- s[x + y + 1] ^= Tl;
669
- }
670
- }
671
- let curH = s[2];
672
- let curL = s[3];
673
- for (let t = 0; t < 24; t++) {
674
- const shift = SHA3_ROTL[t];
675
- const Th = rotlH(curH, curL, shift);
676
- const Tl = rotlL(curH, curL, shift);
677
- const PI = SHA3_PI[t];
678
- curH = s[PI];
679
- curL = s[PI + 1];
680
- s[PI] = Th;
681
- s[PI + 1] = Tl;
682
- }
683
- for (let y = 0; y < 50; y += 10) {
684
- for (let x = 0; x < 10; x++)
685
- B[x] = s[y + x];
686
- for (let x = 0; x < 10; x++)
687
- s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
688
- }
689
- s[0] ^= SHA3_IOTA_H[round];
690
- s[1] ^= SHA3_IOTA_L[round];
691
- }
692
- clean(B);
693
- }
694
- var Keccak = class _Keccak {
695
- state;
696
- pos = 0;
697
- posOut = 0;
698
- finished = false;
699
- state32;
700
- destroyed = false;
701
- blockLen;
702
- suffix;
703
- outputLen;
704
- enableXOF = false;
705
- rounds;
706
- // NOTE: we accept arguments in bytes instead of bits here.
707
- constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
708
- this.blockLen = blockLen;
709
- this.suffix = suffix;
710
- this.outputLen = outputLen;
711
- this.enableXOF = enableXOF;
712
- this.rounds = rounds;
713
- anumber(outputLen, "outputLen");
714
- if (!(0 < blockLen && blockLen < 200))
715
- throw new Error("only keccak-f1600 function is supported");
716
- this.state = new Uint8Array(200);
717
- this.state32 = u32(this.state);
718
- }
719
- clone() {
720
- return this._cloneInto();
721
- }
722
- keccak() {
723
- swap32IfBE(this.state32);
724
- keccakP(this.state32, this.rounds);
725
- swap32IfBE(this.state32);
726
- this.posOut = 0;
727
- this.pos = 0;
728
- }
729
- update(data) {
730
- aexists(this);
731
- abytes(data);
732
- const { blockLen, state } = this;
733
- const len = data.length;
734
- for (let pos = 0; pos < len; ) {
735
- const take = Math.min(blockLen - this.pos, len - pos);
736
- for (let i = 0; i < take; i++)
737
- state[this.pos++] ^= data[pos++];
738
- if (this.pos === blockLen)
739
- this.keccak();
740
- }
741
- return this;
742
- }
743
- finish() {
744
- if (this.finished)
745
- return;
746
- this.finished = true;
747
- const { state, suffix, pos, blockLen } = this;
748
- state[pos] ^= suffix;
749
- if ((suffix & 128) !== 0 && pos === blockLen - 1)
750
- this.keccak();
751
- state[blockLen - 1] ^= 128;
752
- this.keccak();
753
- }
754
- writeInto(out) {
755
- aexists(this, false);
756
- abytes(out);
757
- this.finish();
758
- const bufferOut = this.state;
759
- const { blockLen } = this;
760
- for (let pos = 0, len = out.length; pos < len; ) {
761
- if (this.posOut >= blockLen)
762
- this.keccak();
763
- const take = Math.min(blockLen - this.posOut, len - pos);
764
- out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
765
- this.posOut += take;
766
- pos += take;
767
- }
768
- return out;
769
- }
770
- xofInto(out) {
771
- if (!this.enableXOF)
772
- throw new Error("XOF is not possible for this instance");
773
- return this.writeInto(out);
774
- }
775
- xof(bytes) {
776
- anumber(bytes);
777
- return this.xofInto(new Uint8Array(bytes));
778
- }
779
- digestInto(out) {
780
- aoutput(out, this);
781
- if (this.finished)
782
- throw new Error("digest() was already called");
783
- this.writeInto(out);
784
- this.destroy();
785
- return out;
786
- }
787
- digest() {
788
- return this.digestInto(new Uint8Array(this.outputLen));
789
- }
790
- destroy() {
791
- this.destroyed = true;
792
- clean(this.state);
793
- }
794
- _cloneInto(to) {
795
- const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
796
- to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
797
- to.state32.set(this.state32);
798
- to.pos = this.pos;
799
- to.posOut = this.posOut;
800
- to.finished = this.finished;
801
- to.rounds = rounds;
802
- to.suffix = suffix;
803
- to.outputLen = outputLen;
804
- to.enableXOF = enableXOF;
805
- to.destroyed = this.destroyed;
806
- return to;
807
- }
808
- };
809
- var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
810
- var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
811
-
812
- // src/wallet.ts
813
- var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
814
- function base58Encode(bytes) {
815
- let leadingZeros = 0;
816
- for (const byte of bytes) {
817
- if (byte === 0) leadingZeros++;
818
- else break;
819
- }
820
- let num = 0n;
821
- for (const byte of bytes) {
822
- num = num * 256n + BigInt(byte);
823
- }
824
- let encoded = "";
825
- while (num > 0n) {
826
- encoded = BASE58_ALPHABET[Number(num % 58n)] + encoded;
827
- num = num / 58n;
828
- }
829
- return BASE58_ALPHABET[0].repeat(leadingZeros) + encoded;
830
- }
831
- function deriveSecp256k1Seed(ed25519Seed) {
832
- const hmac = createHmac("sha512", "secp256k1");
833
- hmac.update(ed25519Seed);
834
- return hmac.digest().subarray(0, 32);
835
- }
836
- function getSecp256k1PublicKey(privateKey) {
837
- const ecdh = createECDH("secp256k1");
838
- ecdh.setPrivateKey(privateKey);
839
- return Buffer.from(ecdh.getPublicKey());
840
- }
841
- function evmAddressFromPublicKey(uncompressedPubKey) {
842
- const pubKeyBody = uncompressedPubKey.subarray(1);
843
- const hash = keccak_256(pubKeyBody);
844
- const addressBytes = hash.slice(hash.length - 20);
845
- return "0x" + Buffer.from(addressBytes).toString("hex");
846
- }
847
- function checksumAddress(address) {
848
- const addr = address.slice(2).toLowerCase();
849
- const hash = Buffer.from(keccak_256(Buffer.from(addr, "utf-8"))).toString(
850
- "hex"
851
- );
852
- let checksummed = "0x";
853
- for (let i = 0; i < addr.length; i++) {
854
- checksummed += parseInt(hash[i], 16) >= 8 ? addr[i].toUpperCase() : addr[i];
855
- }
856
- return checksummed;
857
- }
858
- async function getSolanaAddress(nitDir) {
859
- const pubBase64 = await loadPublicKey(nitDir);
860
- const pubBytes = Buffer.from(pubBase64, "base64");
861
- return base58Encode(pubBytes);
862
- }
863
- async function getEvmAddress(nitDir) {
864
- const keyPath = join5(nitDir, "identity", "agent.key");
865
- const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
866
- const ed25519Seed = Buffer.from(privBase64, "base64");
867
- const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
868
- const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
869
- const rawAddress = evmAddressFromPublicKey(secp256k1PubKey);
870
- return checksumAddress(rawAddress);
871
- }
872
- async function getWalletAddresses(nitDir) {
873
- const [solana, ethereum] = await Promise.all([
874
- getSolanaAddress(nitDir),
875
- getEvmAddress(nitDir)
876
- ]);
877
- return { solana, ethereum };
878
- }
879
- async function loadSecp256k1RawKeyPair(nitDir) {
880
- const keyPath = join5(nitDir, "identity", "agent.key");
881
- const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
882
- const ed25519Seed = Buffer.from(privBase64, "base64");
883
- const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
884
- const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
885
- const keypair = new Uint8Array(64);
886
- keypair.set(secp256k1PrivKey, 0);
887
- keypair.set(secp256k1PubKey.subarray(1, 33), 32);
888
- return keypair;
889
- }
890
-
891
- // src/diff.ts
892
- function diffCards(oldCard, newCard) {
893
- const fields = [];
894
- const scalarFields = [
895
- "protocolVersion",
896
- "name",
897
- "description",
898
- "version",
899
- "url",
900
- "publicKey",
901
- "iconUrl",
902
- "documentationUrl"
903
- ];
904
- for (const field of scalarFields) {
905
- const oldVal = oldCard[field];
906
- const newVal = newCard[field];
907
- if (oldVal !== newVal) {
908
- fields.push({ field, old: oldVal, new: newVal });
909
- }
910
- }
911
- const oldProvider = JSON.stringify(oldCard.provider ?? null);
912
- const newProvider = JSON.stringify(newCard.provider ?? null);
913
- if (oldProvider !== newProvider) {
914
- fields.push({ field: "provider", old: oldCard.provider, new: newCard.provider });
915
- }
916
- const arrayFields = [
917
- "defaultInputModes",
918
- "defaultOutputModes"
919
- ];
920
- for (const field of arrayFields) {
921
- const oldArr = JSON.stringify(oldCard[field]);
922
- const newArr = JSON.stringify(newCard[field]);
923
- if (oldArr !== newArr) {
924
- fields.push({ field, old: oldCard[field], new: newCard[field] });
925
- }
926
- }
927
- const oldSkillMap = new Map(oldCard.skills.map((s) => [s.id, s]));
928
- const newSkillMap = new Map(newCard.skills.map((s) => [s.id, s]));
929
- const skillsAdded = [];
930
- const skillsRemoved = [];
931
- const skillsModified = [];
932
- for (const [id] of newSkillMap) {
933
- if (!oldSkillMap.has(id)) {
934
- skillsAdded.push(id);
935
- }
936
- }
937
- for (const [id] of oldSkillMap) {
938
- if (!newSkillMap.has(id)) {
939
- skillsRemoved.push(id);
940
- }
941
- }
942
- for (const [id, newSkill] of newSkillMap) {
943
- const oldSkill = oldSkillMap.get(id);
944
- if (oldSkill && !skillsEqual(oldSkill, newSkill)) {
945
- skillsModified.push(id);
946
- }
947
- }
948
- const changed = fields.length > 0 || skillsAdded.length > 0 || skillsRemoved.length > 0 || skillsModified.length > 0;
949
- return { changed, fields, skillsAdded, skillsRemoved, skillsModified };
950
- }
951
- function formatDiff(diff2) {
952
- if (!diff2.changed) {
953
- return "No changes.";
954
- }
955
- const lines = [];
956
- for (const fd of diff2.fields) {
957
- const oldStr = formatValue(fd.old);
958
- const newStr = formatValue(fd.new);
959
- lines.push(` ${fd.field}:`);
960
- lines.push(`\x1B[31m - ${oldStr}\x1B[0m`);
961
- lines.push(`\x1B[32m + ${newStr}\x1B[0m`);
962
- }
963
- for (const id of diff2.skillsAdded) {
964
- lines.push(`\x1B[32m + skill: ${id}\x1B[0m`);
965
- }
966
- for (const id of diff2.skillsRemoved) {
967
- lines.push(`\x1B[31m - skill: ${id}\x1B[0m`);
968
- }
969
- for (const id of diff2.skillsModified) {
970
- lines.push(`\x1B[33m ~ skill: ${id} (modified)\x1B[0m`);
971
- }
972
- return lines.join("\n");
973
- }
974
- function skillsEqual(a, b) {
975
- return JSON.stringify(a) === JSON.stringify(b);
976
- }
977
- function formatValue(val) {
978
- if (val === void 0) return "(unset)";
979
- if (val === null) return "(null)";
980
- if (typeof val === "string") return val;
981
- return JSON.stringify(val);
982
- }
983
-
984
- // src/remote.ts
985
- import { createHash as createHash3 } from "crypto";
986
- function sha256Hex(data) {
987
- return createHash3("sha256").update(data, "utf-8").digest("hex");
988
- }
989
- async function buildAuthHeaders(nitDir, method, path, body) {
990
- const agentId = await loadAgentId(nitDir);
991
- const timestamp = Math.floor(Date.now() / 1e3).toString();
992
- let message = `${method}
993
- ${path}
994
- ${agentId}
995
- ${timestamp}`;
996
- if (body !== void 0) {
997
- message += `
998
- ${sha256Hex(body)}`;
999
- }
1000
- const signature = await signMessage(nitDir, message);
1001
- return {
1002
- "X-Nit-Agent-Id": agentId,
1003
- "X-Nit-Timestamp": timestamp,
1004
- "X-Nit-Signature": signature
1005
- };
1006
- }
1007
- async function pushBranch(nitDir, apiBase, branch2, cardJson, commitHash) {
1008
- const path = `/agent-card/branches/${encodeURIComponent(branch2)}`;
1009
- const body = JSON.stringify({ card_json: cardJson, commit_hash: commitHash });
1010
- try {
1011
- const authHeaders = await buildAuthHeaders(nitDir, "PUT", path, body);
1012
- const res = await fetch(`${apiBase}${path}`, {
1013
- method: "PUT",
1014
- headers: {
1015
- "Content-Type": "application/json",
1016
- ...authHeaders
1017
- },
1018
- body
1019
- });
1020
- if (!res.ok) {
1021
- const text = await res.text();
1022
- return {
1023
- branch: branch2,
1024
- commitHash,
1025
- remoteUrl: apiBase,
1026
- success: false,
1027
- error: `HTTP ${res.status}: ${text}`
1028
- };
1029
- }
1030
- return { branch: branch2, commitHash, remoteUrl: apiBase, success: true };
1031
- } catch (err) {
1032
- return {
1033
- branch: branch2,
1034
- commitHash,
1035
- remoteUrl: apiBase,
1036
- success: false,
1037
- error: err instanceof Error ? err.message : String(err)
1038
- };
1039
- }
1040
- }
1041
- async function fetchBranchCard(cardUrl, branch2, nitDir) {
1042
- const baseUrl = cardUrl.replace(/\/$/, "");
1043
- let url = `${baseUrl}/.well-known/agent-card.json`;
1044
- if (branch2 !== "main") {
1045
- url += `?branch=${encodeURIComponent(branch2)}`;
1046
- }
1047
- const res = await fetch(url);
1048
- if (res.ok) {
1049
- return await res.json();
1050
- }
1051
- if (res.status === 401 && branch2 !== "main") {
1052
- if (!nitDir) {
1053
- throw new Error(
1054
- `Branch "${branch2}" requires authentication. Provide nitDir for signing.`
1055
- );
1056
- }
1057
- const challengeData = await res.json();
1058
- const signature = await signChallenge(nitDir, challengeData.challenge);
1059
- const authRes = await fetch(url, {
1060
- headers: {
1061
- "X-Nit-Challenge": challengeData.challenge,
1062
- "X-Nit-Signature": signature
1063
- }
1064
- });
1065
- if (!authRes.ok) {
1066
- const body = await authRes.text();
1067
- throw new Error(
1068
- `Failed to fetch branch "${branch2}" after challenge: HTTP ${authRes.status} ${body}`
1069
- );
1070
- }
1071
- return await authRes.json();
1072
- }
1073
- throw new Error(`Failed to fetch card: HTTP ${res.status}`);
1074
- }
1075
-
1076
- // src/config.ts
1077
- import { promises as fs6 } from "fs";
1078
- import { join as join6 } from "path";
1079
- var CONFIG_FILE = "config";
1080
- async function readConfig(nitDir) {
1081
- const configPath = join6(nitDir, CONFIG_FILE);
1082
- let raw;
1083
- try {
1084
- raw = await fs6.readFile(configPath, "utf-8");
1085
- } catch {
1086
- return { remotes: {} };
1087
- }
1088
- return parseConfig(raw);
1089
- }
1090
- async function writeConfig(nitDir, config) {
1091
- const configPath = join6(nitDir, CONFIG_FILE);
1092
- await fs6.writeFile(configPath, serializeConfig(config), "utf-8");
1093
- }
1094
- async function getRemoteUrl(nitDir, remoteName) {
1095
- const config = await readConfig(nitDir);
1096
- return config.remotes[remoteName]?.url ?? null;
1097
- }
1098
- async function getSkillsDir(nitDir) {
1099
- const config = await readConfig(nitDir);
1100
- return config.skillsDir ?? null;
1101
- }
1102
- function parseConfig(raw) {
1103
- const remotes = {};
1104
- let currentSection = null;
1105
- let currentRemote = null;
1106
- let skillsDir;
1107
- for (const line of raw.split("\n")) {
1108
- const trimmed = line.trim();
1109
- if (trimmed === "" || trimmed.startsWith("#")) continue;
1110
- const remoteMatch = trimmed.match(/^\[remote\s+"([^"]+)"\]$/);
1111
- if (remoteMatch) {
1112
- currentSection = "remote";
1113
- currentRemote = remoteMatch[1];
1114
- if (!remotes[currentRemote]) {
1115
- remotes[currentRemote] = {};
1116
- }
1117
- continue;
1118
- }
1119
- if (trimmed === "[skills]") {
1120
- currentSection = "skills";
1121
- currentRemote = null;
1122
- continue;
1123
- }
1124
- const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
1125
- if (kvMatch) {
1126
- const [, key, value] = kvMatch;
1127
- if (currentSection === "remote" && currentRemote !== null) {
1128
- if (key === "url") {
1129
- remotes[currentRemote].url = value.trim();
1130
- } else if (key === "credential") {
1131
- remotes[currentRemote].credential = value.trim();
1132
- }
1133
- } else if (currentSection === "skills") {
1134
- if (key === "dir") {
1135
- skillsDir = value.trim();
1136
- }
1137
- }
1138
- }
1139
- }
1140
- return { remotes, skillsDir };
1141
- }
1142
- function serializeConfig(config) {
1143
- const lines = [];
1144
- for (const [name, remote2] of Object.entries(config.remotes)) {
1145
- lines.push(`[remote "${name}"]`);
1146
- if (remote2.url) {
1147
- lines.push(` url = ${remote2.url}`);
1148
- }
1149
- if (remote2.credential) {
1150
- lines.push(` credential = ${remote2.credential}`);
1151
- }
1152
- lines.push("");
1153
- }
1154
- if (config.skillsDir) {
1155
- lines.push("[skills]");
1156
- lines.push(` dir = ${config.skillsDir}`);
1157
- lines.push("");
1158
- }
1159
- return lines.join("\n");
1160
- }
1161
-
1162
- // src/index.ts
1163
- var NIT_DIR = ".nit";
1164
- var CARD_FILE = "agent-card.json";
1165
- var DEFAULT_API_BASE = "https://api.newtype-ai.org";
1166
- function findNitDir(startDir) {
1167
- let dir = resolve2(startDir || process.cwd());
1168
- while (true) {
1169
- const candidate = join7(dir, NIT_DIR);
1170
- try {
1171
- const s = statSync(candidate);
1172
- if (s.isDirectory()) return candidate;
1173
- } catch {
1174
- }
1175
- const parent = resolve2(dir, "..");
1176
- if (parent === dir) {
1177
- throw new Error(
1178
- "Not a nit repository (or any parent directory). Run `nit init` first."
1179
- );
1180
- }
1181
- dir = parent;
1182
- }
1183
- }
1184
- function projectDir(nitDir) {
1185
- return resolve2(nitDir, "..");
1186
- }
1187
- async function readWorkingCard(nitDir) {
1188
- const cardPath = join7(projectDir(nitDir), CARD_FILE);
1189
- try {
1190
- const raw = await fs7.readFile(cardPath, "utf-8");
1191
- return JSON.parse(raw);
1192
- } catch {
1193
- throw new Error(`Cannot read ${CARD_FILE}. Does it exist?`);
1194
- }
1195
- }
1196
- async function writeWorkingCard(nitDir, card) {
1197
- const cardPath = join7(projectDir(nitDir), CARD_FILE);
1198
- await fs7.writeFile(cardPath, JSON.stringify(card, null, 2) + "\n", "utf-8");
1199
- }
1200
- async function getCardAtCommit(nitDir, commitHash) {
1201
- const commitRaw = await readObject(nitDir, commitHash);
1202
- const commit2 = parseCommit(commitHash, commitRaw);
1203
- const cardRaw = await readObject(nitDir, commit2.card);
1204
- return JSON.parse(cardRaw);
1205
- }
1206
- async function getAuthorName(nitDir) {
1207
- try {
1208
- const card = await readWorkingCard(nitDir);
1209
- return card.name || basename2(projectDir(nitDir));
1210
- } catch {
1211
- return basename2(projectDir(nitDir));
1212
- }
1213
- }
1214
- async function init(options) {
1215
- const projDir = resolve2(options?.projectDir || process.cwd());
1216
- const nitDir = join7(projDir, NIT_DIR);
1217
- try {
1218
- await fs7.access(nitDir);
1219
- throw new Error("Already initialized. .nit/ directory exists.");
1220
- } catch (err) {
1221
- if (err instanceof Error && err.message.startsWith("Already")) throw err;
1222
- }
1223
- await fs7.mkdir(join7(nitDir, "objects"), { recursive: true });
1224
- await fs7.mkdir(join7(nitDir, "refs", "heads"), { recursive: true });
1225
- await fs7.mkdir(join7(nitDir, "refs", "remote"), { recursive: true });
1226
- await fs7.mkdir(join7(nitDir, "identity"), { recursive: true });
1227
- await fs7.mkdir(join7(nitDir, "logs"), { recursive: true });
1228
- const { publicKey: pubBase64 } = await generateKeypair(nitDir);
1229
- const publicKeyField = formatPublicKeyField(pubBase64);
1230
- const agentId = deriveAgentId(publicKeyField);
1231
- await saveAgentId(nitDir, agentId);
1232
- const cardPath = join7(projDir, CARD_FILE);
1233
- let card;
1234
- let skillsFound = [];
1235
- try {
1236
- const raw = await fs7.readFile(cardPath, "utf-8");
1237
- card = JSON.parse(raw);
1238
- card.publicKey = publicKeyField;
1239
- skillsFound = card.skills.map((s) => s.id);
1240
- } catch {
1241
- const discovered = await discoverSkills(projDir);
1242
- skillsFound = discovered.map((s) => s.id);
1243
- card = {
1244
- protocolVersion: "0.3.0",
1245
- name: basename2(projDir),
1246
- description: `AI agent working in ${basename2(projDir)}`,
1247
- version: "1.0.0",
1248
- url: "",
1249
- publicKey: publicKeyField,
1250
- defaultInputModes: ["text/plain"],
1251
- defaultOutputModes: ["text/plain"],
1252
- skills: discovered.map((s) => ({
1253
- id: s.id,
1254
- name: s.name,
1255
- description: s.description
1256
- }))
1257
- };
1258
- }
1259
- if (!card.url) {
1260
- card.url = `https://agent-${agentId}.newtype-ai.org`;
1261
- }
1262
- await writeWorkingCard(nitDir, card);
1263
- const cardJson = JSON.stringify(card, null, 2);
1264
- const cardHash = await writeObject(nitDir, "card", cardJson);
1265
- const commitContent = serializeCommit({
1266
- card: cardHash,
1267
- parent: null,
1268
- author: card.name,
1269
- timestamp: Math.floor(Date.now() / 1e3),
1270
- message: "Initial commit"
1271
- });
1272
- const commitHash = await writeObject(nitDir, "commit", commitContent);
1273
- await setBranch(nitDir, "main", commitHash);
1274
- await setHead(nitDir, "main");
1275
- await fs7.writeFile(join7(nitDir, "logs", "HEAD"), "", "utf-8");
1276
- const skillsDir = await discoverSkillsDir(projDir);
1277
- await writeConfig(nitDir, {
1278
- remotes: { origin: { url: DEFAULT_API_BASE } },
1279
- skillsDir
1280
- });
1281
- const walletAddresses = await getWalletAddresses(nitDir);
1282
- return {
1283
- agentId,
1284
- publicKey: publicKeyField,
1285
- cardUrl: card.url,
1286
- walletAddresses,
1287
- skillsFound,
1288
- skillsDir
1289
- };
1290
- }
1291
- async function status(options) {
1292
- const nitDir = findNitDir(options?.projectDir);
1293
- const currentBranch = await getCurrentBranch(nitDir);
1294
- const pubBase64 = await loadPublicKey(nitDir);
1295
- const publicKey = formatPublicKeyField(pubBase64);
1296
- const agentId = await loadAgentId(nitDir);
1297
- const workingCard = await readWorkingCard(nitDir);
1298
- const cardUrl = workingCard.url || `https://agent-${agentId}.newtype-ai.org`;
1299
- let uncommittedChanges = null;
1300
- try {
1301
- const headHash = await resolveHead(nitDir);
1302
- const headCard = await getCardAtCommit(nitDir, headHash);
1303
- const workingCard2 = await readWorkingCard(nitDir);
1304
- const d = diffCards(headCard, workingCard2);
1305
- if (d.changed) {
1306
- uncommittedChanges = d;
1307
- }
1308
- } catch {
1309
- }
1310
- const branches = await listBranches(nitDir);
1311
- const branchStatus = [];
1312
- for (const b of branches) {
1313
- const remoteHash = await getRemoteRef(nitDir, "origin", b.name);
1314
- let ahead = 0;
1315
- if (remoteHash && remoteHash !== b.commitHash) {
1316
- let hash = b.commitHash;
1317
- while (hash && hash !== remoteHash) {
1318
- ahead++;
1319
- try {
1320
- const raw = await readObject(nitDir, hash);
1321
- const c = parseCommit(hash, raw);
1322
- hash = c.parent;
1323
- } catch {
1324
- break;
1325
- }
1326
- }
1327
- } else if (!remoteHash) {
1328
- let hash = b.commitHash;
1329
- while (hash) {
1330
- ahead++;
1331
- try {
1332
- const raw = await readObject(nitDir, hash);
1333
- const c = parseCommit(hash, raw);
1334
- hash = c.parent;
1335
- } catch {
1336
- break;
1337
- }
1338
- }
1339
- }
1340
- branchStatus.push({ name: b.name, ahead, behind: 0 });
1341
- }
1342
- const walletAddresses = await getWalletAddresses(nitDir);
1343
- return {
1344
- agentId,
1345
- cardUrl,
1346
- branch: currentBranch,
1347
- publicKey,
1348
- walletAddresses,
1349
- uncommittedChanges,
1350
- branches: branchStatus
1351
- };
1352
- }
1353
- async function sign2(message, options) {
1354
- const nitDir = findNitDir(options?.projectDir);
1355
- return signMessage(nitDir, message);
1356
- }
1357
- async function loginPayload(domain, options) {
1358
- const nitDir = findNitDir(options?.projectDir);
1359
- let switchedBranch;
1360
- let createdSkill;
1361
- const currentBranch = await getCurrentBranch(nitDir);
1362
- if (currentBranch !== domain) {
1363
- const isNew = !await getBranch(nitDir, domain);
1364
- if (isNew) {
1365
- const headHash = await resolveHead(nitDir);
1366
- await setBranch(nitDir, domain, headHash);
1367
- }
1368
- await checkout(domain, options);
1369
- switchedBranch = domain;
1370
- }
1371
- const projectDir2 = dirname2(nitDir);
1372
- const skillsDir = await getSkillsDir(nitDir) ?? await discoverSkillsDir(projectDir2);
1373
- if (skillsDir) {
1374
- const skillId = await createSkillTemplate(skillsDir, domain);
1375
- const card = await readWorkingCard(nitDir);
1376
- if (!card.skills.some((s) => s.id === skillId)) {
1377
- card.skills.push({ id: skillId });
1378
- await writeWorkingCard(nitDir, card);
1379
- createdSkill = skillId;
1380
- }
1381
- }
1382
- const agentId = await loadAgentId(nitDir);
1383
- const timestamp = Math.floor(Date.now() / 1e3);
1384
- const message = `${agentId}
1385
- ${domain}
1386
- ${timestamp}`;
1387
- const signature = await signMessage(nitDir, message);
1388
- return { agent_id: agentId, domain, timestamp, signature, switchedBranch, createdSkill };
1389
- }
1390
- async function commit(message, options) {
1391
- const nitDir = findNitDir(options?.projectDir);
1392
- const projDir = projectDir(nitDir);
1393
- let card = await readWorkingCard(nitDir);
1394
- card = await resolveSkillPointers(card, projDir);
1395
- const pubBase64 = await loadPublicKey(nitDir);
1396
- card.publicKey = formatPublicKeyField(pubBase64);
1397
- await writeWorkingCard(nitDir, card);
1398
- const cardJson = JSON.stringify(card, null, 2);
1399
- const cardHash = await writeObject(nitDir, "card", cardJson);
1400
- const currentBranch = await getCurrentBranch(nitDir);
1401
- const parentHash = await getBranch(nitDir, currentBranch);
1402
- if (parentHash) {
1403
- const parentRaw = await readObject(nitDir, parentHash);
1404
- const parentCommit = parseCommit(parentHash, parentRaw);
1405
- if (parentCommit.card === cardHash) {
1406
- throw new Error("Nothing to commit \u2014 agent card is unchanged.");
1407
- }
1408
- }
1409
- const author = await getAuthorName(nitDir);
1410
- const commitContent = serializeCommit({
1411
- card: cardHash,
1412
- parent: parentHash,
1413
- author,
1414
- timestamp: Math.floor(Date.now() / 1e3),
1415
- message
1416
- });
1417
- const commitHash = await writeObject(nitDir, "commit", commitContent);
1418
- await setBranch(nitDir, currentBranch, commitHash);
1419
- return {
1420
- type: "commit",
1421
- hash: commitHash,
1422
- card: cardHash,
1423
- parent: parentHash,
1424
- author,
1425
- timestamp: Math.floor(Date.now() / 1e3),
1426
- message
1427
- };
1428
- }
1429
- async function log(options) {
1430
- const nitDir = findNitDir(options?.projectDir);
1431
- const currentBranch = await getCurrentBranch(nitDir);
1432
- let hash = await getBranch(nitDir, currentBranch);
1433
- const commits = [];
1434
- const limit = options?.count ?? 50;
1435
- while (hash && commits.length < limit) {
1436
- const raw = await readObject(nitDir, hash);
1437
- const c = parseCommit(hash, raw);
1438
- commits.push(c);
1439
- hash = c.parent;
1440
- }
1441
- return commits;
1442
- }
1443
- async function diff(target, options) {
1444
- const nitDir = findNitDir(options?.projectDir);
1445
- if (!target) {
1446
- const headHash2 = await resolveHead(nitDir);
1447
- const headCard2 = await getCardAtCommit(nitDir, headHash2);
1448
- const workingCard = await readWorkingCard(nitDir);
1449
- return diffCards(headCard2, workingCard);
1450
- }
1451
- const targetBranchHash = await getBranch(nitDir, target);
1452
- const headHash = await resolveHead(nitDir);
1453
- const headCard = await getCardAtCommit(nitDir, headHash);
1454
- if (targetBranchHash) {
1455
- const targetCard = await getCardAtCommit(nitDir, targetBranchHash);
1456
- return diffCards(headCard, targetCard);
1457
- }
1458
- if (/^[0-9a-f]{64}$/.test(target)) {
1459
- const targetCard = await getCardAtCommit(nitDir, target);
1460
- return diffCards(headCard, targetCard);
1461
- }
1462
- throw new Error(
1463
- `Unknown target "${target}". Provide a branch name or commit hash.`
1464
- );
1465
- }
1466
- async function branch(name, options) {
1467
- const nitDir = findNitDir(options?.projectDir);
1468
- if (name) {
1469
- const existing = await getBranch(nitDir, name);
1470
- if (existing) {
1471
- throw new Error(`Branch "${name}" already exists.`);
1472
- }
1473
- const headHash = await resolveHead(nitDir);
1474
- await setBranch(nitDir, name, headHash);
1475
- }
1476
- return listBranches(nitDir);
1477
- }
1478
- async function checkout(branchName, options) {
1479
- const nitDir = findNitDir(options?.projectDir);
1480
- try {
1481
- const headHash = await resolveHead(nitDir);
1482
- const headCard = await getCardAtCommit(nitDir, headHash);
1483
- const workingCard = await readWorkingCard(nitDir);
1484
- const d = diffCards(headCard, workingCard);
1485
- if (d.changed) {
1486
- throw new Error(
1487
- "You have uncommitted changes. Commit or discard them before switching branches."
1488
- );
1489
- }
1490
- } catch (err) {
1491
- if (err instanceof Error && err.message.includes("uncommitted changes")) {
1492
- throw err;
1493
- }
1494
- }
1495
- const targetHash = await getBranch(nitDir, branchName);
1496
- if (!targetHash) {
1497
- throw new Error(`Branch "${branchName}" does not exist.`);
1498
- }
1499
- const targetCard = await getCardAtCommit(nitDir, targetHash);
1500
- await writeWorkingCard(nitDir, targetCard);
1501
- await setHead(nitDir, branchName);
1502
- }
1503
- async function push(options) {
1504
- const nitDir = findNitDir(options?.projectDir);
1505
- const remoteName = options?.remoteName || "origin";
1506
- const apiBase = await getRemoteUrl(nitDir, remoteName) || DEFAULT_API_BASE;
1507
- const branches = await listBranches(nitDir);
1508
- const currentBranch = await getCurrentBranch(nitDir);
1509
- const toPush = options?.all ? branches : branches.filter((b) => b.name === currentBranch);
1510
- if (toPush.length === 0) {
1511
- throw new Error("No branches to push.");
1512
- }
1513
- const results = [];
1514
- for (const b of toPush) {
1515
- const commitRaw = await readObject(nitDir, b.commitHash);
1516
- const c = parseCommit(b.commitHash, commitRaw);
1517
- const cardJson = await readObject(nitDir, c.card);
1518
- const result = await pushBranch(
1519
- nitDir,
1520
- apiBase,
1521
- b.name,
1522
- cardJson,
1523
- b.commitHash
1524
- );
1525
- if (result.success) {
1526
- await setRemoteRef(nitDir, remoteName, b.name, b.commitHash);
1527
- }
1528
- results.push(result);
1529
- }
1530
- return results;
1531
- }
1532
- async function remote(options) {
1533
- const nitDir = findNitDir(options?.projectDir);
1534
- const remoteUrl = await getRemoteUrl(nitDir, "origin");
1535
- const agentId = await loadAgentId(nitDir);
1536
- return {
1537
- name: "origin",
1538
- url: remoteUrl || DEFAULT_API_BASE,
1539
- agentId
1540
- };
1541
- }
1542
- async function remoteAdd(name, url, options) {
1543
- const nitDir = findNitDir(options?.projectDir);
1544
- const config = await readConfig(nitDir);
1545
- if (config.remotes[name]) {
1546
- throw new Error(
1547
- `Remote "${name}" already exists. Use 'nit remote set-url ${name} <url>' to change it.`
1548
- );
1549
- }
1550
- config.remotes[name] = { url };
1551
- await writeConfig(nitDir, config);
1552
- }
1553
- async function remoteSetUrl(name, url, options) {
1554
- const nitDir = findNitDir(options?.projectDir);
1555
- const config = await readConfig(nitDir);
1556
- if (!config.remotes[name]) {
1557
- throw new Error(
1558
- `Remote "${name}" does not exist. Use 'nit remote add ${name} <url>' to create it.`
1559
- );
1560
- }
1561
- config.remotes[name].url = url;
1562
- await writeConfig(nitDir, config);
1563
- }
1564
-
1565
- export {
1566
- loadRawKeyPair,
1567
- formatPublicKeyField,
1568
- parsePublicKeyField,
1569
- signChallenge,
1570
- signMessage,
1571
- NIT_NAMESPACE,
1572
- deriveAgentId,
1573
- loadAgentId,
1574
- base58Encode,
1575
- getSolanaAddress,
1576
- getEvmAddress,
1577
- getWalletAddresses,
1578
- loadSecp256k1RawKeyPair,
1579
- diffCards,
1580
- formatDiff,
1581
- fetchBranchCard,
1582
- findNitDir,
1583
- init,
1584
- status,
1585
- sign2 as sign,
1586
- loginPayload,
1587
- commit,
1588
- log,
1589
- diff,
1590
- branch,
1591
- checkout,
1592
- push,
1593
- remote,
1594
- remoteAdd,
1595
- remoteSetUrl
1596
- };
1597
- /*! Bundled license information:
1598
-
1599
- @noble/hashes/utils.js:
1600
- (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
1601
- */