@newtype-ai/nit 0.4.9 → 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,8 +1,19 @@
1
1
  // nit — version control for agent cards
2
+ import {
3
+ deriveAgentId,
4
+ formatPublicKeyField,
5
+ generateKeypair,
6
+ loadAgentId,
7
+ loadPrivateKey,
8
+ loadPublicKey,
9
+ pushBranch,
10
+ saveAgentId,
11
+ signMessage
12
+ } from "./chunk-M6SR6QMR.js";
2
13
 
3
14
  // 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";
15
+ import { promises as fs6, statSync } from "fs";
16
+ import { join as join6, basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
6
17
 
7
18
  // src/objects.ts
8
19
  import { createHash } from "crypto";
@@ -168,156 +179,9 @@ async function getRemoteRef(nitDir, remote2, branch2) {
168
179
  }
169
180
  }
170
181
 
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
182
  // src/skills.ts
319
- import { promises as fs4 } from "fs";
320
- import { join as join4, resolve } from "path";
183
+ import { promises as fs3 } from "fs";
184
+ import { join as join3, resolve } from "path";
321
185
  import { homedir } from "os";
322
186
  var FRAMEWORK_MARKERS = [
323
187
  { marker: ".claude", skillsPath: ".claude/skills" },
@@ -338,36 +202,36 @@ async function discoverSkillsDir(projectDir2) {
338
202
  const idx = absProject.indexOf(`/${marker}`);
339
203
  if (idx !== -1) {
340
204
  const root = absProject.slice(0, idx);
341
- return join4(root, skillsPath);
205
+ return join3(root, skillsPath);
342
206
  }
343
207
  }
344
208
  for (const { marker, skillsPath } of FRAMEWORK_MARKERS) {
345
209
  try {
346
- const stat = await fs4.stat(join4(absProject, marker));
210
+ const stat = await fs3.stat(join3(absProject, marker));
347
211
  if (stat.isDirectory()) {
348
- return join4(absProject, skillsPath);
212
+ return join3(absProject, skillsPath);
349
213
  }
350
214
  } catch {
351
215
  }
352
216
  }
353
217
  for (const { marker, skillsPath } of GLOBAL_SKILLS_DIRS) {
354
218
  try {
355
- const stat = await fs4.stat(join4(home, marker));
219
+ const stat = await fs3.stat(join3(home, marker));
356
220
  if (stat.isDirectory()) {
357
- return join4(home, skillsPath);
221
+ return join3(home, skillsPath);
358
222
  }
359
223
  } catch {
360
224
  }
361
225
  }
362
- return join4(absProject, ".agents", "skills");
226
+ return join3(absProject, ".agents", "skills");
363
227
  }
364
228
  async function createSkillTemplate(skillsDir, domain) {
365
229
  const skillId = domain.replace(/\./g, "-");
366
- const skillDir = join4(skillsDir, skillId);
367
- const skillPath = join4(skillDir, "SKILL.md");
230
+ const skillDir = join3(skillsDir, skillId);
231
+ const skillPath = join3(skillDir, "SKILL.md");
368
232
  let localVersion;
369
233
  try {
370
- const existing = await fs4.readFile(skillPath, "utf-8");
234
+ const existing = await fs3.readFile(skillPath, "utf-8");
371
235
  localVersion = parseVersion(existing);
372
236
  } catch {
373
237
  }
@@ -392,8 +256,8 @@ async function createSkillTemplate(skillsDir, domain) {
392
256
  return skillId;
393
257
  }
394
258
  }
395
- await fs4.mkdir(skillDir, { recursive: true });
396
- await fs4.writeFile(
259
+ await fs3.mkdir(skillDir, { recursive: true });
260
+ await fs3.writeFile(
397
261
  skillPath,
398
262
  remoteContent ?? fallbackTemplate(skillId, domain),
399
263
  "utf-8"
@@ -433,17 +297,17 @@ async function discoverSkills(projectDir2) {
433
297
  const home = homedir();
434
298
  const searchDirs = [
435
299
  // Project-local (all known agent frameworks)
436
- join4(projectDir2, ".claude", "skills"),
437
- join4(projectDir2, ".cursor", "skills"),
438
- join4(projectDir2, ".windsurf", "skills"),
439
- join4(projectDir2, ".codex", "skills"),
440
- join4(projectDir2, ".agents", "skills"),
300
+ join3(projectDir2, ".claude", "skills"),
301
+ join3(projectDir2, ".cursor", "skills"),
302
+ join3(projectDir2, ".windsurf", "skills"),
303
+ join3(projectDir2, ".codex", "skills"),
304
+ join3(projectDir2, ".agents", "skills"),
441
305
  // User-global
442
- join4(home, ".claude", "skills"),
306
+ join3(home, ".claude", "skills"),
443
307
  // Claude Code + Cursor (shared)
444
- join4(home, ".codex", "skills"),
308
+ join3(home, ".codex", "skills"),
445
309
  // Codex CLI
446
- join4(home, ".codeium", "windsurf", "skills")
310
+ join3(home, ".codeium", "windsurf", "skills")
447
311
  // Windsurf
448
312
  ];
449
313
  const seen = /* @__PURE__ */ new Set();
@@ -473,18 +337,166 @@ async function resolveSkillPointers(card, projectDir2) {
473
337
  });
474
338
  return { ...card, skills: resolvedSkills };
475
339
  }
340
+ var AUTH_TEMPLATES = {
341
+ google: (domain, account) => `## Authentication
342
+
343
+ To access ${domain}, use browser profile="user" to reuse the existing Google session (${account}).
344
+
345
+ **Stage 1 \u2014 session reuse:** Open the browser with profile="user" and navigate to ${domain}. If the browser's existing session cookies are valid, you will be logged in automatically. Proceed without any login action.
346
+
347
+ **Stage 2 \u2014 OAuth consent (if login page appears):**
348
+ 1. Look for a "Sign in with Google" or "Continue with Google" button and click it
349
+ 2. You will be redirected to accounts.google.com
350
+ 3. If an account picker appears, select ${account}
351
+ 4. On the consent page, click "Allow", "Continue", or "Authorize"
352
+ 5. Wait for redirect back to ${domain}
353
+
354
+ IMPORTANT: You MUST use browser profile="user" to attach to the human's Chrome session via Chrome DevTools MCP. Do NOT use the default isolated browser profile. Do NOT enter any credentials. Do NOT ask the human for confirmation. Just click through the consent flow.`,
355
+ github: (domain, account) => `## Authentication
356
+
357
+ To access ${domain}, use browser profile="user" to reuse the existing GitHub session (${account}).
358
+
359
+ **Stage 1 \u2014 session reuse:** Open the browser with profile="user" and navigate to ${domain}. If the browser's existing session cookies are valid, you will be logged in automatically. Proceed without any login action.
360
+
361
+ **Stage 2 \u2014 OAuth consent (if login page appears):**
362
+ 1. Look for a "Sign in with GitHub" or "Continue with GitHub" button and click it
363
+ 2. You will be redirected to github.com/login/oauth/authorize
364
+ 3. On the authorization page, click "Authorize [app name]"
365
+ 4. Wait for redirect back to ${domain}
366
+
367
+ IMPORTANT: You MUST use browser profile="user" to attach to the human's Chrome session via Chrome DevTools MCP. Do NOT use the default isolated browser profile. Do NOT enter any credentials. Do NOT ask the human for confirmation. Just click through the consent flow.`,
368
+ x: (domain, account) => `## Authentication
369
+
370
+ To access ${domain}, use browser profile="user" to reuse the existing X session (${account}).
371
+
372
+ **Stage 1 \u2014 session reuse:** Open the browser with profile="user" and navigate to ${domain}. If the browser's existing session cookies are valid, you will be logged in automatically. Proceed without any login action.
373
+
374
+ **Stage 2 \u2014 OAuth consent (if login page appears):**
375
+ 1. Look for a "Sign in with X", "Sign in with Twitter", or "Continue with X" button and click it
376
+ 2. You will be redirected to x.com or api.twitter.com
377
+ 3. On the authorization page, click "Authorize app"
378
+ 4. Wait for redirect back to ${domain}
379
+
380
+ IMPORTANT: You MUST use browser profile="user" to attach to the human's Chrome session via Chrome DevTools MCP. Do NOT use the default isolated browser profile. Do NOT enter any credentials. Do NOT ask the human for confirmation. Just click through the consent flow.`
381
+ };
382
+ function generateAuthInstructions(provider, account, domain) {
383
+ return AUTH_TEMPLATES[provider](domain, account);
384
+ }
385
+ async function updateSkillAuth(skillsDir, domain, auth) {
386
+ const skillId = domain.replace(/\./g, "-");
387
+ const skillDir = join3(skillsDir, skillId);
388
+ const skillPath = join3(skillDir, "SKILL.md");
389
+ await fs3.mkdir(skillDir, { recursive: true });
390
+ let content;
391
+ try {
392
+ content = await fs3.readFile(skillPath, "utf-8");
393
+ } catch {
394
+ content = `---
395
+ name: ${skillId}
396
+ description: Skills and context for ${domain}
397
+ ---
398
+
399
+ # ${skillId}
400
+ `;
401
+ }
402
+ content = upsertAuthFrontmatter(content, auth);
403
+ const instructions = generateAuthInstructions(auth.provider, auth.account, domain);
404
+ content = upsertAuthBody(content, instructions);
405
+ await fs3.writeFile(skillPath, content, "utf-8");
406
+ return skillId;
407
+ }
408
+ async function readSkillAuth(skillsDir, domain) {
409
+ const skillId = domain.replace(/\./g, "-");
410
+ const skillPath = join3(skillsDir, skillId, "SKILL.md");
411
+ let content;
412
+ try {
413
+ content = await fs3.readFile(skillPath, "utf-8");
414
+ } catch {
415
+ return null;
416
+ }
417
+ return parseAuthFrontmatter(content);
418
+ }
419
+ function upsertAuthFrontmatter(content, auth) {
420
+ const fmMatch = content.match(/^(---\r?\n)([\s\S]*?)(\r?\n---)/);
421
+ if (!fmMatch) {
422
+ const fm = `---
423
+ name: skill
424
+ description: skill
425
+ auth:
426
+ provider: ${auth.provider}
427
+ account: ${auth.account}
428
+ ---
429
+ `;
430
+ return fm + content;
431
+ }
432
+ let fmBody = fmMatch[2];
433
+ fmBody = fmBody.replace(/^auth:\n(?: .+\n)*/m, "");
434
+ fmBody = fmBody.replace(/\n\n$/, "\n");
435
+ if (!fmBody.endsWith("\n")) fmBody += "\n";
436
+ fmBody += `auth:
437
+ provider: ${auth.provider}
438
+ account: ${auth.account}
439
+ `;
440
+ return fmMatch[1] + fmBody + fmMatch[3] + content.slice(fmMatch[0].length);
441
+ }
442
+ function parseAuthFrontmatter(content) {
443
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
444
+ if (!fmMatch) return null;
445
+ const fmBlock = fmMatch[1];
446
+ let inAuth = false;
447
+ let provider;
448
+ let account;
449
+ for (const line of fmBlock.split("\n")) {
450
+ const trimmed = line.trimEnd();
451
+ if (trimmed === "auth:") {
452
+ inAuth = true;
453
+ continue;
454
+ }
455
+ if (inAuth) {
456
+ const nestedMatch = trimmed.match(/^\s+(\w+):\s*(.+)$/);
457
+ if (nestedMatch) {
458
+ if (nestedMatch[1] === "provider") provider = nestedMatch[2].trim();
459
+ if (nestedMatch[1] === "account") account = nestedMatch[2].trim();
460
+ continue;
461
+ }
462
+ inAuth = false;
463
+ }
464
+ }
465
+ if (!provider || !account) return null;
466
+ const validProviders = ["google", "github", "x"];
467
+ if (!validProviders.includes(provider)) return null;
468
+ return { provider, account };
469
+ }
470
+ function upsertAuthBody(content, instructions) {
471
+ const fmEnd = content.indexOf("---", 3);
472
+ if (fmEnd === -1) return content + "\n\n" + instructions + "\n";
473
+ const afterFm = content.indexOf("\n", fmEnd + 3);
474
+ const frontmatter = content.slice(0, afterFm + 1);
475
+ let body = content.slice(afterFm + 1);
476
+ const authSectionRegex = /## Authentication\n[\s\S]*?(?=\n## |\n*$)/;
477
+ if (authSectionRegex.test(body)) {
478
+ body = body.replace(authSectionRegex, instructions);
479
+ } else {
480
+ if (body.trim()) {
481
+ body = body.trimEnd() + "\n\n" + instructions + "\n";
482
+ } else {
483
+ body = "\n" + instructions + "\n";
484
+ }
485
+ }
486
+ return frontmatter + body;
487
+ }
476
488
  async function scanSkillDir(dir) {
477
489
  let entries;
478
490
  try {
479
- entries = await fs4.readdir(dir);
491
+ entries = await fs3.readdir(dir);
480
492
  } catch {
481
493
  return [];
482
494
  }
483
495
  const skills = [];
484
496
  for (const entry of entries) {
485
- const skillMdPath = join4(dir, entry, "SKILL.md");
497
+ const skillMdPath = join3(dir, entry, "SKILL.md");
486
498
  try {
487
- const content = await fs4.readFile(skillMdPath, "utf-8");
499
+ const content = await fs3.readFile(skillMdPath, "utf-8");
488
500
  const meta = parseFrontmatter(content, entry, skillMdPath);
489
501
  if (meta) skills.push(meta);
490
502
  } catch {
@@ -534,8 +546,8 @@ function parseFrontmatter(content, dirName, filePath) {
534
546
 
535
547
  // src/wallet.ts
536
548
  import { createHmac, createECDH, sign as cryptoSign } from "crypto";
537
- import { promises as fs5 } from "fs";
538
- import { join as join5 } from "path";
549
+ import { promises as fs4 } from "fs";
550
+ import { join as join4 } from "path";
539
551
 
540
552
  // node_modules/@noble/hashes/_u64.js
541
553
  var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
@@ -1229,7 +1241,7 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
1229
1241
  let v = u8n(hashLen);
1230
1242
  let k = u8n(hashLen);
1231
1243
  let i = 0;
1232
- const reset = () => {
1244
+ const reset2 = () => {
1233
1245
  v.fill(1);
1234
1246
  k.fill(0);
1235
1247
  i = 0;
@@ -1257,12 +1269,12 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
1257
1269
  return concatBytes(...out);
1258
1270
  };
1259
1271
  const genUntil = (seed, pred) => {
1260
- reset();
1272
+ reset2();
1261
1273
  reseed(seed);
1262
1274
  let res = void 0;
1263
1275
  while (!(res = pred(gen())))
1264
1276
  reseed();
1265
- reset();
1277
+ reset2();
1266
1278
  return res;
1267
1279
  };
1268
1280
  return genUntil;
@@ -2802,13 +2814,13 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
2802
2814
  }
2803
2815
  return { seed, k2sig };
2804
2816
  }
2805
- function sign3(message, secretKey, opts = {}) {
2817
+ function sign2(message, secretKey, opts = {}) {
2806
2818
  const { seed, k2sig } = prepSig(message, secretKey, opts);
2807
2819
  const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac2);
2808
2820
  const sig = drbg(seed, k2sig);
2809
2821
  return sig.toBytes(opts.format);
2810
2822
  }
2811
- function verify2(signature, message, publicKey, opts = {}) {
2823
+ function verify(signature, message, publicKey, opts = {}) {
2812
2824
  const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
2813
2825
  publicKey = abytes(publicKey, void 0, "publicKey");
2814
2826
  message = validateMsgAndHash(message, prehash);
@@ -2848,8 +2860,8 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
2848
2860
  utils,
2849
2861
  lengths,
2850
2862
  Point,
2851
- sign: sign3,
2852
- verify: verify2,
2863
+ sign: sign2,
2864
+ verify,
2853
2865
  recoverPublicKey,
2854
2866
  Signature,
2855
2867
  hash
@@ -2955,8 +2967,8 @@ async function getSolanaAddress(nitDir) {
2955
2967
  return base58Encode(pubBytes);
2956
2968
  }
2957
2969
  async function getEvmAddress(nitDir) {
2958
- const keyPath = join5(nitDir, "identity", "agent.key");
2959
- const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
2970
+ const keyPath = join4(nitDir, "identity", "agent.key");
2971
+ const privBase64 = (await fs4.readFile(keyPath, "utf-8")).trim();
2960
2972
  const ed25519Seed = Buffer.from(privBase64, "base64");
2961
2973
  const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
2962
2974
  const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
@@ -2971,8 +2983,8 @@ async function getWalletAddresses(nitDir) {
2971
2983
  return { solana, ethereum };
2972
2984
  }
2973
2985
  async function loadSecp256k1RawKeyPair(nitDir) {
2974
- const keyPath = join5(nitDir, "identity", "agent.key");
2975
- const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
2986
+ const keyPath = join4(nitDir, "identity", "agent.key");
2987
+ const privBase64 = (await fs4.readFile(keyPath, "utf-8")).trim();
2976
2988
  const ed25519Seed = Buffer.from(privBase64, "base64");
2977
2989
  const secp256k1PrivKey = deriveSecp256k1Seed(ed25519Seed);
2978
2990
  const secp256k1PubKey = getSecp256k1PublicKey(secp256k1PrivKey);
@@ -2985,8 +2997,8 @@ async function signEvmHash(nitDir, hash) {
2985
2997
  if (hash.length !== 32) {
2986
2998
  throw new Error(`Expected 32-byte hash, got ${hash.length} bytes`);
2987
2999
  }
2988
- const keyPath = join5(nitDir, "identity", "agent.key");
2989
- const privBase64 = (await fs5.readFile(keyPath, "utf-8")).trim();
3000
+ const keyPath = join4(nitDir, "identity", "agent.key");
3001
+ const privBase64 = (await fs4.readFile(keyPath, "utf-8")).trim();
2990
3002
  const ed25519Seed = Buffer.from(privBase64, "base64");
2991
3003
  const privKey = deriveSecp256k1Seed(ed25519Seed);
2992
3004
  const sigBytes = secp256k1.sign(hash, privKey, { prehash: false, format: "recovered" });
@@ -3097,115 +3109,23 @@ function formatValue(val) {
3097
3109
  return JSON.stringify(val);
3098
3110
  }
3099
3111
 
3100
- // src/remote.ts
3101
- import { createHash as createHash3 } from "crypto";
3102
- function sha256Hex(data) {
3103
- return createHash3("sha256").update(data, "utf-8").digest("hex");
3104
- }
3105
- async function buildAuthHeaders(nitDir, method, path, body) {
3106
- const agentId = await loadAgentId(nitDir);
3107
- const timestamp = Math.floor(Date.now() / 1e3).toString();
3108
- let message = `${method}
3109
- ${path}
3110
- ${agentId}
3111
- ${timestamp}`;
3112
- if (body !== void 0) {
3113
- message += `
3114
- ${sha256Hex(body)}`;
3115
- }
3116
- const signature = await signMessage(nitDir, message);
3117
- return {
3118
- "X-Nit-Agent-Id": agentId,
3119
- "X-Nit-Timestamp": timestamp,
3120
- "X-Nit-Signature": signature
3121
- };
3122
- }
3123
- async function pushBranch(nitDir, apiBase, branch2, cardJson, commitHash) {
3124
- const path = `/agent-card/branches/${encodeURIComponent(branch2)}`;
3125
- const body = JSON.stringify({ card_json: cardJson, commit_hash: commitHash });
3126
- try {
3127
- const authHeaders = await buildAuthHeaders(nitDir, "PUT", path, body);
3128
- const res = await fetch(`${apiBase}${path}`, {
3129
- method: "PUT",
3130
- headers: {
3131
- "Content-Type": "application/json",
3132
- ...authHeaders
3133
- },
3134
- body
3135
- });
3136
- if (!res.ok) {
3137
- const text = await res.text();
3138
- return {
3139
- branch: branch2,
3140
- commitHash,
3141
- remoteUrl: apiBase,
3142
- success: false,
3143
- error: `HTTP ${res.status}: ${text}`
3144
- };
3145
- }
3146
- return { branch: branch2, commitHash, remoteUrl: apiBase, success: true };
3147
- } catch (err) {
3148
- return {
3149
- branch: branch2,
3150
- commitHash,
3151
- remoteUrl: apiBase,
3152
- success: false,
3153
- error: err instanceof Error ? err.message : String(err)
3154
- };
3155
- }
3156
- }
3157
- async function fetchBranchCard(cardUrl, branch2, nitDir) {
3158
- const baseUrl = cardUrl.replace(/\/$/, "");
3159
- let url = `${baseUrl}/.well-known/agent-card.json`;
3160
- if (branch2 !== "main") {
3161
- url += `?branch=${encodeURIComponent(branch2)}`;
3162
- }
3163
- const res = await fetch(url);
3164
- if (res.ok) {
3165
- return await res.json();
3166
- }
3167
- if (res.status === 401 && branch2 !== "main") {
3168
- if (!nitDir) {
3169
- throw new Error(
3170
- `Branch "${branch2}" requires authentication. Provide nitDir for signing.`
3171
- );
3172
- }
3173
- const challengeData = await res.json();
3174
- const signature = await signChallenge(nitDir, challengeData.challenge);
3175
- const authRes = await fetch(url, {
3176
- headers: {
3177
- "X-Nit-Challenge": challengeData.challenge,
3178
- "X-Nit-Signature": signature
3179
- }
3180
- });
3181
- if (!authRes.ok) {
3182
- const body = await authRes.text();
3183
- throw new Error(
3184
- `Failed to fetch branch "${branch2}" after challenge: HTTP ${authRes.status} ${body}`
3185
- );
3186
- }
3187
- return await authRes.json();
3188
- }
3189
- throw new Error(`Failed to fetch card: HTTP ${res.status}`);
3190
- }
3191
-
3192
3112
  // src/config.ts
3193
- import { promises as fs6 } from "fs";
3194
- import { join as join6 } from "path";
3113
+ import { promises as fs5 } from "fs";
3114
+ import { join as join5 } from "path";
3195
3115
  var CONFIG_FILE = "config";
3196
3116
  async function readConfig(nitDir) {
3197
- const configPath = join6(nitDir, CONFIG_FILE);
3117
+ const configPath = join5(nitDir, CONFIG_FILE);
3198
3118
  let raw;
3199
3119
  try {
3200
- raw = await fs6.readFile(configPath, "utf-8");
3120
+ raw = await fs5.readFile(configPath, "utf-8");
3201
3121
  } catch {
3202
3122
  return { remotes: {} };
3203
3123
  }
3204
3124
  return parseConfig(raw);
3205
3125
  }
3206
3126
  async function writeConfig(nitDir, config) {
3207
- const configPath = join6(nitDir, CONFIG_FILE);
3208
- await fs6.writeFile(configPath, serializeConfig(config), "utf-8");
3127
+ const configPath = join5(nitDir, CONFIG_FILE);
3128
+ await fs5.writeFile(configPath, serializeConfig(config), "utf-8");
3209
3129
  }
3210
3130
  async function getRemoteUrl(nitDir, remoteName) {
3211
3131
  const config = await readConfig(nitDir);
@@ -3377,7 +3297,7 @@ var DEFAULT_API_BASE = "https://api.newtype-ai.org";
3377
3297
  function findNitDir(startDir) {
3378
3298
  let dir = resolve2(startDir || process.cwd());
3379
3299
  while (true) {
3380
- const candidate = join7(dir, NIT_DIR);
3300
+ const candidate = join6(dir, NIT_DIR);
3381
3301
  try {
3382
3302
  const s = statSync(candidate);
3383
3303
  if (s.isDirectory()) return candidate;
@@ -3396,17 +3316,17 @@ function projectDir(nitDir) {
3396
3316
  return resolve2(nitDir, "..");
3397
3317
  }
3398
3318
  async function readWorkingCard(nitDir) {
3399
- const cardPath = join7(projectDir(nitDir), CARD_FILE);
3319
+ const cardPath = join6(projectDir(nitDir), CARD_FILE);
3400
3320
  try {
3401
- const raw = await fs7.readFile(cardPath, "utf-8");
3321
+ const raw = await fs6.readFile(cardPath, "utf-8");
3402
3322
  return JSON.parse(raw);
3403
3323
  } catch {
3404
3324
  throw new Error(`Cannot read ${CARD_FILE}. Does it exist?`);
3405
3325
  }
3406
3326
  }
3407
3327
  async function writeWorkingCard(nitDir, card) {
3408
- const cardPath = join7(projectDir(nitDir), CARD_FILE);
3409
- await fs7.writeFile(cardPath, JSON.stringify(card, null, 2) + "\n", "utf-8");
3328
+ const cardPath = join6(projectDir(nitDir), CARD_FILE);
3329
+ await fs6.writeFile(cardPath, JSON.stringify(card, null, 2) + "\n", "utf-8");
3410
3330
  }
3411
3331
  async function getCardAtCommit(nitDir, commitHash) {
3412
3332
  const commitRaw = await readObject(nitDir, commitHash);
@@ -3424,27 +3344,27 @@ async function getAuthorName(nitDir) {
3424
3344
  }
3425
3345
  async function init(options) {
3426
3346
  const projDir = resolve2(options?.projectDir || process.cwd());
3427
- const nitDir = join7(projDir, NIT_DIR);
3347
+ const nitDir = join6(projDir, NIT_DIR);
3428
3348
  try {
3429
- await fs7.access(nitDir);
3349
+ await fs6.access(nitDir);
3430
3350
  throw new Error("Already initialized. .nit/ directory exists.");
3431
3351
  } catch (err) {
3432
3352
  if (err instanceof Error && err.message.startsWith("Already")) throw err;
3433
3353
  }
3434
- await fs7.mkdir(join7(nitDir, "objects"), { recursive: true });
3435
- await fs7.mkdir(join7(nitDir, "refs", "heads"), { recursive: true });
3436
- await fs7.mkdir(join7(nitDir, "refs", "remote"), { recursive: true });
3437
- await fs7.mkdir(join7(nitDir, "identity"), { recursive: true });
3438
- await fs7.mkdir(join7(nitDir, "logs"), { recursive: true });
3354
+ await fs6.mkdir(join6(nitDir, "objects"), { recursive: true });
3355
+ await fs6.mkdir(join6(nitDir, "refs", "heads"), { recursive: true });
3356
+ await fs6.mkdir(join6(nitDir, "refs", "remote"), { recursive: true });
3357
+ await fs6.mkdir(join6(nitDir, "identity"), { recursive: true });
3358
+ await fs6.mkdir(join6(nitDir, "logs"), { recursive: true });
3439
3359
  const { publicKey: pubBase64 } = await generateKeypair(nitDir);
3440
3360
  const publicKeyField = formatPublicKeyField(pubBase64);
3441
3361
  const agentId = deriveAgentId(publicKeyField);
3442
3362
  await saveAgentId(nitDir, agentId);
3443
- const cardPath = join7(projDir, CARD_FILE);
3363
+ const cardPath = join6(projDir, CARD_FILE);
3444
3364
  let card;
3445
3365
  let skillsFound = [];
3446
3366
  try {
3447
- const raw = await fs7.readFile(cardPath, "utf-8");
3367
+ const raw = await fs6.readFile(cardPath, "utf-8");
3448
3368
  card = JSON.parse(raw);
3449
3369
  card.publicKey = publicKeyField;
3450
3370
  skillsFound = card.skills.map((s) => s.id);
@@ -3483,7 +3403,7 @@ async function init(options) {
3483
3403
  const commitHash = await writeObject(nitDir, "commit", commitContent);
3484
3404
  await setBranch(nitDir, "main", commitHash);
3485
3405
  await setHead(nitDir, "main");
3486
- await fs7.writeFile(join7(nitDir, "logs", "HEAD"), "", "utf-8");
3406
+ await fs6.writeFile(join6(nitDir, "logs", "HEAD"), "", "utf-8");
3487
3407
  const skillsDir = await discoverSkillsDir(projDir);
3488
3408
  await writeConfig(nitDir, {
3489
3409
  remotes: { origin: { url: DEFAULT_API_BASE } },
@@ -3561,7 +3481,7 @@ async function status(options) {
3561
3481
  branches: branchStatus
3562
3482
  };
3563
3483
  }
3564
- async function sign2(message, options) {
3484
+ async function sign(message, options) {
3565
3485
  const nitDir = findNitDir(options?.projectDir);
3566
3486
  return signMessage(nitDir, message);
3567
3487
  }
@@ -3789,16 +3709,146 @@ async function rpcInfo(options) {
3789
3709
  const config = await readConfig(nitDir);
3790
3710
  return config.rpc ?? {};
3791
3711
  }
3712
+ async function reset(target, options) {
3713
+ const nitDir = findNitDir(options?.projectDir);
3714
+ let commitHash;
3715
+ if (!target) {
3716
+ commitHash = await resolveHead(nitDir);
3717
+ } else {
3718
+ const branchHash = await getBranch(nitDir, target);
3719
+ if (branchHash) {
3720
+ commitHash = branchHash;
3721
+ } else if (/^[0-9a-f]{64}$/.test(target)) {
3722
+ commitHash = target;
3723
+ } else {
3724
+ throw new Error(`Unknown target "${target}". Provide a branch name or commit hash.`);
3725
+ }
3726
+ }
3727
+ const card = await getCardAtCommit(nitDir, commitHash);
3728
+ await writeWorkingCard(nitDir, card);
3729
+ return { hash: commitHash };
3730
+ }
3731
+ async function show(target, options) {
3732
+ const nitDir = findNitDir(options?.projectDir);
3733
+ let commitHash;
3734
+ if (!target) {
3735
+ commitHash = await resolveHead(nitDir);
3736
+ } else {
3737
+ const branchHash = await getBranch(nitDir, target);
3738
+ if (branchHash) {
3739
+ commitHash = branchHash;
3740
+ } else if (/^[0-9a-f]{64}$/.test(target)) {
3741
+ commitHash = target;
3742
+ } else {
3743
+ throw new Error(`Unknown target "${target}". Provide a branch name or commit hash.`);
3744
+ }
3745
+ }
3746
+ const commitRaw = await readObject(nitDir, commitHash);
3747
+ const c = parseCommit(commitHash, commitRaw);
3748
+ const cardJson = await getCardAtCommit(nitDir, commitHash);
3749
+ return {
3750
+ hash: c.hash,
3751
+ card: c.card,
3752
+ parent: c.parent,
3753
+ author: c.author,
3754
+ timestamp: c.timestamp,
3755
+ message: c.message,
3756
+ cardJson
3757
+ };
3758
+ }
3759
+ async function pull(options) {
3760
+ const nitDir = findNitDir(options?.projectDir);
3761
+ const remoteName = options?.remoteName || "origin";
3762
+ const apiBase = await getRemoteUrl(nitDir, remoteName) || DEFAULT_API_BASE;
3763
+ const currentBranch = await getCurrentBranch(nitDir);
3764
+ const agentId = await loadAgentId(nitDir);
3765
+ const branches = options?.all ? await listBranches(nitDir) : [{ name: currentBranch, commitHash: await resolveHead(nitDir) }];
3766
+ const results = [];
3767
+ for (const b of branches) {
3768
+ try {
3769
+ const { fetchBranchCard: fetchBranchCard2 } = await import("./remote-WZ625MBZ.js");
3770
+ const cardUrl = `${apiBase}/agent-card/${agentId}`;
3771
+ const remoteCard = await fetchBranchCard2(cardUrl, b.name, nitDir);
3772
+ const cardJson = JSON.stringify(remoteCard, null, 2);
3773
+ const cardHash = await writeObject(nitDir, "card", cardJson);
3774
+ const localHash = await getBranch(nitDir, b.name);
3775
+ if (localHash) {
3776
+ const localRaw = await readObject(nitDir, localHash);
3777
+ const localCommit = parseCommit(localHash, localRaw);
3778
+ if (localCommit.card === cardHash) {
3779
+ results.push({ branch: b.name, commitHash: localHash, updated: false });
3780
+ continue;
3781
+ }
3782
+ }
3783
+ const author = remoteCard.name || b.name;
3784
+ const commitContent = serializeCommit({
3785
+ card: cardHash,
3786
+ parent: localHash,
3787
+ author,
3788
+ timestamp: Math.floor(Date.now() / 1e3),
3789
+ message: `Pull from ${remoteName}`
3790
+ });
3791
+ const commitHash = await writeObject(nitDir, "commit", commitContent);
3792
+ await setBranch(nitDir, b.name, commitHash);
3793
+ await setRemoteRef(nitDir, remoteName, b.name, commitHash);
3794
+ if (b.name === currentBranch) {
3795
+ await writeWorkingCard(nitDir, remoteCard);
3796
+ }
3797
+ results.push({ branch: b.name, commitHash, updated: true });
3798
+ } catch (err) {
3799
+ const msg = err instanceof Error ? err.message : String(err);
3800
+ results.push({ branch: b.name, commitHash: "", updated: false });
3801
+ }
3802
+ }
3803
+ return results;
3804
+ }
3805
+ async function authSet(domain, provider, account, options) {
3806
+ const nitDir = findNitDir(options?.projectDir);
3807
+ const projDir = projectDir(nitDir);
3808
+ let switchedBranch;
3809
+ let createdBranch = false;
3810
+ const currentBranch = await getCurrentBranch(nitDir);
3811
+ if (currentBranch !== domain) {
3812
+ const isNew = !await getBranch(nitDir, domain);
3813
+ if (isNew) {
3814
+ const headHash = await resolveHead(nitDir);
3815
+ await setBranch(nitDir, domain, headHash);
3816
+ createdBranch = true;
3817
+ }
3818
+ await checkout(domain, options);
3819
+ switchedBranch = domain;
3820
+ }
3821
+ const skillsDir = await getSkillsDir(nitDir) ?? await discoverSkillsDir(projDir);
3822
+ const auth = { provider, account };
3823
+ const skillId = await updateSkillAuth(skillsDir, domain, auth);
3824
+ const card = await readWorkingCard(nitDir);
3825
+ if (!card.skills.some((s) => s.id === skillId)) {
3826
+ card.skills.push({ id: skillId });
3827
+ await writeWorkingCard(nitDir, card);
3828
+ }
3829
+ return { branch: domain, skillId, provider, account, switchedBranch, createdBranch };
3830
+ }
3831
+ async function authShow(domain, options) {
3832
+ const nitDir = findNitDir(options?.projectDir);
3833
+ const projDir = projectDir(nitDir);
3834
+ const skillsDir = await getSkillsDir(nitDir) ?? await discoverSkillsDir(projDir);
3835
+ const results = [];
3836
+ if (domain) {
3837
+ const auth = await readSkillAuth(skillsDir, domain);
3838
+ results.push({ branch: domain, auth });
3839
+ } else {
3840
+ const branches = await listBranches(nitDir);
3841
+ for (const b of branches) {
3842
+ const auth = await readSkillAuth(skillsDir, b.name);
3843
+ if (auth) {
3844
+ results.push({ branch: b.name, auth });
3845
+ }
3846
+ }
3847
+ }
3848
+ return results;
3849
+ }
3792
3850
 
3793
3851
  export {
3794
- loadRawKeyPair,
3795
- formatPublicKeyField,
3796
- parsePublicKeyField,
3797
- signChallenge,
3798
- signMessage,
3799
- NIT_NAMESPACE,
3800
- deriveAgentId,
3801
- loadAgentId,
3802
3852
  base58Encode,
3803
3853
  getSolanaAddress,
3804
3854
  getEvmAddress,
@@ -3808,11 +3858,10 @@ export {
3808
3858
  signSolanaBytes,
3809
3859
  diffCards,
3810
3860
  formatDiff,
3811
- fetchBranchCard,
3812
3861
  findNitDir,
3813
3862
  init,
3814
3863
  status,
3815
- sign2 as sign,
3864
+ sign,
3816
3865
  loginPayload,
3817
3866
  commit,
3818
3867
  log,
@@ -3826,7 +3875,12 @@ export {
3826
3875
  signTx2 as signTx,
3827
3876
  broadcast2 as broadcast,
3828
3877
  rpcSetUrl,
3829
- rpcInfo
3878
+ rpcInfo,
3879
+ reset,
3880
+ show,
3881
+ pull,
3882
+ authSet,
3883
+ authShow
3830
3884
  };
3831
3885
  /*! Bundled license information:
3832
3886