@newtype-ai/nit 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/{chunk-5AVY6P7B.js → chunk-7KTMZ67T.js} +118 -120
- package/dist/cli.js +9 -24
- package/dist/index.d.ts +31 -14
- package/dist/index.js +9 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ An agent working across multiple platforms (FAAM, Polymarket, etc.) needs to pre
|
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
main → full agent card (public, discoverable)
|
|
13
|
-
faam.
|
|
13
|
+
faam.io → { skills: [content, social], description: "Content creator..." }
|
|
14
14
|
polymarket.com → { skills: [research, trading], description: "Market analyst..." }
|
|
15
15
|
```
|
|
16
16
|
|
|
@@ -33,10 +33,10 @@ npx @newtype-ai/nit init
|
|
|
33
33
|
nit init
|
|
34
34
|
|
|
35
35
|
# Create a platform-specific branch
|
|
36
|
-
nit branch faam.
|
|
36
|
+
nit branch faam.io
|
|
37
37
|
|
|
38
38
|
# Switch to it and customize the card
|
|
39
|
-
nit checkout faam.
|
|
39
|
+
nit checkout faam.io
|
|
40
40
|
# edit agent-card.json...
|
|
41
41
|
nit commit -m "FAAM config"
|
|
42
42
|
|
|
@@ -74,9 +74,9 @@ Platforms verify your identity by challenging you to sign a nonce — no shared
|
|
|
74
74
|
|
|
75
75
|
### Branches
|
|
76
76
|
|
|
77
|
-
Each branch is a different agent card for a different platform. Branch name = root domain of the platform (e.g., `faam.
|
|
77
|
+
Each branch is a different agent card for a different platform. Branch name = root domain of the platform (e.g., `faam.io`, `polymarket.com`).
|
|
78
78
|
|
|
79
|
-
`nit checkout faam.
|
|
79
|
+
`nit checkout faam.io` overwrites `./agent-card.json` with that branch's version.
|
|
80
80
|
|
|
81
81
|
### Skill Resolution
|
|
82
82
|
|
|
@@ -96,7 +96,7 @@ The main branch is public. Non-main branches require signed-challenge authentica
|
|
|
96
96
|
|
|
97
97
|
```
|
|
98
98
|
GET /.well-known/agent-card.json → main card (public)
|
|
99
|
-
GET /.well-known/agent-card.json?branch=faam.
|
|
99
|
+
GET /.well-known/agent-card.json?branch=faam.io → 401 { challenge }
|
|
100
100
|
GET ... + X-Nit-Signature + X-Nit-Challenge → branch card
|
|
101
101
|
```
|
|
102
102
|
|
|
@@ -124,8 +124,8 @@ your-project/
|
|
|
124
124
|
import { init, commit, checkout, branch, push, status } from '@newtype-ai/nit';
|
|
125
125
|
|
|
126
126
|
await init();
|
|
127
|
-
await branch('faam.
|
|
128
|
-
await checkout('faam.
|
|
127
|
+
await branch('faam.io');
|
|
128
|
+
await checkout('faam.io');
|
|
129
129
|
// modify agent-card.json...
|
|
130
130
|
await commit('FAAM config');
|
|
131
131
|
await push({ all: true });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// nit — version control for agent cards
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { promises as
|
|
5
|
-
import { join as
|
|
4
|
+
import { promises as fs5, statSync } from "fs";
|
|
5
|
+
import { join as join5, basename as basename2, resolve } from "path";
|
|
6
6
|
|
|
7
7
|
// src/objects.ts
|
|
8
8
|
import { createHash } from "crypto";
|
|
@@ -170,6 +170,7 @@ async function getRemoteRef(nitDir, remote2, branch2) {
|
|
|
170
170
|
|
|
171
171
|
// src/identity.ts
|
|
172
172
|
import {
|
|
173
|
+
createHash as createHash2,
|
|
173
174
|
generateKeyPairSync,
|
|
174
175
|
createPrivateKey,
|
|
175
176
|
createPublicKey,
|
|
@@ -261,94 +262,73 @@ function verifySignature(pubBase64, challenge, signatureBase64) {
|
|
|
261
262
|
Buffer.from(signatureBase64, "base64")
|
|
262
263
|
);
|
|
263
264
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
265
|
+
async function signMessage(nitDir, message) {
|
|
266
|
+
const privateKey = await loadPrivateKey(nitDir);
|
|
267
|
+
const sig = sign(null, Buffer.from(message, "utf-8"), privateKey);
|
|
268
|
+
return sig.toString("base64");
|
|
269
|
+
}
|
|
270
|
+
var NIT_NAMESPACE = "801ba518-f326-47e5-97c9-d1efd1865a19";
|
|
271
|
+
function deriveAgentId(publicKeyField) {
|
|
272
|
+
return uuidv5(publicKeyField, NIT_NAMESPACE);
|
|
273
|
+
}
|
|
274
|
+
async function loadAgentId(nitDir) {
|
|
275
|
+
const idPath = join3(nitDir, "identity", "agent-id");
|
|
272
276
|
try {
|
|
273
|
-
|
|
277
|
+
return (await fs3.readFile(idPath, "utf-8")).trim();
|
|
274
278
|
} catch {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
async function writeConfig(nitDir, config) {
|
|
280
|
-
const configPath = join4(nitDir, CONFIG_FILE);
|
|
281
|
-
await fs4.writeFile(configPath, serializeConfig(config), "utf-8");
|
|
282
|
-
}
|
|
283
|
-
async function getRemoteCredential(nitDir, remoteName) {
|
|
284
|
-
const config = await readConfig(nitDir);
|
|
285
|
-
return config.remotes[remoteName]?.credential ?? null;
|
|
286
|
-
}
|
|
287
|
-
async function setRemoteCredential(nitDir, remoteName, credential) {
|
|
288
|
-
const config = await readConfig(nitDir);
|
|
289
|
-
if (!config.remotes[remoteName]) {
|
|
290
|
-
config.remotes[remoteName] = {};
|
|
291
|
-
}
|
|
292
|
-
config.remotes[remoteName].credential = credential;
|
|
293
|
-
await writeConfig(nitDir, config);
|
|
294
|
-
}
|
|
295
|
-
function parseConfig(raw) {
|
|
296
|
-
const remotes = {};
|
|
297
|
-
let currentRemote = null;
|
|
298
|
-
for (const line of raw.split("\n")) {
|
|
299
|
-
const trimmed = line.trim();
|
|
300
|
-
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
301
|
-
const sectionMatch = trimmed.match(/^\[remote\s+"([^"]+)"\]$/);
|
|
302
|
-
if (sectionMatch) {
|
|
303
|
-
currentRemote = sectionMatch[1];
|
|
304
|
-
if (!remotes[currentRemote]) {
|
|
305
|
-
remotes[currentRemote] = {};
|
|
306
|
-
}
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
if (currentRemote !== null) {
|
|
310
|
-
const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
311
|
-
if (kvMatch) {
|
|
312
|
-
const [, key, value] = kvMatch;
|
|
313
|
-
if (key === "credential") {
|
|
314
|
-
remotes[currentRemote].credential = value.trim();
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
279
|
+
throw new Error(
|
|
280
|
+
"No agent ID found. Run `nit init` to generate identity."
|
|
281
|
+
);
|
|
318
282
|
}
|
|
319
|
-
return { remotes };
|
|
320
283
|
}
|
|
321
|
-
function
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
284
|
+
async function saveAgentId(nitDir, agentId) {
|
|
285
|
+
const idPath = join3(nitDir, "identity", "agent-id");
|
|
286
|
+
await fs3.writeFile(idPath, agentId + "\n", "utf-8");
|
|
287
|
+
}
|
|
288
|
+
function parseUuid(uuid) {
|
|
289
|
+
const hex = uuid.replace(/-/g, "");
|
|
290
|
+
return Buffer.from(hex, "hex");
|
|
291
|
+
}
|
|
292
|
+
function formatUuid(bytes) {
|
|
293
|
+
const hex = bytes.toString("hex");
|
|
294
|
+
return [
|
|
295
|
+
hex.slice(0, 8),
|
|
296
|
+
hex.slice(8, 12),
|
|
297
|
+
hex.slice(12, 16),
|
|
298
|
+
hex.slice(16, 20),
|
|
299
|
+
hex.slice(20, 32)
|
|
300
|
+
].join("-");
|
|
301
|
+
}
|
|
302
|
+
function uuidv5(name, namespace) {
|
|
303
|
+
const namespaceBytes = parseUuid(namespace);
|
|
304
|
+
const nameBytes = Buffer.from(name, "utf-8");
|
|
305
|
+
const data = Buffer.concat([namespaceBytes, nameBytes]);
|
|
306
|
+
const hash = createHash2("sha1").update(data).digest();
|
|
307
|
+
const uuid = Buffer.from(hash.subarray(0, 16));
|
|
308
|
+
uuid[6] = uuid[6] & 15 | 80;
|
|
309
|
+
uuid[8] = uuid[8] & 63 | 128;
|
|
310
|
+
return formatUuid(uuid);
|
|
331
311
|
}
|
|
332
312
|
|
|
333
313
|
// src/skills.ts
|
|
334
|
-
import { promises as
|
|
335
|
-
import { join as
|
|
314
|
+
import { promises as fs4 } from "fs";
|
|
315
|
+
import { join as join4 } from "path";
|
|
336
316
|
import { homedir } from "os";
|
|
337
317
|
async function discoverSkills(projectDir2) {
|
|
338
318
|
const home = homedir();
|
|
339
319
|
const searchDirs = [
|
|
340
320
|
// Project-local (all known agent frameworks)
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
321
|
+
join4(projectDir2, ".claude", "skills"),
|
|
322
|
+
join4(projectDir2, ".cursor", "skills"),
|
|
323
|
+
join4(projectDir2, ".windsurf", "skills"),
|
|
324
|
+
join4(projectDir2, ".codex", "skills"),
|
|
325
|
+
join4(projectDir2, ".agents", "skills"),
|
|
346
326
|
// User-global
|
|
347
|
-
|
|
327
|
+
join4(home, ".claude", "skills"),
|
|
348
328
|
// Claude Code + Cursor (shared)
|
|
349
|
-
|
|
329
|
+
join4(home, ".codex", "skills"),
|
|
350
330
|
// Codex CLI
|
|
351
|
-
|
|
331
|
+
join4(home, ".codeium", "windsurf", "skills")
|
|
352
332
|
// Windsurf
|
|
353
333
|
];
|
|
354
334
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -381,15 +361,15 @@ async function resolveSkillPointers(card, projectDir2) {
|
|
|
381
361
|
async function scanSkillDir(dir) {
|
|
382
362
|
let entries;
|
|
383
363
|
try {
|
|
384
|
-
entries = await
|
|
364
|
+
entries = await fs4.readdir(dir);
|
|
385
365
|
} catch {
|
|
386
366
|
return [];
|
|
387
367
|
}
|
|
388
368
|
const skills = [];
|
|
389
369
|
for (const entry of entries) {
|
|
390
|
-
const skillMdPath =
|
|
370
|
+
const skillMdPath = join4(dir, entry, "SKILL.md");
|
|
391
371
|
try {
|
|
392
|
-
const content = await
|
|
372
|
+
const content = await fs4.readFile(skillMdPath, "utf-8");
|
|
393
373
|
const meta = parseFrontmatter(content, entry, skillMdPath);
|
|
394
374
|
if (meta) skills.push(meta);
|
|
395
375
|
} catch {
|
|
@@ -531,36 +511,50 @@ function formatValue(val) {
|
|
|
531
511
|
}
|
|
532
512
|
|
|
533
513
|
// src/remote.ts
|
|
514
|
+
import { createHash as createHash3 } from "crypto";
|
|
534
515
|
var API_BASE = "https://api.newtype-ai.org";
|
|
516
|
+
function sha256Hex(data) {
|
|
517
|
+
return createHash3("sha256").update(data, "utf-8").digest("hex");
|
|
518
|
+
}
|
|
519
|
+
async function buildAuthHeaders(nitDir, method, path, body) {
|
|
520
|
+
const agentId = await loadAgentId(nitDir);
|
|
521
|
+
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
522
|
+
let message = `${method}
|
|
523
|
+
${path}
|
|
524
|
+
${agentId}
|
|
525
|
+
${timestamp}`;
|
|
526
|
+
if (body !== void 0) {
|
|
527
|
+
message += `
|
|
528
|
+
${sha256Hex(body)}`;
|
|
529
|
+
}
|
|
530
|
+
const signature = await signMessage(nitDir, message);
|
|
531
|
+
return {
|
|
532
|
+
"X-Nit-Agent-Id": agentId,
|
|
533
|
+
"X-Nit-Timestamp": timestamp,
|
|
534
|
+
"X-Nit-Signature": signature
|
|
535
|
+
};
|
|
536
|
+
}
|
|
535
537
|
async function pushBranch(nitDir, remoteName, branch2, cardJson, commitHash) {
|
|
536
|
-
const
|
|
537
|
-
|
|
538
|
-
return {
|
|
539
|
-
branch: branch2,
|
|
540
|
-
commitHash,
|
|
541
|
-
remoteUrl: API_BASE,
|
|
542
|
-
success: false,
|
|
543
|
-
error: `No credential configured for remote "${remoteName}". Run: nit remote set-credential <agent-key>`
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
const url = `${API_BASE}/agent-card/branches/${encodeURIComponent(branch2)}`;
|
|
538
|
+
const path = `/agent-card/branches/${encodeURIComponent(branch2)}`;
|
|
539
|
+
const body = JSON.stringify({ card_json: cardJson, commit_hash: commitHash });
|
|
547
540
|
try {
|
|
548
|
-
const
|
|
541
|
+
const authHeaders = await buildAuthHeaders(nitDir, "PUT", path, body);
|
|
542
|
+
const res = await fetch(`${API_BASE}${path}`, {
|
|
549
543
|
method: "PUT",
|
|
550
544
|
headers: {
|
|
551
545
|
"Content-Type": "application/json",
|
|
552
|
-
|
|
546
|
+
...authHeaders
|
|
553
547
|
},
|
|
554
|
-
body
|
|
548
|
+
body
|
|
555
549
|
});
|
|
556
550
|
if (!res.ok) {
|
|
557
|
-
const
|
|
551
|
+
const text = await res.text();
|
|
558
552
|
return {
|
|
559
553
|
branch: branch2,
|
|
560
554
|
commitHash,
|
|
561
555
|
remoteUrl: API_BASE,
|
|
562
556
|
success: false,
|
|
563
|
-
error: `HTTP ${res.status}: ${
|
|
557
|
+
error: `HTTP ${res.status}: ${text}`
|
|
564
558
|
};
|
|
565
559
|
}
|
|
566
560
|
return { branch: branch2, commitHash, remoteUrl: API_BASE, success: true };
|
|
@@ -615,7 +609,7 @@ var CARD_FILE = "agent-card.json";
|
|
|
615
609
|
function findNitDir(startDir) {
|
|
616
610
|
let dir = resolve(startDir || process.cwd());
|
|
617
611
|
while (true) {
|
|
618
|
-
const candidate =
|
|
612
|
+
const candidate = join5(dir, NIT_DIR);
|
|
619
613
|
try {
|
|
620
614
|
const s = statSync(candidate);
|
|
621
615
|
if (s.isDirectory()) return candidate;
|
|
@@ -634,17 +628,17 @@ function projectDir(nitDir) {
|
|
|
634
628
|
return resolve(nitDir, "..");
|
|
635
629
|
}
|
|
636
630
|
async function readWorkingCard(nitDir) {
|
|
637
|
-
const cardPath =
|
|
631
|
+
const cardPath = join5(projectDir(nitDir), CARD_FILE);
|
|
638
632
|
try {
|
|
639
|
-
const raw = await
|
|
633
|
+
const raw = await fs5.readFile(cardPath, "utf-8");
|
|
640
634
|
return JSON.parse(raw);
|
|
641
635
|
} catch {
|
|
642
636
|
throw new Error(`Cannot read ${CARD_FILE}. Does it exist?`);
|
|
643
637
|
}
|
|
644
638
|
}
|
|
645
639
|
async function writeWorkingCard(nitDir, card) {
|
|
646
|
-
const cardPath =
|
|
647
|
-
await
|
|
640
|
+
const cardPath = join5(projectDir(nitDir), CARD_FILE);
|
|
641
|
+
await fs5.writeFile(cardPath, JSON.stringify(card, null, 2) + "\n", "utf-8");
|
|
648
642
|
}
|
|
649
643
|
async function getCardAtCommit(nitDir, commitHash) {
|
|
650
644
|
const commitRaw = await readObject(nitDir, commitHash);
|
|
@@ -662,25 +656,27 @@ async function getAuthorName(nitDir) {
|
|
|
662
656
|
}
|
|
663
657
|
async function init(options) {
|
|
664
658
|
const projDir = resolve(options?.projectDir || process.cwd());
|
|
665
|
-
const nitDir =
|
|
659
|
+
const nitDir = join5(projDir, NIT_DIR);
|
|
666
660
|
try {
|
|
667
|
-
await
|
|
661
|
+
await fs5.access(nitDir);
|
|
668
662
|
throw new Error("Already initialized. .nit/ directory exists.");
|
|
669
663
|
} catch (err) {
|
|
670
664
|
if (err instanceof Error && err.message.startsWith("Already")) throw err;
|
|
671
665
|
}
|
|
672
|
-
await
|
|
673
|
-
await
|
|
674
|
-
await
|
|
675
|
-
await
|
|
676
|
-
await
|
|
666
|
+
await fs5.mkdir(join5(nitDir, "objects"), { recursive: true });
|
|
667
|
+
await fs5.mkdir(join5(nitDir, "refs", "heads"), { recursive: true });
|
|
668
|
+
await fs5.mkdir(join5(nitDir, "refs", "remote"), { recursive: true });
|
|
669
|
+
await fs5.mkdir(join5(nitDir, "identity"), { recursive: true });
|
|
670
|
+
await fs5.mkdir(join5(nitDir, "logs"), { recursive: true });
|
|
677
671
|
const { publicKey: pubBase64 } = await generateKeypair(nitDir);
|
|
678
672
|
const publicKeyField = formatPublicKeyField(pubBase64);
|
|
679
|
-
const
|
|
673
|
+
const agentId = deriveAgentId(publicKeyField);
|
|
674
|
+
await saveAgentId(nitDir, agentId);
|
|
675
|
+
const cardPath = join5(projDir, CARD_FILE);
|
|
680
676
|
let card;
|
|
681
677
|
let skillsFound = [];
|
|
682
678
|
try {
|
|
683
|
-
const raw = await
|
|
679
|
+
const raw = await fs5.readFile(cardPath, "utf-8");
|
|
684
680
|
card = JSON.parse(raw);
|
|
685
681
|
card.publicKey = publicKeyField;
|
|
686
682
|
skillsFound = card.skills.map((s) => s.id);
|
|
@@ -703,6 +699,9 @@ async function init(options) {
|
|
|
703
699
|
}))
|
|
704
700
|
};
|
|
705
701
|
}
|
|
702
|
+
if (!card.url) {
|
|
703
|
+
card.url = `https://agent-${agentId}.newtype-ai.org`;
|
|
704
|
+
}
|
|
706
705
|
await writeWorkingCard(nitDir, card);
|
|
707
706
|
const cardJson = JSON.stringify(card, null, 2);
|
|
708
707
|
const cardHash = await writeObject(nitDir, "card", cardJson);
|
|
@@ -716,11 +715,12 @@ async function init(options) {
|
|
|
716
715
|
const commitHash = await writeObject(nitDir, "commit", commitContent);
|
|
717
716
|
await setBranch(nitDir, "main", commitHash);
|
|
718
717
|
await setHead(nitDir, "main");
|
|
719
|
-
await
|
|
720
|
-
await
|
|
718
|
+
await fs5.writeFile(join5(nitDir, "logs", "HEAD"), "", "utf-8");
|
|
719
|
+
await fs5.writeFile(join5(nitDir, "config"), "", "utf-8");
|
|
721
720
|
return {
|
|
721
|
+
agentId,
|
|
722
722
|
publicKey: publicKeyField,
|
|
723
|
-
cardUrl: card.url
|
|
723
|
+
cardUrl: card.url,
|
|
724
724
|
skillsFound
|
|
725
725
|
};
|
|
726
726
|
}
|
|
@@ -921,24 +921,23 @@ async function push(options) {
|
|
|
921
921
|
async function remote(options) {
|
|
922
922
|
const nitDir = findNitDir(options?.projectDir);
|
|
923
923
|
const card = await readWorkingCard(nitDir);
|
|
924
|
-
const
|
|
924
|
+
const agentId = await loadAgentId(nitDir);
|
|
925
925
|
return {
|
|
926
926
|
name: "origin",
|
|
927
927
|
url: card.url || "(not set)",
|
|
928
|
-
|
|
928
|
+
agentId
|
|
929
929
|
};
|
|
930
930
|
}
|
|
931
|
-
async function setCredential(credential, options) {
|
|
932
|
-
const nitDir = findNitDir(options?.projectDir);
|
|
933
|
-
const remoteName = options?.remoteName || "origin";
|
|
934
|
-
await setRemoteCredential(nitDir, remoteName, credential);
|
|
935
|
-
}
|
|
936
931
|
|
|
937
932
|
export {
|
|
938
933
|
formatPublicKeyField,
|
|
939
934
|
parsePublicKeyField,
|
|
940
935
|
signChallenge,
|
|
941
936
|
verifySignature,
|
|
937
|
+
signMessage,
|
|
938
|
+
NIT_NAMESPACE,
|
|
939
|
+
deriveAgentId,
|
|
940
|
+
loadAgentId,
|
|
942
941
|
diffCards,
|
|
943
942
|
formatDiff,
|
|
944
943
|
fetchBranchCard,
|
|
@@ -951,6 +950,5 @@ export {
|
|
|
951
950
|
branch,
|
|
952
951
|
checkout,
|
|
953
952
|
push,
|
|
954
|
-
remote
|
|
955
|
-
setCredential
|
|
953
|
+
remote
|
|
956
954
|
};
|
package/dist/cli.js
CHANGED
|
@@ -10,9 +10,8 @@ import {
|
|
|
10
10
|
log,
|
|
11
11
|
push,
|
|
12
12
|
remote,
|
|
13
|
-
setCredential,
|
|
14
13
|
status
|
|
15
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7KTMZ67T.js";
|
|
16
15
|
|
|
17
16
|
// src/cli.ts
|
|
18
17
|
var bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
@@ -71,10 +70,9 @@ async function cmdInit() {
|
|
|
71
70
|
const result = await init();
|
|
72
71
|
console.log(bold("Initialized nit repository"));
|
|
73
72
|
console.log();
|
|
74
|
-
console.log(`
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
73
|
+
console.log(` Agent ID: ${green(result.agentId)}`);
|
|
74
|
+
console.log(` Public key: ${dim(result.publicKey)}`);
|
|
75
|
+
console.log(` Card URL: ${result.cardUrl}`);
|
|
78
76
|
if (result.skillsFound.length > 0) {
|
|
79
77
|
console.log(` Skills: ${result.skillsFound.join(", ")}`);
|
|
80
78
|
} else {
|
|
@@ -177,23 +175,11 @@ async function cmdPush(args) {
|
|
|
177
175
|
}
|
|
178
176
|
}
|
|
179
177
|
async function cmdRemote(args) {
|
|
180
|
-
const subcommand = args[0];
|
|
181
|
-
if (subcommand === "set-credential") {
|
|
182
|
-
const token = args[1];
|
|
183
|
-
if (!token) {
|
|
184
|
-
console.error("Usage: nit remote set-credential <agent-key>");
|
|
185
|
-
process.exit(1);
|
|
186
|
-
}
|
|
187
|
-
await setCredential(token);
|
|
188
|
-
console.log(`Credential ${green("configured")} for origin.`);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
178
|
const info = await remote();
|
|
192
179
|
console.log(`${bold(info.name)}`);
|
|
193
180
|
console.log(` URL: ${info.url}`);
|
|
194
|
-
console.log(
|
|
195
|
-
|
|
196
|
-
);
|
|
181
|
+
console.log(` Agent ID: ${info.agentId}`);
|
|
182
|
+
console.log(` Auth: ${green("Ed25519 keypair")}`);
|
|
197
183
|
}
|
|
198
184
|
function printUsage() {
|
|
199
185
|
console.log(`
|
|
@@ -211,13 +197,12 @@ ${bold("Commands:")}
|
|
|
211
197
|
checkout <branch> Switch branch (overwrites agent-card.json)
|
|
212
198
|
push [--all] Push branch(es) to remote
|
|
213
199
|
remote Show remote info
|
|
214
|
-
remote set-credential <key> Set push credential (agent key)
|
|
215
200
|
|
|
216
201
|
${bold("Examples:")}
|
|
217
202
|
nit init
|
|
218
|
-
nit branch faam.
|
|
219
|
-
nit checkout faam.
|
|
220
|
-
${dim("# edit agent-card.json for
|
|
203
|
+
nit branch faam.io
|
|
204
|
+
nit checkout faam.io
|
|
205
|
+
${dim("# edit agent-card.json for this platform...")}
|
|
221
206
|
nit commit -m "FAAM config"
|
|
222
207
|
nit push --all
|
|
223
208
|
`.trim());
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ interface NitHead {
|
|
|
27
27
|
}
|
|
28
28
|
/** Remote configuration for a single named remote. */
|
|
29
29
|
interface NitRemoteConfig {
|
|
30
|
-
/**
|
|
30
|
+
/** Legacy field — push auth is now via Ed25519 keypair */
|
|
31
31
|
credential?: string;
|
|
32
32
|
}
|
|
33
33
|
/** Full .nit/config file contents. */
|
|
@@ -140,15 +140,38 @@ declare function signChallenge(nitDir: string, challenge: string): Promise<strin
|
|
|
140
140
|
* for challenge-response flows.
|
|
141
141
|
*/
|
|
142
142
|
declare function verifySignature(pubBase64: string, challenge: string, signatureBase64: string): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Sign an arbitrary message with the agent's private key.
|
|
145
|
+
* Returns a standard base64-encoded signature.
|
|
146
|
+
*/
|
|
147
|
+
declare function signMessage(nitDir: string, message: string): Promise<string>;
|
|
148
|
+
/**
|
|
149
|
+
* Fixed namespace UUID for nit agent ID derivation.
|
|
150
|
+
* Generated once, hardcoded forever. Changing this would change ALL agent IDs.
|
|
151
|
+
* Must match the server-side constant in apps/agent-cards/src/api/agent-id.ts.
|
|
152
|
+
*/
|
|
153
|
+
declare const NIT_NAMESPACE = "801ba518-f326-47e5-97c9-d1efd1865a19";
|
|
154
|
+
/**
|
|
155
|
+
* Derive a deterministic agent ID (UUID) from an Ed25519 public key field.
|
|
156
|
+
* Uses UUIDv5: SHA-1 hash of NIT_NAMESPACE + publicKeyField.
|
|
157
|
+
*
|
|
158
|
+
* @param publicKeyField "ed25519:<base64>" format string
|
|
159
|
+
* @returns UUID string (lowercase, with hyphens)
|
|
160
|
+
*/
|
|
161
|
+
declare function deriveAgentId(publicKeyField: string): string;
|
|
162
|
+
/**
|
|
163
|
+
* Load the agent ID from .nit/identity/agent-id.
|
|
164
|
+
*/
|
|
165
|
+
declare function loadAgentId(nitDir: string): Promise<string>;
|
|
143
166
|
|
|
144
167
|
/**
|
|
145
168
|
* Fetch an agent card from a remote URL.
|
|
146
169
|
*
|
|
147
170
|
* For the main branch, this is a simple public GET.
|
|
148
171
|
* For other branches, this performs the challenge-response flow:
|
|
149
|
-
* 1. Request branch
|
|
172
|
+
* 1. Request branch -> 401 with challenge
|
|
150
173
|
* 2. Sign challenge with agent's private key
|
|
151
|
-
* 3. Re-request with signature
|
|
174
|
+
* 3. Re-request with signature -> get branch card
|
|
152
175
|
*
|
|
153
176
|
* @param cardUrl The agent's card URL (e.g. https://agent-{uuid}.newtype-ai.org)
|
|
154
177
|
* @param branch Branch to fetch ("main" for public, others need auth)
|
|
@@ -162,8 +185,9 @@ declare function fetchBranchCard(cardUrl: string, branch: string, nitDir?: strin
|
|
|
162
185
|
*/
|
|
163
186
|
declare function findNitDir(startDir?: string): string;
|
|
164
187
|
interface InitResult {
|
|
188
|
+
agentId: string;
|
|
165
189
|
publicKey: string;
|
|
166
|
-
cardUrl: string
|
|
190
|
+
cardUrl: string;
|
|
167
191
|
skillsFound: string[];
|
|
168
192
|
}
|
|
169
193
|
/**
|
|
@@ -231,20 +255,13 @@ declare function push(options?: {
|
|
|
231
255
|
interface RemoteInfo {
|
|
232
256
|
name: string;
|
|
233
257
|
url: string;
|
|
234
|
-
|
|
258
|
+
agentId: string;
|
|
235
259
|
}
|
|
236
260
|
/**
|
|
237
|
-
* Show remote info. URL comes from agent-card.json,
|
|
261
|
+
* Show remote info. URL comes from agent-card.json, agent ID from .nit/identity/.
|
|
238
262
|
*/
|
|
239
263
|
declare function remote(options?: {
|
|
240
264
|
projectDir?: string;
|
|
241
265
|
}): Promise<RemoteInfo>;
|
|
242
|
-
/**
|
|
243
|
-
* Set the push credential for a remote.
|
|
244
|
-
*/
|
|
245
|
-
declare function setCredential(credential: string, options?: {
|
|
246
|
-
projectDir?: string;
|
|
247
|
-
remoteName?: string;
|
|
248
|
-
}): Promise<void>;
|
|
249
266
|
|
|
250
|
-
export { type AgentCard, type AgentCardSkill, type DiffResult, type FieldDiff, type InitResult, type NitBranch, type NitCommit, type NitConfig, type NitHead, type NitRemoteConfig, type PushResult, type RemoteInfo, type SkillMetadata, type StatusResult, branch, checkout, commit, diff, diffCards, fetchBranchCard, findNitDir, formatDiff, formatPublicKeyField, init, log, parsePublicKeyField, push, remote,
|
|
267
|
+
export { type AgentCard, type AgentCardSkill, type DiffResult, type FieldDiff, type InitResult, NIT_NAMESPACE, type NitBranch, type NitCommit, type NitConfig, type NitHead, type NitRemoteConfig, type PushResult, type RemoteInfo, type SkillMetadata, type StatusResult, branch, checkout, commit, deriveAgentId, diff, diffCards, fetchBranchCard, findNitDir, formatDiff, formatPublicKeyField, init, loadAgentId, log, parsePublicKeyField, push, remote, signChallenge, signMessage, status, verifySignature };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// nit — version control for agent cards
|
|
2
2
|
import {
|
|
3
|
+
NIT_NAMESPACE,
|
|
3
4
|
branch,
|
|
4
5
|
checkout,
|
|
5
6
|
commit,
|
|
7
|
+
deriveAgentId,
|
|
6
8
|
diff,
|
|
7
9
|
diffCards,
|
|
8
10
|
fetchBranchCard,
|
|
@@ -10,19 +12,22 @@ import {
|
|
|
10
12
|
formatDiff,
|
|
11
13
|
formatPublicKeyField,
|
|
12
14
|
init,
|
|
15
|
+
loadAgentId,
|
|
13
16
|
log,
|
|
14
17
|
parsePublicKeyField,
|
|
15
18
|
push,
|
|
16
19
|
remote,
|
|
17
|
-
setCredential,
|
|
18
20
|
signChallenge,
|
|
21
|
+
signMessage,
|
|
19
22
|
status,
|
|
20
23
|
verifySignature
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-7KTMZ67T.js";
|
|
22
25
|
export {
|
|
26
|
+
NIT_NAMESPACE,
|
|
23
27
|
branch,
|
|
24
28
|
checkout,
|
|
25
29
|
commit,
|
|
30
|
+
deriveAgentId,
|
|
26
31
|
diff,
|
|
27
32
|
diffCards,
|
|
28
33
|
fetchBranchCard,
|
|
@@ -30,12 +35,13 @@ export {
|
|
|
30
35
|
formatDiff,
|
|
31
36
|
formatPublicKeyField,
|
|
32
37
|
init,
|
|
38
|
+
loadAgentId,
|
|
33
39
|
log,
|
|
34
40
|
parsePublicKeyField,
|
|
35
41
|
push,
|
|
36
42
|
remote,
|
|
37
|
-
setCredential,
|
|
38
43
|
signChallenge,
|
|
44
|
+
signMessage,
|
|
39
45
|
status,
|
|
40
46
|
verifySignature
|
|
41
47
|
};
|