@newtype-ai/nit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ // nit — version control for agent cards
3
+ import {
4
+ branch,
5
+ checkout,
6
+ commit,
7
+ diff,
8
+ formatDiff,
9
+ init,
10
+ log,
11
+ push,
12
+ remote,
13
+ status
14
+ } from "./chunk-5EGCFUZ7.js";
15
+
16
+ // src/cli.ts
17
+ var bold = (s) => `\x1B[1m${s}\x1B[0m`;
18
+ var green = (s) => `\x1B[32m${s}\x1B[0m`;
19
+ var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
20
+ var red = (s) => `\x1B[31m${s}\x1B[0m`;
21
+ var dim = (s) => `\x1B[2m${s}\x1B[0m`;
22
+ async function main() {
23
+ const [, , command, ...args] = process.argv;
24
+ try {
25
+ switch (command) {
26
+ case "init":
27
+ await cmdInit();
28
+ break;
29
+ case "status":
30
+ await cmdStatus();
31
+ break;
32
+ case "commit":
33
+ await cmdCommit(args);
34
+ break;
35
+ case "log":
36
+ await cmdLog();
37
+ break;
38
+ case "diff":
39
+ await cmdDiff(args);
40
+ break;
41
+ case "branch":
42
+ await cmdBranch(args);
43
+ break;
44
+ case "checkout":
45
+ await cmdCheckout(args);
46
+ break;
47
+ case "push":
48
+ await cmdPush(args);
49
+ break;
50
+ case "remote":
51
+ await cmdRemote();
52
+ break;
53
+ case "help":
54
+ case "--help":
55
+ case "-h":
56
+ case void 0:
57
+ printUsage();
58
+ break;
59
+ default:
60
+ console.error(`nit: '${command}' is not a nit command. See 'nit help'.`);
61
+ process.exit(1);
62
+ }
63
+ } catch (err) {
64
+ const msg = err instanceof Error ? err.message : String(err);
65
+ console.error(red(`error: ${msg}`));
66
+ process.exit(1);
67
+ }
68
+ }
69
+ async function cmdInit() {
70
+ const result = await init();
71
+ console.log(bold("Initialized nit repository"));
72
+ console.log();
73
+ console.log(` Public key: ${green(result.publicKey)}`);
74
+ if (result.cardUrl) {
75
+ console.log(` Card URL: ${result.cardUrl}`);
76
+ }
77
+ if (result.skillsFound.length > 0) {
78
+ console.log(` Skills: ${result.skillsFound.join(", ")}`);
79
+ } else {
80
+ console.log(` Skills: ${dim("(none discovered)")}`);
81
+ }
82
+ console.log();
83
+ console.log(dim("Created .nit/ with initial commit on main."));
84
+ }
85
+ async function cmdStatus() {
86
+ const s = await status();
87
+ console.log(`On branch ${bold(s.branch)}`);
88
+ console.log(`Public key: ${dim(s.publicKey)}`);
89
+ console.log();
90
+ if (s.uncommittedChanges) {
91
+ console.log(yellow("Uncommitted changes:"));
92
+ console.log(formatDiff(s.uncommittedChanges));
93
+ console.log();
94
+ } else {
95
+ console.log(green("Working card clean."));
96
+ console.log();
97
+ }
98
+ if (s.branches.length > 0) {
99
+ for (const b of s.branches) {
100
+ const marker = b.name === s.branch ? "* " : " ";
101
+ const ahead = b.ahead > 0 ? yellow(` [ahead ${b.ahead}]`) : "";
102
+ console.log(`${marker}${b.name}${ahead}`);
103
+ }
104
+ }
105
+ }
106
+ async function cmdCommit(args) {
107
+ let message = "";
108
+ const mIndex = args.indexOf("-m");
109
+ if (mIndex !== -1 && args[mIndex + 1]) {
110
+ message = args[mIndex + 1];
111
+ } else {
112
+ console.error('Usage: nit commit -m "message"');
113
+ process.exit(1);
114
+ }
115
+ const c = await commit(message);
116
+ console.log(
117
+ `${dim(`[${c.hash.slice(0, 8)}]`)} ${c.message}`
118
+ );
119
+ }
120
+ async function cmdLog() {
121
+ const commits = await log();
122
+ for (const c of commits) {
123
+ const date = new Date(c.timestamp * 1e3).toISOString().slice(0, 19);
124
+ console.log(
125
+ `${yellow(c.hash.slice(0, 8))} ${c.message} ${dim(`(${c.author}, ${date})`)}`
126
+ );
127
+ }
128
+ if (commits.length === 0) {
129
+ console.log(dim("No commits yet."));
130
+ }
131
+ }
132
+ async function cmdDiff(args) {
133
+ const target = args[0];
134
+ const d = await diff(target);
135
+ console.log(formatDiff(d));
136
+ }
137
+ async function cmdBranch(args) {
138
+ const name = args[0];
139
+ const branches = await branch(name);
140
+ if (name) {
141
+ console.log(`Branch '${green(name)}' created.`);
142
+ }
143
+ let currentBranch;
144
+ try {
145
+ const s = await status();
146
+ currentBranch = s.branch;
147
+ } catch {
148
+ currentBranch = "";
149
+ }
150
+ for (const b of branches) {
151
+ if (b.name === currentBranch) {
152
+ console.log(`* ${green(b.name)}`);
153
+ } else {
154
+ console.log(` ${b.name}`);
155
+ }
156
+ }
157
+ }
158
+ async function cmdCheckout(args) {
159
+ const branchName = args[0];
160
+ if (!branchName) {
161
+ console.error("Usage: nit checkout <branch>");
162
+ process.exit(1);
163
+ }
164
+ await checkout(branchName);
165
+ console.log(`Switched to branch '${green(branchName)}'.`);
166
+ }
167
+ async function cmdPush(args) {
168
+ const all = args.includes("--all");
169
+ const results = await push({ all });
170
+ for (const r of results) {
171
+ if (r.success) {
172
+ console.log(`${green("\u2713")} ${r.branch} \u2192 ${r.remoteUrl}`);
173
+ } else {
174
+ console.log(`${red("\u2717")} ${r.branch}: ${r.error}`);
175
+ }
176
+ }
177
+ }
178
+ async function cmdRemote() {
179
+ const info = await remote();
180
+ console.log(`${bold(info.name)}`);
181
+ console.log(` URL: ${info.url}`);
182
+ console.log(
183
+ ` Credential: ${info.hasCredential ? green("configured") : yellow("not set")}`
184
+ );
185
+ }
186
+ function printUsage() {
187
+ console.log(`
188
+ ${bold("nit")} \u2014 version control for agent cards
189
+
190
+ ${bold("Usage:")} nit <command> [options]
191
+
192
+ ${bold("Commands:")}
193
+ init Initialize .nit/ in current directory
194
+ status Show current branch and uncommitted changes
195
+ commit -m "msg" Snapshot agent-card.json
196
+ log Show commit history
197
+ diff [target] Compare card vs HEAD, branch, or commit
198
+ branch [name] List branches or create a new one
199
+ checkout <branch> Switch branch (overwrites agent-card.json)
200
+ push [--all] Push branch(es) to remote
201
+ remote Show remote info
202
+
203
+ ${bold("Examples:")}
204
+ nit init
205
+ nit branch faam.fun
206
+ nit checkout faam.fun
207
+ ${dim("# edit agent-card.json for FAAM...")}
208
+ nit commit -m "FAAM config"
209
+ nit push --all
210
+ `.trim());
211
+ }
212
+ main();
@@ -0,0 +1,243 @@
1
+ /** Commit object referencing a card snapshot. */
2
+ interface NitCommit {
3
+ type: 'commit';
4
+ /** SHA-256 hex digest of the serialized commit */
5
+ hash: string;
6
+ /** Card object hash */
7
+ card: string;
8
+ /** Parent commit hash (null for initial commit) */
9
+ parent: string | null;
10
+ /** Author name or ID */
11
+ author: string;
12
+ /** Unix timestamp in seconds */
13
+ timestamp: number;
14
+ /** Commit message */
15
+ message: string;
16
+ }
17
+ /** A branch is a named pointer to a commit hash. */
18
+ interface NitBranch {
19
+ name: string;
20
+ commitHash: string;
21
+ }
22
+ /** HEAD is always a symbolic ref pointing to a branch. */
23
+ interface NitHead {
24
+ type: 'ref';
25
+ /** e.g. "refs/heads/main" */
26
+ ref: string;
27
+ }
28
+ /** Remote configuration for a single named remote. */
29
+ interface NitRemoteConfig {
30
+ /** Push credential (Bearer token) */
31
+ credential?: string;
32
+ }
33
+ /** Full .nit/config file contents. */
34
+ interface NitConfig {
35
+ /** Keyed by remote name (e.g. "origin") */
36
+ remotes: Record<string, NitRemoteConfig>;
37
+ }
38
+ /** A2A-compatible agent card. */
39
+ interface AgentCard {
40
+ protocolVersion: string;
41
+ name: string;
42
+ description: string;
43
+ version: string;
44
+ url: string;
45
+ /** Format: "ed25519:<base64>" — present only on main branch */
46
+ publicKey?: string;
47
+ defaultInputModes: string[];
48
+ defaultOutputModes: string[];
49
+ skills: AgentCardSkill[];
50
+ iconUrl?: string;
51
+ documentationUrl?: string;
52
+ provider?: {
53
+ organization: string;
54
+ url?: string;
55
+ };
56
+ }
57
+ /** A single skill entry in an agent card. */
58
+ interface AgentCardSkill {
59
+ id: string;
60
+ name: string;
61
+ description: string;
62
+ tags?: string[];
63
+ examples?: string[];
64
+ inputModes?: string[];
65
+ outputModes?: string[];
66
+ }
67
+ /** Metadata extracted from a SKILL.md frontmatter. */
68
+ interface SkillMetadata {
69
+ /** Directory name (e.g. "seo-audit") */
70
+ id: string;
71
+ /** From frontmatter `name` field */
72
+ name: string;
73
+ /** From frontmatter `description` field */
74
+ description: string;
75
+ /** From frontmatter `metadata.version` */
76
+ version?: string;
77
+ /** Full filesystem path to the SKILL.md */
78
+ path: string;
79
+ }
80
+ /** Structured diff between two agent cards. */
81
+ interface DiffResult {
82
+ changed: boolean;
83
+ fields: FieldDiff[];
84
+ skillsAdded: string[];
85
+ skillsRemoved: string[];
86
+ skillsModified: string[];
87
+ }
88
+ /** A single field-level change. */
89
+ interface FieldDiff {
90
+ field: string;
91
+ old: unknown;
92
+ new: unknown;
93
+ }
94
+ /** Result of pushing a branch to a remote. */
95
+ interface PushResult {
96
+ branch: string;
97
+ commitHash: string;
98
+ remoteUrl: string;
99
+ success: boolean;
100
+ error?: string;
101
+ }
102
+ /** Result returned by the status command. */
103
+ interface StatusResult {
104
+ branch: string;
105
+ publicKey: string;
106
+ uncommittedChanges: DiffResult | null;
107
+ branches: Array<{
108
+ name: string;
109
+ ahead: number;
110
+ behind: number;
111
+ }>;
112
+ }
113
+
114
+ /**
115
+ * Compare two agent cards and return a structured diff.
116
+ */
117
+ declare function diffCards(oldCard: AgentCard, newCard: AgentCard): DiffResult;
118
+ /**
119
+ * Format a diff result for terminal display.
120
+ */
121
+ declare function formatDiff(diff: DiffResult): string;
122
+
123
+ /**
124
+ * Format a raw base64 public key as the value for the agent card's
125
+ * `publicKey` field: "ed25519:<base64>".
126
+ */
127
+ declare function formatPublicKeyField(pubBase64: string): string;
128
+ /**
129
+ * Extract the raw base64 key from an "ed25519:<base64>" field value.
130
+ */
131
+ declare function parsePublicKeyField(field: string): string;
132
+ /**
133
+ * Sign a challenge string with the agent's private key.
134
+ * Returns a standard base64-encoded signature.
135
+ */
136
+ declare function signChallenge(nitDir: string, challenge: string): Promise<string>;
137
+ /**
138
+ * Verify a signature against a challenge using the raw base64 public key.
139
+ * This is a utility for consumers; nit itself uses it in the remote module
140
+ * for challenge-response flows.
141
+ */
142
+ declare function verifySignature(pubBase64: string, challenge: string, signatureBase64: string): boolean;
143
+
144
+ /**
145
+ * Fetch an agent card from a remote URL.
146
+ *
147
+ * For the main branch, this is a simple public GET.
148
+ * For other branches, this performs the challenge-response flow:
149
+ * 1. Request branch → 401 with challenge
150
+ * 2. Sign challenge with agent's private key
151
+ * 3. Re-request with signature → get branch card
152
+ *
153
+ * @param cardUrl The agent's card URL (e.g. https://agent-{uuid}.newtype-ai.org)
154
+ * @param branch Branch to fetch ("main" for public, others need auth)
155
+ * @param nitDir Path to .nit/ directory (needed for signing non-main requests)
156
+ */
157
+ declare function fetchBranchCard(cardUrl: string, branch: string, nitDir?: string): Promise<AgentCard>;
158
+
159
+ /**
160
+ * Walk up from startDir looking for a .nit/ directory.
161
+ * Returns the path to .nit/ or throws if not found.
162
+ */
163
+ declare function findNitDir(startDir?: string): string;
164
+ interface InitResult {
165
+ publicKey: string;
166
+ cardUrl: string | null;
167
+ skillsFound: string[];
168
+ }
169
+ /**
170
+ * Initialize a new nit repository in the project directory.
171
+ *
172
+ * 1. Create .nit/ directory structure
173
+ * 2. Generate Ed25519 keypair
174
+ * 3. Create or update agent-card.json with publicKey
175
+ * 4. Create initial commit on main branch
176
+ */
177
+ declare function init(options?: {
178
+ projectDir?: string;
179
+ }): Promise<InitResult>;
180
+ /**
181
+ * Show current branch, uncommitted changes, and ahead/behind remote.
182
+ */
183
+ declare function status(options?: {
184
+ projectDir?: string;
185
+ }): Promise<StatusResult>;
186
+ /**
187
+ * Snapshot the current agent-card.json as a new commit.
188
+ * Resolves skill pointers from SKILL.md before committing.
189
+ */
190
+ declare function commit(message: string, options?: {
191
+ projectDir?: string;
192
+ }): Promise<NitCommit>;
193
+ /**
194
+ * Walk the commit chain from the current branch HEAD.
195
+ */
196
+ declare function log(options?: {
197
+ projectDir?: string;
198
+ count?: number;
199
+ }): Promise<NitCommit[]>;
200
+ /**
201
+ * Compare the current card against a target.
202
+ *
203
+ * - No target: working card vs HEAD
204
+ * - Branch name: HEAD vs target branch HEAD
205
+ * - Commit hash (64 hex chars): HEAD vs specific commit
206
+ */
207
+ declare function diff(target?: string, options?: {
208
+ projectDir?: string;
209
+ }): Promise<DiffResult>;
210
+ /**
211
+ * List branches (no name) or create a new branch (with name).
212
+ */
213
+ declare function branch(name?: string, options?: {
214
+ projectDir?: string;
215
+ }): Promise<NitBranch[]>;
216
+ /**
217
+ * Switch to a different branch. Overwrites agent-card.json with the
218
+ * branch's version. Aborts if there are uncommitted changes.
219
+ */
220
+ declare function checkout(branchName: string, options?: {
221
+ projectDir?: string;
222
+ }): Promise<void>;
223
+ /**
224
+ * Push current branch (or all branches) to the remote.
225
+ */
226
+ declare function push(options?: {
227
+ projectDir?: string;
228
+ remoteName?: string;
229
+ all?: boolean;
230
+ }): Promise<PushResult[]>;
231
+ interface RemoteInfo {
232
+ name: string;
233
+ url: string;
234
+ hasCredential: boolean;
235
+ }
236
+ /**
237
+ * Show remote info. URL comes from agent-card.json, credential from .nit/config.
238
+ */
239
+ declare function remote(options?: {
240
+ projectDir?: string;
241
+ }): Promise<RemoteInfo>;
242
+
243
+ 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, signChallenge, status, verifySignature };
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ // nit — version control for agent cards
2
+ import {
3
+ branch,
4
+ checkout,
5
+ commit,
6
+ diff,
7
+ diffCards,
8
+ fetchBranchCard,
9
+ findNitDir,
10
+ formatDiff,
11
+ formatPublicKeyField,
12
+ init,
13
+ log,
14
+ parsePublicKeyField,
15
+ push,
16
+ remote,
17
+ signChallenge,
18
+ status,
19
+ verifySignature
20
+ } from "./chunk-5EGCFUZ7.js";
21
+ export {
22
+ branch,
23
+ checkout,
24
+ commit,
25
+ diff,
26
+ diffCards,
27
+ fetchBranchCard,
28
+ findNitDir,
29
+ formatDiff,
30
+ formatPublicKeyField,
31
+ init,
32
+ log,
33
+ parsePublicKeyField,
34
+ push,
35
+ remote,
36
+ signChallenge,
37
+ status,
38
+ verifySignature
39
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@newtype-ai/nit",
3
+ "version": "0.1.0",
4
+ "description": "Version control for agent cards",
5
+ "type": "module",
6
+ "bin": {
7
+ "nit": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "prepublishOnly": "tsup"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "keywords": [
28
+ "agent-card",
29
+ "version-control",
30
+ "nit",
31
+ "identity",
32
+ "a2a",
33
+ "ed25519"
34
+ ],
35
+ "author": "newtype-ai",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/newtype-ai/nit"
40
+ },
41
+ "homepage": "https://github.com/newtype-ai/nit",
42
+ "devDependencies": {
43
+ "@types/node": "^25.3.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.0.0"
46
+ }
47
+ }