@cef-ai/cli 0.3.0 → 0.4.1
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-program.d.ts +14 -0
- package/dist/cli-program.d.ts.map +1 -0
- package/dist/cli-program.js +171 -0
- package/dist/cli-program.js.map +1 -0
- package/dist/cli.js +4 -89
- package/dist/cli.js.map +1 -1
- package/dist/commands/keypair.d.ts +21 -0
- package/dist/commands/keypair.d.ts.map +1 -0
- package/dist/commands/keypair.js +91 -0
- package/dist/commands/keypair.js.map +1 -0
- package/dist/commands/publish.d.ts +40 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +199 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/lib/cid.d.ts +3 -0
- package/dist/lib/cid.d.ts.map +1 -0
- package/dist/lib/cid.js +43 -0
- package/dist/lib/cid.js.map +1 -0
- package/dist/lib/credentials.d.ts +43 -0
- package/dist/lib/credentials.d.ts.map +1 -0
- package/dist/lib/credentials.js +241 -0
- package/dist/lib/credentials.js.map +1 -0
- package/dist/lib/jcs.d.ts +3 -0
- package/dist/lib/jcs.d.ts.map +1 -0
- package/dist/lib/jcs.js +48 -0
- package/dist/lib/jcs.js.map +1 -0
- package/dist/lib/signing.d.ts +13 -0
- package/dist/lib/signing.d.ts.map +1 -0
- package/dist/lib/signing.js +34 -0
- package/dist/lib/signing.js.map +1 -0
- package/dist/lib.d.ts +6 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -0
- package/dist/lib.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare const DEFAULT_MARKETPLACE_URL = "https://agent-marketplace.compute.dev.ddcdragon.com";
|
|
3
|
+
export interface BuildProgramOptions {
|
|
4
|
+
/** Optional fetch override threaded into `cef publish`. Tests use this. */
|
|
5
|
+
fetchImpl?: typeof fetch;
|
|
6
|
+
/**
|
|
7
|
+
* How to surface unrecoverable command errors. The bin entry uses the
|
|
8
|
+
* default (log + process.exit(1)); tests pass a function that throws so
|
|
9
|
+
* vitest's `await program.parseAsync()` rejects observably.
|
|
10
|
+
*/
|
|
11
|
+
onError?: (err: unknown) => never;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildProgram(opts?: BuildProgramOptions): Command;
|
|
14
|
+
//# sourceMappingURL=cli-program.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-program.d.ts","sourceRoot":"","sources":["../src/cli-program.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,eAAO,MAAM,uBAAuB,wDACmB,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,KAAK,CAAC;CACnC;AAQD,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CA0MpE"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commander program factory shared by `./cli.ts` (the bin entry) and the
|
|
3
|
+
* integration tests. Splitting it out keeps the binary itself a thin
|
|
4
|
+
* wrapper that just calls `buildProgram().parseAsync(argv)` while letting
|
|
5
|
+
* tests construct the same wiring without triggering top-level argv
|
|
6
|
+
* parsing on import.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import { cefBuild } from "./commands/build.js";
|
|
13
|
+
import { cefInspect } from "./commands/inspect.js";
|
|
14
|
+
import { cefKeypairGenerate } from "./commands/keypair.js";
|
|
15
|
+
import { cefPublish } from "./commands/publish.js";
|
|
16
|
+
import { cefTypegen } from "./commands/typegen.js";
|
|
17
|
+
export const DEFAULT_MARKETPLACE_URL = "https://agent-marketplace.compute.dev.ddcdragon.com";
|
|
18
|
+
function defaultOnError(err) {
|
|
19
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
20
|
+
console.error(msg);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
export function buildProgram(opts = {}) {
|
|
24
|
+
const onError = opts.onError ?? defaultOnError;
|
|
25
|
+
// dist/cli-program.js → ../package.json (when running compiled).
|
|
26
|
+
// src/cli-program.ts → ../package.json (when running via vitest in src/).
|
|
27
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const pkg = JSON.parse(readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
29
|
+
const program = new Command();
|
|
30
|
+
program
|
|
31
|
+
.name("cef")
|
|
32
|
+
.description("CEF agent build & test CLI")
|
|
33
|
+
.version(pkg.version);
|
|
34
|
+
program
|
|
35
|
+
.command("build")
|
|
36
|
+
.description("Build agent bundle.js + manifest.json")
|
|
37
|
+
.option("--config <path>", "Path to cef.config.ts")
|
|
38
|
+
.option("--out <dir>", "Output directory", "dist")
|
|
39
|
+
.action(async (subOpts) => {
|
|
40
|
+
try {
|
|
41
|
+
const result = await cefBuild({
|
|
42
|
+
configPath: subOpts.config,
|
|
43
|
+
outDir: subOpts.out,
|
|
44
|
+
});
|
|
45
|
+
for (const a of result.agents) {
|
|
46
|
+
console.log(`[ok] ${a.agentId} -> ${a.bundlePath} (${a.bundleBytes} bytes)`);
|
|
47
|
+
console.log(`[ok] ${a.agentId} -> ${a.manifestPath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
onError(e);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
program
|
|
55
|
+
.command("typegen")
|
|
56
|
+
.description("Generate .cef/generated.d.ts and update cef.lock.json")
|
|
57
|
+
.option("--config <path>", "Path to cef.config.ts")
|
|
58
|
+
.action(async (subOpts) => {
|
|
59
|
+
try {
|
|
60
|
+
const result = await cefTypegen({ configPath: subOpts.config });
|
|
61
|
+
console.log(`[ok] ${result.generatedPath}`);
|
|
62
|
+
console.log(`[ok] ${result.lockfilePath}`);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
onError(e);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
program
|
|
69
|
+
.command("inspect <agentDir>")
|
|
70
|
+
.description("Inspect a built bundle + manifest")
|
|
71
|
+
.action(async (agentDir) => {
|
|
72
|
+
try {
|
|
73
|
+
const result = await cefInspect({ agentDir });
|
|
74
|
+
const anyMissing = result.engagements.some((e) => e.missingMethods.length > 0);
|
|
75
|
+
if (anyMissing)
|
|
76
|
+
process.exit(2);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
onError(e);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Stubs — implemented in subsequent milestones.
|
|
83
|
+
program
|
|
84
|
+
.command("test")
|
|
85
|
+
.description("(stub) run agent tests")
|
|
86
|
+
.action(() => {
|
|
87
|
+
console.log("cef test: not yet implemented (use vitest directly for now)");
|
|
88
|
+
});
|
|
89
|
+
program
|
|
90
|
+
.command("publish")
|
|
91
|
+
.description("Publish a built agent's manifest to the marketplace")
|
|
92
|
+
.option("--marketplace <url>", "Marketplace base URL (overrides $CEF_MARKETPLACE_URL)")
|
|
93
|
+
.option("--agent <id>", "Which dist/<id>/ to publish (defaults to the only built agent)")
|
|
94
|
+
.option("--privkey <hex>", "AS private key (hex, 64 chars). Pair with --pubkey.")
|
|
95
|
+
.option("--pubkey <hex>", "AS public key (hex, 64 chars). Pair with --privkey.")
|
|
96
|
+
.option("--keystore <path>", "Path to a JSON keystore file `{ pubkey, privkey }`")
|
|
97
|
+
.option("--profile <name>", "Profile section in ~/.config/cef/credentials (default: 'default')")
|
|
98
|
+
.option("--out <dir>", "Output directory the build wrote to (defaults to dist)", "dist")
|
|
99
|
+
.action(async (subOpts) => {
|
|
100
|
+
try {
|
|
101
|
+
const marketplaceUrl = subOpts.marketplace ??
|
|
102
|
+
process.env.CEF_MARKETPLACE_URL ??
|
|
103
|
+
DEFAULT_MARKETPLACE_URL;
|
|
104
|
+
const publishOpts = {
|
|
105
|
+
marketplaceUrl,
|
|
106
|
+
...(subOpts.agent !== undefined ? { agentId: subOpts.agent } : {}),
|
|
107
|
+
...(subOpts.privkey !== undefined ? { privkey: subOpts.privkey } : {}),
|
|
108
|
+
...(subOpts.pubkey !== undefined ? { pubkey: subOpts.pubkey } : {}),
|
|
109
|
+
...(subOpts.keystore !== undefined ? { keystore: subOpts.keystore } : {}),
|
|
110
|
+
...(subOpts.profile !== undefined ? { profile: subOpts.profile } : {}),
|
|
111
|
+
...(subOpts.out !== undefined ? { distDir: subOpts.out } : {}),
|
|
112
|
+
...(opts.fetchImpl !== undefined ? { fetchImpl: opts.fetchImpl } : {}),
|
|
113
|
+
};
|
|
114
|
+
const result = await cefPublish(publishOpts);
|
|
115
|
+
console.log(`✓ Published ${result.agentId}@${result.version}`);
|
|
116
|
+
console.log(` agentId: ${result.agentId}`);
|
|
117
|
+
console.log(` pubkey: ${result.pubkey}`);
|
|
118
|
+
console.log(` manifestCid: ${result.manifestCid}`);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
// CredentialsError carries either a single-line typo message or
|
|
122
|
+
// the canonical multi-line "no AS credentials configured" guidance
|
|
123
|
+
// block. Both ship through `onError` unchanged — the default impl
|
|
124
|
+
// writes to stderr, which is what we want.
|
|
125
|
+
onError(e);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
const keypair = program
|
|
129
|
+
.command("keypair")
|
|
130
|
+
.description("Manage AS Ed25519 keypairs (Agent Service identity)");
|
|
131
|
+
keypair
|
|
132
|
+
.command("generate")
|
|
133
|
+
.description("Generate a new AS keypair (stdout, --out file, or --profile)")
|
|
134
|
+
.option("--out <path>", "Write the JSON keypair to <path> (mode 0600); refuses existing unless --force")
|
|
135
|
+
.option("--profile <name>", "Write/merge into ~/.config/cef/credentials under [<name>] (mode 0600)")
|
|
136
|
+
.option("--force", "Overwrite an existing --out file or --profile section")
|
|
137
|
+
.action(async (subOpts) => {
|
|
138
|
+
try {
|
|
139
|
+
const result = await cefKeypairGenerate({
|
|
140
|
+
...(subOpts.out !== undefined ? { out: subOpts.out } : {}),
|
|
141
|
+
...(subOpts.profile !== undefined ? { profile: subOpts.profile } : {}),
|
|
142
|
+
...(subOpts.force !== undefined ? { force: subOpts.force } : {}),
|
|
143
|
+
});
|
|
144
|
+
if (result.path === undefined && result.profile === undefined) {
|
|
145
|
+
// Default sink: print the JSON to stdout.
|
|
146
|
+
process.stdout.write(JSON.stringify({ pubkey: result.pubkey, privkey: result.privkey }) +
|
|
147
|
+
"\n");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const profileSuffix = result.profile
|
|
151
|
+
? ` [profile: ${result.profile}]`
|
|
152
|
+
: "";
|
|
153
|
+
console.log(`✓ AS keypair written to ${result.path}${profileSuffix}`);
|
|
154
|
+
console.log(` Pubkey: ${result.pubkey}`);
|
|
155
|
+
console.log(" This keypair is your Agent Service identity. Keep the private key safe.");
|
|
156
|
+
console.log(" To share with your team, hand them the file or sync it through your team's");
|
|
157
|
+
console.log(" secrets manager — do NOT generate a new one for each developer.");
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
onError(e);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
program
|
|
164
|
+
.command("dev")
|
|
165
|
+
.description("(stub) run dev loop")
|
|
166
|
+
.action(() => {
|
|
167
|
+
console.log("cef dev: not yet implemented");
|
|
168
|
+
});
|
|
169
|
+
return program;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=cli-program.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-program.js","sourceRoot":"","sources":["../src/cli-program.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -3,106 +3,21 @@
|
|
|
3
3
|
* `cef` CLI binary entry point. Wires the programmatic command functions
|
|
4
4
|
* (re-exported from `./lib.ts`) into commander subcommands.
|
|
5
5
|
*
|
|
6
|
-
* Subcommands implemented
|
|
6
|
+
* Subcommands implemented:
|
|
7
7
|
* - build : bundle agents per cef.config.ts
|
|
8
8
|
* - typegen : generate .cef/generated.d.ts + cef.lock.json
|
|
9
9
|
* - inspect : print manifest routing + bundle methods for a built agent
|
|
10
|
+
* - publish : sign + POST a built manifest to the marketplace API
|
|
10
11
|
*
|
|
11
12
|
* Stubs (planned for the next phase):
|
|
12
|
-
* - test,
|
|
13
|
+
* - test, dev
|
|
13
14
|
*/
|
|
14
|
-
import {
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { Command } from "commander";
|
|
18
|
-
import { cefBuild } from "./commands/build.js";
|
|
19
|
-
import { cefInspect } from "./commands/inspect.js";
|
|
20
|
-
import { cefTypegen } from "./commands/typegen.js";
|
|
21
|
-
// dist/cli.js → ../package.json. Read at runtime so `cef --version` always
|
|
22
|
-
// reflects the published package version rather than a hardcoded literal.
|
|
23
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
24
|
-
const pkg = JSON.parse(readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
15
|
+
import { buildProgram } from "./cli-program.js";
|
|
25
16
|
function fail(err) {
|
|
26
17
|
const msg = err instanceof Error ? err.message : String(err);
|
|
27
18
|
console.error(msg);
|
|
28
19
|
process.exit(1);
|
|
29
20
|
}
|
|
30
|
-
function buildProgram() {
|
|
31
|
-
const program = new Command();
|
|
32
|
-
program
|
|
33
|
-
.name("cef")
|
|
34
|
-
.description("CEF agent build & test CLI")
|
|
35
|
-
.version(pkg.version);
|
|
36
|
-
program
|
|
37
|
-
.command("build")
|
|
38
|
-
.description("Build agent bundle.js + manifest.json")
|
|
39
|
-
.option("--config <path>", "Path to cef.config.ts")
|
|
40
|
-
.option("--out <dir>", "Output directory", "dist")
|
|
41
|
-
.action(async (opts) => {
|
|
42
|
-
try {
|
|
43
|
-
const result = await cefBuild({
|
|
44
|
-
configPath: opts.config,
|
|
45
|
-
outDir: opts.out,
|
|
46
|
-
});
|
|
47
|
-
for (const a of result.agents) {
|
|
48
|
-
console.log(`[ok] ${a.agentId} -> ${a.bundlePath} (${a.bundleBytes} bytes)`);
|
|
49
|
-
console.log(`[ok] ${a.agentId} -> ${a.manifestPath}`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
fail(e);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
program
|
|
57
|
-
.command("typegen")
|
|
58
|
-
.description("Generate .cef/generated.d.ts and update cef.lock.json")
|
|
59
|
-
.option("--config <path>", "Path to cef.config.ts")
|
|
60
|
-
.action(async (opts) => {
|
|
61
|
-
try {
|
|
62
|
-
const result = await cefTypegen({ configPath: opts.config });
|
|
63
|
-
console.log(`[ok] ${result.generatedPath}`);
|
|
64
|
-
console.log(`[ok] ${result.lockfilePath}`);
|
|
65
|
-
}
|
|
66
|
-
catch (e) {
|
|
67
|
-
fail(e);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
program
|
|
71
|
-
.command("inspect <agentDir>")
|
|
72
|
-
.description("Inspect a built bundle + manifest")
|
|
73
|
-
.action(async (agentDir) => {
|
|
74
|
-
try {
|
|
75
|
-
const result = await cefInspect({ agentDir });
|
|
76
|
-
const anyMissing = result.engagements.some((e) => e.missingMethods.length > 0);
|
|
77
|
-
if (anyMissing)
|
|
78
|
-
process.exit(2);
|
|
79
|
-
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
fail(e);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
// Stubs for v1 — implemented in the next phase. They print and exit 0
|
|
85
|
-
// so a CI step that calls them does not fail (placeholder behaviour).
|
|
86
|
-
program
|
|
87
|
-
.command("test")
|
|
88
|
-
.description("(stub) run agent tests")
|
|
89
|
-
.action(() => {
|
|
90
|
-
console.log("cef test: not yet implemented (use vitest directly for now)");
|
|
91
|
-
});
|
|
92
|
-
program
|
|
93
|
-
.command("publish")
|
|
94
|
-
.description("(stub) publish to marketplace")
|
|
95
|
-
.action(() => {
|
|
96
|
-
console.log("cef publish: not yet implemented");
|
|
97
|
-
});
|
|
98
|
-
program
|
|
99
|
-
.command("dev")
|
|
100
|
-
.description("(stub) run dev loop")
|
|
101
|
-
.action(() => {
|
|
102
|
-
console.log("cef dev: not yet implemented");
|
|
103
|
-
});
|
|
104
|
-
return program;
|
|
105
|
-
}
|
|
106
21
|
// Top-level await is fine: the package is "type": "module" with
|
|
107
22
|
// "module": "NodeNext" which targets ES2022.
|
|
108
23
|
try {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,SAAS,IAAI,CAAC,GAAY;IACxB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,gEAAgE;AAChE,6CAA6C;AAC7C,IAAI,CAAC;IACH,MAAM,YAAY,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAAC,OAAO,CAAC,EAAE,CAAC;IACX,IAAI,CAAC,CAAC,CAAC,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface CefKeypairGenerateOptions {
|
|
2
|
+
/** Write the JSON keypair to this path. Mutually exclusive with `profile`. */
|
|
3
|
+
out?: string;
|
|
4
|
+
/** Write/merge into the shared credentials file under this section. */
|
|
5
|
+
profile?: string;
|
|
6
|
+
/** Allow overwriting an existing file or profile. */
|
|
7
|
+
force?: boolean;
|
|
8
|
+
/** Override the credentials file path (tests). */
|
|
9
|
+
configFilePath?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CefKeypairGenerateResult {
|
|
12
|
+
pubkey: string;
|
|
13
|
+
/** Hex-encoded private seed. */
|
|
14
|
+
privkey: string;
|
|
15
|
+
/** File path written, when `out` or `profile` was set. */
|
|
16
|
+
path?: string;
|
|
17
|
+
/** Profile name written, when `profile` was set. */
|
|
18
|
+
profile?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function cefKeypairGenerate(opts?: CefKeypairGenerateOptions): Promise<CefKeypairGenerateResult>;
|
|
21
|
+
//# sourceMappingURL=keypair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keypair.d.ts","sourceRoot":"","sources":["../../src/commands/keypair.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiCD,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,yBAA8B,GACnC,OAAO,CAAC,wBAAwB,CAAC,CA8CnC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cef keypair generate` — explicit AS Ed25519 keypair provisioning.
|
|
3
|
+
*
|
|
4
|
+
* The AS keypair represents an Agent Service identity, potentially shared
|
|
5
|
+
* across a team. This command is the *only* place a keypair is materialised;
|
|
6
|
+
* `cef publish` never auto-generates. Output sinks:
|
|
7
|
+
*
|
|
8
|
+
* - stdout (default): JSON `{ pubkey, privkey }`. Useful for `| pbcopy` or
|
|
9
|
+
* piping into a secrets manager.
|
|
10
|
+
* - `--out <path>`: writes the JSON to a file with mode 0600. Refuses
|
|
11
|
+
* existing files unless `--force`.
|
|
12
|
+
* - `--profile <name>`: writes/merges into the shared
|
|
13
|
+
* `~/.config/cef/credentials` INI file, mode 0600. Refuses to overwrite
|
|
14
|
+
* an existing profile unless `--force`. Atomic via temp + rename.
|
|
15
|
+
*
|
|
16
|
+
* The post-write banner reminds the developer this is identity material
|
|
17
|
+
* meant to be shared with their team, not generated per-developer.
|
|
18
|
+
*/
|
|
19
|
+
import fs from "node:fs/promises";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { defaultCredentialsFilePath, parseConfigFile, serializeConfigFile, } from "../lib/credentials.js";
|
|
22
|
+
import { generateKeypair } from "../lib/signing.js";
|
|
23
|
+
function bytesToHex(b) {
|
|
24
|
+
let s = "";
|
|
25
|
+
for (let i = 0; i < b.length; i++)
|
|
26
|
+
s += b[i].toString(16).padStart(2, "0");
|
|
27
|
+
return s;
|
|
28
|
+
}
|
|
29
|
+
async function exists(p) {
|
|
30
|
+
try {
|
|
31
|
+
await fs.stat(p);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (e.code === "ENOENT")
|
|
36
|
+
return false;
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function atomicWrite(filePath, content) {
|
|
41
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
42
|
+
// Temp in the same dir so rename stays atomic across the same fs.
|
|
43
|
+
const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
44
|
+
await fs.writeFile(tmp, content, { encoding: "utf8", mode: 0o600 });
|
|
45
|
+
try {
|
|
46
|
+
await fs.rename(tmp, filePath);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
await fs.rm(tmp, { force: true });
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
// chmod after rename in case the file pre-existed with looser perms.
|
|
53
|
+
await fs.chmod(filePath, 0o600).catch(() => { });
|
|
54
|
+
}
|
|
55
|
+
export async function cefKeypairGenerate(opts = {}) {
|
|
56
|
+
if (opts.out !== undefined && opts.profile !== undefined) {
|
|
57
|
+
throw new Error("cef keypair generate: --out and --profile are mutually exclusive");
|
|
58
|
+
}
|
|
59
|
+
const { pubkey, privkeyBytes } = await generateKeypair();
|
|
60
|
+
const privkey = bytesToHex(privkeyBytes);
|
|
61
|
+
// Profile sink: merge into the shared credentials file.
|
|
62
|
+
if (opts.profile !== undefined) {
|
|
63
|
+
const filePath = opts.configFilePath ?? defaultCredentialsFilePath();
|
|
64
|
+
let parsed = {};
|
|
65
|
+
try {
|
|
66
|
+
const existing = await fs.readFile(filePath, "utf8");
|
|
67
|
+
parsed = parseConfigFile(existing);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e.code !== "ENOENT")
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
if (parsed[opts.profile] && !opts.force) {
|
|
74
|
+
throw new Error(`cef keypair generate: profile [${opts.profile}] already exists in ${filePath} (pass --force to overwrite)`);
|
|
75
|
+
}
|
|
76
|
+
parsed[opts.profile] = { pubkey, privkey };
|
|
77
|
+
await atomicWrite(filePath, serializeConfigFile(parsed));
|
|
78
|
+
return { pubkey, privkey, path: filePath, profile: opts.profile };
|
|
79
|
+
}
|
|
80
|
+
// File sink: write the JSON keystore to `out`.
|
|
81
|
+
if (opts.out !== undefined) {
|
|
82
|
+
if ((await exists(opts.out)) && !opts.force) {
|
|
83
|
+
throw new Error(`cef keypair generate: ${opts.out} already exists (pass --force to overwrite)`);
|
|
84
|
+
}
|
|
85
|
+
await atomicWrite(opts.out, JSON.stringify({ pubkey, privkey }, null, 2) + "\n");
|
|
86
|
+
return { pubkey, privkey, path: opts.out };
|
|
87
|
+
}
|
|
88
|
+
// Default sink: stdout. Caller (CLI wrapper) prints the JSON.
|
|
89
|
+
return { pubkey, privkey };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=keypair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keypair.js","sourceRoot":"","sources":["../../src/commands/keypair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type AsCredentials, type ResolveCredentialsOptions } from "../lib/credentials.js";
|
|
2
|
+
export interface CefPublishOptions {
|
|
3
|
+
/** Resolved marketplace base URL — no trailing slash assumed. */
|
|
4
|
+
marketplaceUrl: string;
|
|
5
|
+
/** Which `dist/<id>/` to publish; auto-detected when undefined. */
|
|
6
|
+
agentId?: string;
|
|
7
|
+
/** Hex private seed (pairs with `pubkey`); highest-priority credential source. */
|
|
8
|
+
privkey?: string;
|
|
9
|
+
/** Hex public key paired with `privkey`. */
|
|
10
|
+
pubkey?: string;
|
|
11
|
+
/** Path to a JSON keystore file `{ pubkey, privkey }`. */
|
|
12
|
+
keystore?: string;
|
|
13
|
+
/** Profile name within the shared `~/.config/cef/credentials` file. */
|
|
14
|
+
profile?: string;
|
|
15
|
+
/** Defaults to `<cwd>/dist`. */
|
|
16
|
+
distDir?: string;
|
|
17
|
+
/** Defaults to `process.cwd()`. */
|
|
18
|
+
cwd?: string;
|
|
19
|
+
/**
|
|
20
|
+
* `fetch` override — defaults to `globalThis.fetch`. Tests pass a stub so
|
|
21
|
+
* the integration spec can assert on the wire shape without touching the
|
|
22
|
+
* network.
|
|
23
|
+
*/
|
|
24
|
+
fetchImpl?: typeof fetch;
|
|
25
|
+
/**
|
|
26
|
+
* Override the credential resolver. Tests inject a fixed keypair this way
|
|
27
|
+
* so they don't have to set up flags/env/files.
|
|
28
|
+
*/
|
|
29
|
+
resolveCredentialsImpl?: (opts: ResolveCredentialsOptions) => Promise<AsCredentials>;
|
|
30
|
+
}
|
|
31
|
+
export interface CefPublishResult {
|
|
32
|
+
/** Whatever `agentId` the marketplace returned (plain alias today). */
|
|
33
|
+
agentId: string;
|
|
34
|
+
version: string;
|
|
35
|
+
manifestCid: string;
|
|
36
|
+
/** Pubkey the manifest was published as (hex). */
|
|
37
|
+
pubkey: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function cefPublish(opts: CefPublishOptions): Promise<CefPublishResult>;
|
|
40
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AA8BA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC/B,MAAM,uBAAuB,CAAC;AAI/B,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,CACvB,IAAI,EAAE,yBAAyB,KAC5B,OAAO,CAAC,aAAa,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB;AAqBD,wBAAsB,UAAU,CAC9B,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAgI3B"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cef publish` — POSTs a built agent's manifest to the CEF marketplace.
|
|
3
|
+
*
|
|
4
|
+
* Wire contract (matches `marketplace/scripts/smoke-publish.ts`):
|
|
5
|
+
*
|
|
6
|
+
* POST <marketplaceUrl>/api/v1/marketplace/agents
|
|
7
|
+
* Headers:
|
|
8
|
+
* Content-Type: application/json
|
|
9
|
+
* X-AS-Pubkey: <hex Ed25519 pubkey>
|
|
10
|
+
* X-AS-Signature: <hex Ed25519 signature over canonical body bytes>
|
|
11
|
+
* Body (JCS-canonicalized JSON):
|
|
12
|
+
* {
|
|
13
|
+
* agentId: <composite "<asPubKey>:<alias>">,
|
|
14
|
+
* version: <semver>,
|
|
15
|
+
* manifest: <full AgentManifest, with agentId + agentServicePubkey filled>,
|
|
16
|
+
* issuedAt: <ISO 8601>,
|
|
17
|
+
* nonce: <base64url 16 random bytes>
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* `cef build` emits the manifest with `agentId` / `agentServicePubkey` left
|
|
21
|
+
* as empty strings; this command stamps them in (composite `<asPubKey>:<alias>`
|
|
22
|
+
* for `agentId`, the loaded AS pubkey for `agentServicePubkey`) before signing
|
|
23
|
+
* so the manifest the server hashes is byte-for-byte the manifest the publisher
|
|
24
|
+
* signs. Vault enforces the `<asPubKey>:` prefix on connect, so the canonical
|
|
25
|
+
* form is composite — the plain alias is recorded only in `manifest.alias`.
|
|
26
|
+
*/
|
|
27
|
+
import crypto from "node:crypto";
|
|
28
|
+
import fs from "node:fs/promises";
|
|
29
|
+
import path from "node:path";
|
|
30
|
+
import { resolveCredentials, } from "../lib/credentials.js";
|
|
31
|
+
import { canonicalize } from "../lib/jcs.js";
|
|
32
|
+
import { signBody } from "../lib/signing.js";
|
|
33
|
+
const DEFAULT_DIST = "dist";
|
|
34
|
+
export async function cefPublish(opts) {
|
|
35
|
+
const cwd = opts.cwd ? path.resolve(opts.cwd) : process.cwd();
|
|
36
|
+
const distDir = opts.distDir
|
|
37
|
+
? path.resolve(cwd, opts.distDir)
|
|
38
|
+
: path.join(cwd, DEFAULT_DIST);
|
|
39
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
40
|
+
if (!fetchImpl) {
|
|
41
|
+
throw new Error("[cef publish] no fetch implementation available (pass opts.fetchImpl or run on Node ≥18)");
|
|
42
|
+
}
|
|
43
|
+
const agentId = opts.agentId ?? (await autodetectAgentId(distDir));
|
|
44
|
+
const agentDir = path.join(distDir, agentId);
|
|
45
|
+
const manifestPath = path.join(agentDir, "manifest.json");
|
|
46
|
+
let manifestRaw;
|
|
47
|
+
try {
|
|
48
|
+
manifestRaw = await fs.readFile(manifestPath, "utf8");
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
const code = e.code;
|
|
52
|
+
if (code === "ENOENT") {
|
|
53
|
+
throw new Error(`[cef publish] manifest not found at ${manifestPath} — run \`cef build\` first`);
|
|
54
|
+
}
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
let manifest;
|
|
58
|
+
try {
|
|
59
|
+
manifest = JSON.parse(manifestRaw);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new Error(`[cef publish] manifest at ${manifestPath} is not valid JSON: ${e.message}`);
|
|
63
|
+
}
|
|
64
|
+
validateManifestShape(manifest, manifestPath);
|
|
65
|
+
// The plain alias is the wire identity. `cef build` writes it to
|
|
66
|
+
// `manifest.alias` (per `prototype.md` §"AgentManifest.Alias") and
|
|
67
|
+
// leaves `manifest.agentId` blank for `cef publish` to fill in.
|
|
68
|
+
const alias = (manifest.alias ?? manifest.agentId);
|
|
69
|
+
const resolver = opts.resolveCredentialsImpl ?? resolveCredentials;
|
|
70
|
+
const credResolveOpts = {
|
|
71
|
+
...(opts.privkey !== undefined ? { privkeyFlag: opts.privkey } : {}),
|
|
72
|
+
...(opts.pubkey !== undefined ? { pubkeyFlag: opts.pubkey } : {}),
|
|
73
|
+
...(opts.keystore !== undefined ? { keystoreFlag: opts.keystore } : {}),
|
|
74
|
+
...(opts.profile !== undefined ? { profileFlag: opts.profile } : {}),
|
|
75
|
+
};
|
|
76
|
+
const { pubkey, privkeyBytes } = await resolver(credResolveOpts);
|
|
77
|
+
// Stamp the manifest's identity fields. The marketplace verifies
|
|
78
|
+
// `manifest.agentId === body.agentId` and we want the persisted manifest
|
|
79
|
+
// bytes to record the AS pubkey too — so the published artifact carries
|
|
80
|
+
// its own provenance even though the wire-level signature is detached.
|
|
81
|
+
//
|
|
82
|
+
// Composite `<pubkey>:<alias>` is the canonical form. Plain-alias was a
|
|
83
|
+
// CLI bug that resulted in vault-side connect failures (`agentId prefix
|
|
84
|
+
// does not match agentServicePubKey`); SDK 0.3.4 normalizes defensively,
|
|
85
|
+
// this stamps canonical at publish time so the marketplace record is
|
|
86
|
+
// correct. Strip a leading `0x` on the pubkey to mirror vault-sdk's
|
|
87
|
+
// `getCompositeAgentId` helper — the credential resolver already requires
|
|
88
|
+
// 64 bare hex chars, but defending here keeps the two helpers symmetric.
|
|
89
|
+
const cleanPubkey = pubkey.startsWith("0x") ? pubkey.slice(2) : pubkey;
|
|
90
|
+
const compositeAgentId = `${cleanPubkey}:${alias}`;
|
|
91
|
+
const stampedManifest = {
|
|
92
|
+
...manifest,
|
|
93
|
+
agentId: compositeAgentId,
|
|
94
|
+
agentServicePubkey: pubkey,
|
|
95
|
+
};
|
|
96
|
+
const body = {
|
|
97
|
+
agentId: compositeAgentId,
|
|
98
|
+
version: stampedManifest.version,
|
|
99
|
+
manifest: stampedManifest,
|
|
100
|
+
issuedAt: new Date().toISOString(),
|
|
101
|
+
nonce: randomBase64UrlNonce(16),
|
|
102
|
+
};
|
|
103
|
+
const canonical = canonicalize(body);
|
|
104
|
+
const signature = await signBody(canonical, privkeyBytes);
|
|
105
|
+
const url = `${opts.marketplaceUrl.replace(/\/+$/, "")}/api/v1/marketplace/agents`;
|
|
106
|
+
const res = await fetchImpl(url, {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: {
|
|
109
|
+
"content-type": "application/json",
|
|
110
|
+
"X-AS-Pubkey": pubkey,
|
|
111
|
+
"X-AS-Signature": signature,
|
|
112
|
+
},
|
|
113
|
+
body: canonical,
|
|
114
|
+
});
|
|
115
|
+
if (res.status === 201) {
|
|
116
|
+
const json = (await res.json());
|
|
117
|
+
if (typeof json.agentId !== "string" ||
|
|
118
|
+
typeof json.version !== "string" ||
|
|
119
|
+
typeof json.manifestCid !== "string") {
|
|
120
|
+
throw new Error(`[cef publish] unexpected 201 body: ${JSON.stringify(json)}`);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
agentId: json.agentId,
|
|
124
|
+
version: json.version,
|
|
125
|
+
manifestCid: json.manifestCid,
|
|
126
|
+
pubkey,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Friendly error path for replays. The marketplace returns
|
|
130
|
+
// `{ error: "REPLAY", ... }` on 409 (see `recordNonce`).
|
|
131
|
+
const text = await res.text();
|
|
132
|
+
if (res.status === 409) {
|
|
133
|
+
throw new Error(`[cef publish] REPLAY: nonce already used (${text})`);
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`[cef publish] marketplace returned HTTP ${res.status}: ${text}`);
|
|
136
|
+
}
|
|
137
|
+
async function autodetectAgentId(distDir) {
|
|
138
|
+
let entries;
|
|
139
|
+
try {
|
|
140
|
+
entries = await fs.readdir(distDir);
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
const code = e.code;
|
|
144
|
+
if (code === "ENOENT") {
|
|
145
|
+
throw new Error(`[cef publish] dist directory ${distDir} not found — run \`cef build\` first`);
|
|
146
|
+
}
|
|
147
|
+
throw e;
|
|
148
|
+
}
|
|
149
|
+
const candidates = [];
|
|
150
|
+
for (const name of entries) {
|
|
151
|
+
const stat = await fs.stat(path.join(distDir, name)).catch(() => null);
|
|
152
|
+
if (!stat?.isDirectory())
|
|
153
|
+
continue;
|
|
154
|
+
// Only consider dirs that actually contain a manifest.json.
|
|
155
|
+
const has = await fs
|
|
156
|
+
.stat(path.join(distDir, name, "manifest.json"))
|
|
157
|
+
.then(() => true)
|
|
158
|
+
.catch(() => false);
|
|
159
|
+
if (has)
|
|
160
|
+
candidates.push(name);
|
|
161
|
+
}
|
|
162
|
+
if (candidates.length === 0) {
|
|
163
|
+
throw new Error(`[cef publish] no built agents found in ${distDir} — run \`cef build\` first`);
|
|
164
|
+
}
|
|
165
|
+
if (candidates.length > 1) {
|
|
166
|
+
throw new Error(`[cef publish] multiple built agents in ${distDir} (${candidates
|
|
167
|
+
.sort()
|
|
168
|
+
.join(", ")}) — pass \`--agent <id>\` to pick one`);
|
|
169
|
+
}
|
|
170
|
+
return candidates[0];
|
|
171
|
+
}
|
|
172
|
+
function validateManifestShape(m, source) {
|
|
173
|
+
const missing = [];
|
|
174
|
+
// Build emits both `alias` and (placeholder) `agentId`; treat presence of
|
|
175
|
+
// either as the alias. Spec calls this out as `id (alias)`.
|
|
176
|
+
if (!m.alias && !m.agentId)
|
|
177
|
+
missing.push("alias|agentId");
|
|
178
|
+
if (!m.version)
|
|
179
|
+
missing.push("version");
|
|
180
|
+
if (!m.card)
|
|
181
|
+
missing.push("card");
|
|
182
|
+
else {
|
|
183
|
+
if (!m.card.name)
|
|
184
|
+
missing.push("card.name");
|
|
185
|
+
if (!m.card.description)
|
|
186
|
+
missing.push("card.description");
|
|
187
|
+
}
|
|
188
|
+
if (!Array.isArray(m.handles))
|
|
189
|
+
missing.push("handles[]");
|
|
190
|
+
if (!Array.isArray(m.publishes))
|
|
191
|
+
missing.push("publishes[]");
|
|
192
|
+
if (missing.length > 0) {
|
|
193
|
+
throw new Error(`[cef publish] manifest at ${source} is missing required fields: ${missing.join(", ")}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function randomBase64UrlNonce(numBytes) {
|
|
197
|
+
return crypto.randomBytes(numBytes).toString("base64url");
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cid.d.ts","sourceRoot":"","sources":["../../src/lib/cid.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAI7C,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI3D"}
|
package/dist/lib/cid.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest CID (`blake3:<base32>`) — the content-addressed identifier the
|
|
3
|
+
* marketplace stores for each published manifest.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the marketplace's `lib/manifest/cid.ts`:
|
|
6
|
+
* - JCS-canonicalize the manifest object,
|
|
7
|
+
* - BLAKE3-hash the UTF-8 bytes,
|
|
8
|
+
* - base32-encode (RFC 4648 lowercase alphabet, NO padding),
|
|
9
|
+
* - prefix with `blake3:`.
|
|
10
|
+
*
|
|
11
|
+
* The cef CLI computes this locally so it can echo the expected CID back to
|
|
12
|
+
* the user (and so a future smoke test could compare against the server's
|
|
13
|
+
* returned `manifestCid` without round-tripping the network).
|
|
14
|
+
*/
|
|
15
|
+
import { blake3 } from "@noble/hashes/blake3.js";
|
|
16
|
+
import { canonicalizeBytes } from "./jcs.js";
|
|
17
|
+
export const MANIFEST_CID_PREFIX = "blake3:";
|
|
18
|
+
const BASE32_ALPHABET = "abcdefghijklmnopqrstuvwxyz234567";
|
|
19
|
+
export function computeManifestCid(manifest) {
|
|
20
|
+
const bytes = canonicalizeBytes(manifest);
|
|
21
|
+
const digest = blake3(bytes);
|
|
22
|
+
return MANIFEST_CID_PREFIX + base32EncodeNoPadding(digest);
|
|
23
|
+
}
|
|
24
|
+
function base32EncodeNoPadding(bytes) {
|
|
25
|
+
let out = "";
|
|
26
|
+
let buffer = 0;
|
|
27
|
+
let bits = 0;
|
|
28
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
29
|
+
buffer = (buffer << 8) | bytes[i];
|
|
30
|
+
bits += 8;
|
|
31
|
+
while (bits >= 5) {
|
|
32
|
+
bits -= 5;
|
|
33
|
+
const idx = (buffer >> bits) & 0b11111;
|
|
34
|
+
out += BASE32_ALPHABET[idx];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (bits > 0) {
|
|
38
|
+
const idx = (buffer << (5 - bits)) & 0b11111;
|
|
39
|
+
out += BASE32_ALPHABET[idx];
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=cid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cid.js","sourceRoot":"","sources":["../../src/lib/cid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,MAAM,eAAe,GAAG,kCAAkC,CAAC;AAE3D,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,mBAAmB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAiB;IAC9C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC;QAC9C,IAAI,IAAI,CAAC,CAAC;QACV,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,CAAC;YACV,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC;YACvC,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC;QAC7C,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type CredentialSource = "flags" | "env" | "keystore-flag" | "keystore-env" | "config-profile";
|
|
2
|
+
export interface AsCredentials {
|
|
3
|
+
/** 64-char lowercase hex (32 bytes), matches the wire format. */
|
|
4
|
+
pubkey: string;
|
|
5
|
+
/** Raw 32-byte Ed25519 seed. */
|
|
6
|
+
privkeyBytes: Uint8Array;
|
|
7
|
+
source: CredentialSource;
|
|
8
|
+
/** Set only when `source === 'config-profile'`. */
|
|
9
|
+
profileName?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ResolveCredentialsOptions {
|
|
12
|
+
privkeyFlag?: string;
|
|
13
|
+
pubkeyFlag?: string;
|
|
14
|
+
keystoreFlag?: string;
|
|
15
|
+
profileFlag?: string;
|
|
16
|
+
/** Defaults to `process.env`. Tests pass an isolated map. */
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
/** Defaults to `<XDG_CONFIG_HOME|~/.config>/cef/credentials`. */
|
|
19
|
+
configFilePath?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class CredentialsError extends Error {
|
|
22
|
+
constructor(message: string);
|
|
23
|
+
}
|
|
24
|
+
export declare function defaultCredentialsFilePath(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a minimal INI file: section headers `[name]`, `key = value` pairs,
|
|
27
|
+
* `;` and `#` line comments. No nested sections, no quoting, no escapes —
|
|
28
|
+
* the credentials file shape is trivial and that's all we need.
|
|
29
|
+
*
|
|
30
|
+
* Returns a map of `{ section: { key: value } }`. Keys/values are trimmed.
|
|
31
|
+
* Pre-section keys live under the empty-string section; the credentials
|
|
32
|
+
* loader only reads named sections so those are ignored.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseConfigFile(content: string): Record<string, Record<string, string>>;
|
|
35
|
+
/**
|
|
36
|
+
* Render a parsed INI map back to text. Sections are emitted in insertion
|
|
37
|
+
* order; the empty-string section (if any) is dropped — this writer only
|
|
38
|
+
* supports section-scoped credentials. Used by `cef keypair generate
|
|
39
|
+
* --profile` when merging into the shared credentials file.
|
|
40
|
+
*/
|
|
41
|
+
export declare function serializeConfigFile(data: Record<string, Record<string, string>>): string;
|
|
42
|
+
export declare function resolveCredentials(opts: ResolveCredentialsOptions): Promise<AsCredentials>;
|
|
43
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,gBAAgB,GACxB,OAAO,GACP,KAAK,GACL,eAAe,GACf,cAAc,GACd,gBAAgB,CAAC;AAErB,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,YAAY,EAAE,UAAU,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAgBD,wBAAgB,0BAA0B,IAAI,MAAM,CAInD;AAgED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA+BvF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAC3C,MAAM,CAYR;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAqHxB"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the AS Ed25519 keypair `cef publish` (and any future signing
|
|
3
|
+
* subcommand) needs to sign the publish envelope. The AS keypair represents
|
|
4
|
+
* the Agent Service identity — potentially shared across a team — so it is
|
|
5
|
+
* never silently auto-generated. Callers must explicitly provision it.
|
|
6
|
+
*
|
|
7
|
+
* Resolution follows AWS-CLI conventions and walks these sources in priority
|
|
8
|
+
* order, returning the first one that produces a complete keypair:
|
|
9
|
+
*
|
|
10
|
+
* 1. CLI flags (`--privkey` + `--pubkey`)
|
|
11
|
+
* 2. Env vars (`CEF_AS_PRIVATE_KEY` + `CEF_AS_PUBLIC_KEY`)
|
|
12
|
+
* 3. Keystore file via flag(`--keystore <path>`)
|
|
13
|
+
* 4. Keystore file via env (`CEF_AS_KEYSTORE`)
|
|
14
|
+
* 5. Profile in shared config (`~/.config/cef/credentials`, INI, profile
|
|
15
|
+
* selected by `--profile` / `CEF_PROFILE`, default `default`).
|
|
16
|
+
*
|
|
17
|
+
* If none produces credentials, a `CredentialsError` is thrown carrying the
|
|
18
|
+
* canonical multi-line guidance message — the CLI surfaces that verbatim on
|
|
19
|
+
* stderr before exiting non-zero.
|
|
20
|
+
*/
|
|
21
|
+
import fs from "node:fs/promises";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
export class CredentialsError extends Error {
|
|
25
|
+
constructor(message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "CredentialsError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const NO_CREDENTIALS_MESSAGE = `Error: no AS credentials configured.
|
|
31
|
+
|
|
32
|
+
Provide credentials via one of:
|
|
33
|
+
- flags: --privkey <hex> --pubkey <hex>
|
|
34
|
+
- env: CEF_AS_PRIVATE_KEY=<hex> CEF_AS_PUBLIC_KEY=<hex>
|
|
35
|
+
- file: --keystore <path> (or CEF_AS_KEYSTORE env)
|
|
36
|
+
- file: ~/.config/cef/credentials (with [default] or another profile via --profile)
|
|
37
|
+
|
|
38
|
+
Generate a new keypair with:
|
|
39
|
+
cef keypair generate
|
|
40
|
+
|
|
41
|
+
Note: the AS keypair represents your Agent Service identity. If you're publishing for an
|
|
42
|
+
existing team, ask your team for the existing keypair — don't generate a new one.`;
|
|
43
|
+
export function defaultCredentialsFilePath() {
|
|
44
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
45
|
+
const base = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), ".config");
|
|
46
|
+
return path.join(base, "cef", "credentials");
|
|
47
|
+
}
|
|
48
|
+
const HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
49
|
+
function normalizePubkey(hex, ctx) {
|
|
50
|
+
if (!HEX_RE.test(hex)) {
|
|
51
|
+
throw new CredentialsError(`${ctx}: pubkey must be 64 hex chars (32 bytes), got ${hex.length} chars`);
|
|
52
|
+
}
|
|
53
|
+
return hex.toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
function hexToBytes(hex, ctx) {
|
|
56
|
+
if (!HEX_RE.test(hex)) {
|
|
57
|
+
throw new CredentialsError(`${ctx}: privkey must be 64 hex chars (32 bytes Ed25519 seed), got ${hex.length} chars`);
|
|
58
|
+
}
|
|
59
|
+
const out = new Uint8Array(32);
|
|
60
|
+
for (let i = 0; i < 32; i++) {
|
|
61
|
+
out[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
async function readKeystoreFile(filePath, ctx) {
|
|
66
|
+
let raw;
|
|
67
|
+
try {
|
|
68
|
+
raw = await fs.readFile(filePath, "utf8");
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
const code = e.code;
|
|
72
|
+
if (code === "ENOENT")
|
|
73
|
+
return null;
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
let parsed;
|
|
77
|
+
try {
|
|
78
|
+
parsed = JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
throw new CredentialsError(`${ctx}: ${filePath} is not valid JSON: ${e.message}`);
|
|
82
|
+
}
|
|
83
|
+
if (!parsed ||
|
|
84
|
+
typeof parsed !== "object" ||
|
|
85
|
+
typeof parsed.pubkey !== "string" ||
|
|
86
|
+
typeof parsed.privkey !== "string") {
|
|
87
|
+
throw new CredentialsError(`${ctx}: ${filePath} is missing pubkey/privkey hex fields`);
|
|
88
|
+
}
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse a minimal INI file: section headers `[name]`, `key = value` pairs,
|
|
93
|
+
* `;` and `#` line comments. No nested sections, no quoting, no escapes —
|
|
94
|
+
* the credentials file shape is trivial and that's all we need.
|
|
95
|
+
*
|
|
96
|
+
* Returns a map of `{ section: { key: value } }`. Keys/values are trimmed.
|
|
97
|
+
* Pre-section keys live under the empty-string section; the credentials
|
|
98
|
+
* loader only reads named sections so those are ignored.
|
|
99
|
+
*/
|
|
100
|
+
export function parseConfigFile(content) {
|
|
101
|
+
const out = {};
|
|
102
|
+
let current = "";
|
|
103
|
+
out[current] = {};
|
|
104
|
+
const lines = content.split(/\r?\n/);
|
|
105
|
+
for (let i = 0; i < lines.length; i++) {
|
|
106
|
+
const raw = lines[i] ?? "";
|
|
107
|
+
const line = raw.trim();
|
|
108
|
+
if (line.length === 0)
|
|
109
|
+
continue;
|
|
110
|
+
if (line.startsWith(";") || line.startsWith("#"))
|
|
111
|
+
continue;
|
|
112
|
+
if (line.startsWith("[") && line.endsWith("]")) {
|
|
113
|
+
current = line.slice(1, -1).trim();
|
|
114
|
+
if (!out[current])
|
|
115
|
+
out[current] = {};
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const eq = line.indexOf("=");
|
|
119
|
+
if (eq < 0) {
|
|
120
|
+
throw new CredentialsError(`credentials file: malformed line ${i + 1}: ${raw}`);
|
|
121
|
+
}
|
|
122
|
+
const key = line.slice(0, eq).trim();
|
|
123
|
+
const value = line.slice(eq + 1).trim();
|
|
124
|
+
if (key.length === 0) {
|
|
125
|
+
throw new CredentialsError(`credentials file: empty key on line ${i + 1}`);
|
|
126
|
+
}
|
|
127
|
+
(out[current] ??= {})[key] = value;
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Render a parsed INI map back to text. Sections are emitted in insertion
|
|
133
|
+
* order; the empty-string section (if any) is dropped — this writer only
|
|
134
|
+
* supports section-scoped credentials. Used by `cef keypair generate
|
|
135
|
+
* --profile` when merging into the shared credentials file.
|
|
136
|
+
*/
|
|
137
|
+
export function serializeConfigFile(data) {
|
|
138
|
+
const parts = [];
|
|
139
|
+
for (const section of Object.keys(data)) {
|
|
140
|
+
if (section.length === 0)
|
|
141
|
+
continue;
|
|
142
|
+
parts.push(`[${section}]`);
|
|
143
|
+
const kv = data[section] ?? {};
|
|
144
|
+
for (const key of Object.keys(kv)) {
|
|
145
|
+
parts.push(`${key} = ${kv[key]}`);
|
|
146
|
+
}
|
|
147
|
+
parts.push("");
|
|
148
|
+
}
|
|
149
|
+
return parts.join("\n");
|
|
150
|
+
}
|
|
151
|
+
export async function resolveCredentials(opts) {
|
|
152
|
+
const env = opts.env ?? process.env;
|
|
153
|
+
// (1) Flags. If either privkey or pubkey is set, both must be set.
|
|
154
|
+
if (opts.privkeyFlag !== undefined || opts.pubkeyFlag !== undefined) {
|
|
155
|
+
if (opts.privkeyFlag === undefined || opts.pubkeyFlag === undefined) {
|
|
156
|
+
throw new CredentialsError("credentials: --privkey and --pubkey must be provided together");
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
pubkey: normalizePubkey(opts.pubkeyFlag, "--pubkey"),
|
|
160
|
+
privkeyBytes: hexToBytes(opts.privkeyFlag, "--privkey"),
|
|
161
|
+
source: "flags",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// (2) Env vars. Same pairing rule — if one is set, both must be.
|
|
165
|
+
const envPriv = env.CEF_AS_PRIVATE_KEY;
|
|
166
|
+
const envPub = env.CEF_AS_PUBLIC_KEY;
|
|
167
|
+
if (envPriv !== undefined || envPub !== undefined) {
|
|
168
|
+
if (envPriv === undefined || envPub === undefined) {
|
|
169
|
+
throw new CredentialsError("credentials: CEF_AS_PRIVATE_KEY and CEF_AS_PUBLIC_KEY must both be set");
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
pubkey: normalizePubkey(envPub, "CEF_AS_PUBLIC_KEY"),
|
|
173
|
+
privkeyBytes: hexToBytes(envPriv, "CEF_AS_PRIVATE_KEY"),
|
|
174
|
+
source: "env",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// (3) --keystore <path>. Missing file is a hard error here — the user
|
|
178
|
+
// explicitly named a path, so silently falling through to the next source
|
|
179
|
+
// would mask a typo.
|
|
180
|
+
if (opts.keystoreFlag !== undefined) {
|
|
181
|
+
const file = await readKeystoreFile(opts.keystoreFlag, "--keystore");
|
|
182
|
+
if (file === null) {
|
|
183
|
+
throw new CredentialsError(`--keystore: ${opts.keystoreFlag} does not exist`);
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
pubkey: normalizePubkey(file.pubkey, opts.keystoreFlag),
|
|
187
|
+
privkeyBytes: hexToBytes(file.privkey, opts.keystoreFlag),
|
|
188
|
+
source: "keystore-flag",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// (4) CEF_AS_KEYSTORE env. Same: if set, the file must exist.
|
|
192
|
+
const envKeystore = env.CEF_AS_KEYSTORE;
|
|
193
|
+
if (envKeystore !== undefined && envKeystore.length > 0) {
|
|
194
|
+
const file = await readKeystoreFile(envKeystore, "CEF_AS_KEYSTORE");
|
|
195
|
+
if (file === null) {
|
|
196
|
+
throw new CredentialsError(`CEF_AS_KEYSTORE: ${envKeystore} does not exist`);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
pubkey: normalizePubkey(file.pubkey, envKeystore),
|
|
200
|
+
privkeyBytes: hexToBytes(file.privkey, envKeystore),
|
|
201
|
+
source: "keystore-env",
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// (5) Shared credentials file → profile section. A missing file with no
|
|
205
|
+
// explicit `--profile` flag is "no credentials", not an error. With
|
|
206
|
+
// `--profile <name>` set we always require either the file or the
|
|
207
|
+
// section to exist — silent fallthrough would mask the typo.
|
|
208
|
+
const configFilePath = opts.configFilePath ?? defaultCredentialsFilePath();
|
|
209
|
+
const profileName = opts.profileFlag ?? env.CEF_PROFILE ?? "default";
|
|
210
|
+
const profileExplicit = opts.profileFlag !== undefined ||
|
|
211
|
+
(env.CEF_PROFILE !== undefined && env.CEF_PROFILE.length > 0);
|
|
212
|
+
let configText = null;
|
|
213
|
+
try {
|
|
214
|
+
configText = await fs.readFile(configFilePath, "utf8");
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
const code = e.code;
|
|
218
|
+
if (code !== "ENOENT")
|
|
219
|
+
throw e;
|
|
220
|
+
}
|
|
221
|
+
if (configText !== null) {
|
|
222
|
+
const parsed = parseConfigFile(configText);
|
|
223
|
+
const section = parsed[profileName];
|
|
224
|
+
if (section && section.pubkey && section.privkey) {
|
|
225
|
+
return {
|
|
226
|
+
pubkey: normalizePubkey(section.pubkey, `${configFilePath} [${profileName}]`),
|
|
227
|
+
privkeyBytes: hexToBytes(section.privkey, `${configFilePath} [${profileName}]`),
|
|
228
|
+
source: "config-profile",
|
|
229
|
+
profileName,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (profileExplicit) {
|
|
233
|
+
throw new CredentialsError(`--profile: ${profileName} not found in ${configFilePath}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (profileExplicit) {
|
|
237
|
+
throw new CredentialsError(`--profile: credentials file ${configFilePath} does not exist`);
|
|
238
|
+
}
|
|
239
|
+
throw new CredentialsError(NO_CREDENTIALS_MESSAGE);
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcs.d.ts","sourceRoot":"","sources":["../../src/lib/jcs.ts"],"names":[],"mappings":"AAeA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOnD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAE5D"}
|
package/dist/lib/jcs.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 8785 JSON Canonicalization Scheme (JCS).
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper over the `canonicalize` npm package — the same library the
|
|
5
|
+
* marketplace API uses. Re-exposed here as `canonicalize()` returning a
|
|
6
|
+
* string (and `canonicalizeBytes()` returning the UTF-8 bytes that get
|
|
7
|
+
* signed / hashed) so call sites in `cef publish` mirror the marketplace's
|
|
8
|
+
* `lib/jcs.ts` one-to-one.
|
|
9
|
+
*
|
|
10
|
+
* RFC 8785 leaves the encoding of non-finite numbers / BigInt undefined; we
|
|
11
|
+
* reject them up front rather than rely on the package's silent coercion,
|
|
12
|
+
* matching the marketplace's behaviour.
|
|
13
|
+
*/
|
|
14
|
+
import canonicalizePkg from "canonicalize";
|
|
15
|
+
export function canonicalize(value) {
|
|
16
|
+
assertJcsCompatible(value);
|
|
17
|
+
const out = canonicalizePkg(value);
|
|
18
|
+
if (out === undefined) {
|
|
19
|
+
throw new TypeError("JCS: canonicalize() returned undefined");
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
export function canonicalizeBytes(value) {
|
|
24
|
+
return new TextEncoder().encode(canonicalize(value));
|
|
25
|
+
}
|
|
26
|
+
function assertJcsCompatible(value) {
|
|
27
|
+
if (typeof value === "number") {
|
|
28
|
+
if (!Number.isFinite(value)) {
|
|
29
|
+
throw new TypeError(`JCS: non-finite number ${String(value)}`);
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === "bigint") {
|
|
34
|
+
throw new TypeError("JCS: bigint not supported by RFC 8785");
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
for (const item of value)
|
|
38
|
+
assertJcsCompatible(item);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (value !== null && typeof value === "object") {
|
|
42
|
+
for (const v of Object.values(value)) {
|
|
43
|
+
if (v !== undefined)
|
|
44
|
+
assertJcsCompatible(v);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=jcs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcs.js","sourceRoot":"","sources":["../../src/lib/jcs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,eAAe,MAAM,cAAc,CAAC;AAE3C,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,SAAS,CAAC,0BAA0B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC,KAAK,SAAS;gBAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface Ed25519Keypair {
|
|
2
|
+
/** Hex-encoded public key (32-byte Ed25519 pubkey, lowercase, no prefix). */
|
|
3
|
+
pubkey: string;
|
|
4
|
+
/** Raw 32-byte private seed. */
|
|
5
|
+
privkeyBytes: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
export declare function generateKeypair(): Promise<Ed25519Keypair>;
|
|
8
|
+
/**
|
|
9
|
+
* Sign the UTF-8 bytes of `canonicalJson` with `privkeyBytes`. Returns
|
|
10
|
+
* lowercase-hex signature (64 bytes → 128 hex chars).
|
|
11
|
+
*/
|
|
12
|
+
export declare function signBody(canonicalJson: string, privkeyBytes: Uint8Array): Promise<string>;
|
|
13
|
+
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/lib/signing.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,cAAc,CAAC,CAI/D;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,MAAM,CAAC,CAIjB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ed25519 keypair generation + body signing for `cef publish`. Produces the
|
|
3
|
+
* lowercase-hex pubkey + signature pair that the marketplace's
|
|
4
|
+
* `X-AS-Pubkey` / `X-AS-Signature` headers expect (raw hex, no `0x` prefix,
|
|
5
|
+
* no encoding wrapper).
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the marketplace's `lib/signing/sign.ts`. Signing input is the
|
|
8
|
+
* UTF-8 bytes of the JCS-canonical body — callers are expected to pass the
|
|
9
|
+
* exact string they place in the HTTP request body, so the signature
|
|
10
|
+
* covers byte-for-byte what the server will re-canonicalize and verify.
|
|
11
|
+
*/
|
|
12
|
+
import * as ed25519 from "@noble/ed25519";
|
|
13
|
+
function bytesToHex(b) {
|
|
14
|
+
let s = "";
|
|
15
|
+
for (let i = 0; i < b.length; i++) {
|
|
16
|
+
s += b[i].toString(16).padStart(2, "0");
|
|
17
|
+
}
|
|
18
|
+
return s;
|
|
19
|
+
}
|
|
20
|
+
export async function generateKeypair() {
|
|
21
|
+
const privkeyBytes = ed25519.utils.randomPrivateKey();
|
|
22
|
+
const pubkeyBytes = await ed25519.getPublicKeyAsync(privkeyBytes);
|
|
23
|
+
return { pubkey: bytesToHex(pubkeyBytes), privkeyBytes };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sign the UTF-8 bytes of `canonicalJson` with `privkeyBytes`. Returns
|
|
27
|
+
* lowercase-hex signature (64 bytes → 128 hex chars).
|
|
28
|
+
*/
|
|
29
|
+
export async function signBody(canonicalJson, privkeyBytes) {
|
|
30
|
+
const message = new TextEncoder().encode(canonicalJson);
|
|
31
|
+
const sig = await ed25519.signAsync(message, privkeyBytes);
|
|
32
|
+
return bytesToHex(sig);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/lib/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,SAAS,UAAU,CAAC,CAAa;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,CAAC,IAAK,CAAC,CAAC,CAAC,CAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;IACtD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAClE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,aAAqB,EACrB,YAAwB;IAExB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC3D,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
package/dist/lib.d.ts
CHANGED
|
@@ -9,4 +9,10 @@ export { cefTypegen } from "./commands/typegen.js";
|
|
|
9
9
|
export type { CefTypegenOptions, CefTypegenResult, } from "./commands/typegen.js";
|
|
10
10
|
export { cefInspect } from "./commands/inspect.js";
|
|
11
11
|
export type { CefInspectOptions, CefInspectResult } from "./commands/inspect.js";
|
|
12
|
+
export { cefPublish } from "./commands/publish.js";
|
|
13
|
+
export type { CefPublishOptions, CefPublishResult, } from "./commands/publish.js";
|
|
14
|
+
export { cefKeypairGenerate } from "./commands/keypair.js";
|
|
15
|
+
export type { CefKeypairGenerateOptions, CefKeypairGenerateResult, } from "./commands/keypair.js";
|
|
16
|
+
export { resolveCredentials, CredentialsError, defaultCredentialsFilePath, } from "./lib/credentials.js";
|
|
17
|
+
export type { AsCredentials, CredentialSource, ResolveCredentialsOptions, } from "./lib/credentials.js";
|
|
12
18
|
//# sourceMappingURL=lib.d.ts.map
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEjF,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EACV,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC"}
|
package/dist/lib.js
CHANGED
|
@@ -6,4 +6,7 @@
|
|
|
6
6
|
export { cefBuild } from "./commands/build.js";
|
|
7
7
|
export { cefTypegen } from "./commands/typegen.js";
|
|
8
8
|
export { cefInspect } from "./commands/inspect.js";
|
|
9
|
+
export { cefPublish } from "./commands/publish.js";
|
|
10
|
+
export { cefKeypairGenerate } from "./commands/keypair.js";
|
|
11
|
+
export { resolveCredentials, CredentialsError, defaultCredentialsFilePath, } from "./lib/credentials.js";
|
|
9
12
|
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGnD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAM3D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cef-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"access": "public"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@noble/ed25519": "^2.1.0",
|
|
18
|
+
"@noble/hashes": "^2.2.0",
|
|
19
|
+
"canonicalize": "^3.0.0",
|
|
17
20
|
"commander": "^12.0.0",
|
|
18
21
|
"esbuild": "^0.21.0",
|
|
19
22
|
"json-schema-to-typescript": "^14.0.0",
|