@elisym/sdk 0.15.1 → 0.15.2
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 +21 -0
- package/dist/agent-store.cjs +109 -0
- package/dist/agent-store.cjs.map +1 -1
- package/dist/agent-store.d.cts +22 -1
- package/dist/agent-store.d.ts +22 -1
- package/dist/agent-store.js +108 -1
- package/dist/agent-store.js.map +1 -1
- package/dist/node.cjs.map +1 -1
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,27 @@ client.close();
|
|
|
64
64
|
| `MediaService` | NIP-96 media uploads for job attachments |
|
|
65
65
|
| `SolanaPaymentStrategy` | Solana fee calculation, payment request creation/validation |
|
|
66
66
|
|
|
67
|
+
## Agent config (`elisym.yaml`)
|
|
68
|
+
|
|
69
|
+
Each agent has its own directory at `<project>/.elisym/<name>/` (project-local) or `~/.elisym/<name>/` (home-global), containing a public `elisym.yaml` and a private `.secrets.json`. The full layout and helpers live in the `@elisym/sdk/agent-store` subpath. CLI `elisym init` and MCP `create_agent` scaffold a fresh `elisym.yaml` with descriptive comments and commented-out examples for every optional field.
|
|
70
|
+
|
|
71
|
+
Top-level fields (full schema reference: [`skills/elisym-config/SKILL.md`](../../skills/elisym-config/SKILL.md)):
|
|
72
|
+
|
|
73
|
+
<!-- fields:begin -->
|
|
74
|
+
|
|
75
|
+
| Field | Type / Example | Required | Notes |
|
|
76
|
+
| -------------- | ----------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `display_name` | `string` (`<=64`) | no | Human-readable name shown in UI. Falls back to the folder name. |
|
|
78
|
+
| `description` | `string` (`<=500`) | no | Public description shown in discovery results. Defaults to `""`. |
|
|
79
|
+
| `picture` | `string` - `./avatar.png` or `https://...` | no | Avatar. Relative paths resolve against the YAML; absolute URLs must be HTTPS. |
|
|
80
|
+
| `banner` | `string` - `./banner.png` or `https://...` | no | Cover image. Same resolution rules as `picture`. |
|
|
81
|
+
| `relays` | `string[]` - `["wss://relay.damus.io", ...]` | no | Nostr relays. Defaults to `relay.damus.io`, `nos.lol`, `relay.nostr.band` when empty. |
|
|
82
|
+
| `payments` | `[{ chain, network, address }]` | no | One entry per `(chain, network)`. Receives every asset on that chain (SOL directly, SPL ATAs). |
|
|
83
|
+
| `llm` | `{ provider, model, max_tokens }` | no | Required for provider mode. Omit for customer mode or non-LLM agents. |
|
|
84
|
+
| `security` | `{ withdrawals_enabled?, agent_switch_enabled? }` (partial) | no | Capability gates. Both default to `false`. |
|
|
85
|
+
|
|
86
|
+
<!-- fields:end -->
|
|
87
|
+
|
|
67
88
|
## How It Works
|
|
68
89
|
|
|
69
90
|
```
|
package/dist/agent-store.cjs
CHANGED
|
@@ -14,6 +14,15 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
14
14
|
var YAML__default = /*#__PURE__*/_interopDefault(YAML);
|
|
15
15
|
|
|
16
16
|
// src/agent-store/schema.ts
|
|
17
|
+
|
|
18
|
+
// src/constants.ts
|
|
19
|
+
var RELAYS = [
|
|
20
|
+
"wss://relay.damus.io",
|
|
21
|
+
"wss://nos.lol",
|
|
22
|
+
"wss://relay.nostr.band",
|
|
23
|
+
"wss://relay.primal.net",
|
|
24
|
+
"wss://relay.snort.social"
|
|
25
|
+
];
|
|
17
26
|
var LIMITS = {
|
|
18
27
|
MAX_DESCRIPTION_LENGTH: 500,
|
|
19
28
|
MAX_AGENT_NAME_LENGTH: 64};
|
|
@@ -305,6 +314,98 @@ function listEncryptedFields(secrets) {
|
|
|
305
314
|
function homeElisymPathHint(name) {
|
|
306
315
|
return `~/.elisym/${name}/elisym.yaml`;
|
|
307
316
|
}
|
|
317
|
+
var PLACEHOLDER_DISPLAY_NAME = "My Agent";
|
|
318
|
+
var PLACEHOLDER_PICTURE = "./avatar.png";
|
|
319
|
+
var PLACEHOLDER_BANNER = "./banner.png";
|
|
320
|
+
var PLACEHOLDER_PAYMENTS = [
|
|
321
|
+
{ chain: "solana", network: "devnet", address: "<your-solana-address>" }
|
|
322
|
+
];
|
|
323
|
+
var PLACEHOLDER_LLM = {
|
|
324
|
+
provider: "anthropic",
|
|
325
|
+
model: "claude-sonnet-4-6",
|
|
326
|
+
max_tokens: 4096
|
|
327
|
+
};
|
|
328
|
+
var DEFAULT_SECURITY = { withdrawals_enabled: false, agent_switch_enabled: false };
|
|
329
|
+
function commentLines(text) {
|
|
330
|
+
return text.split("\n").map((line) => line.length > 0 ? `# ${line}` : "#").join("\n");
|
|
331
|
+
}
|
|
332
|
+
function isUnset(value) {
|
|
333
|
+
if (value === void 0) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
function renderBlock(block) {
|
|
342
|
+
const header = commentLines(block.description);
|
|
343
|
+
const unset = isUnset(block.value);
|
|
344
|
+
const renderValue = unset ? block.placeholder : block.value;
|
|
345
|
+
const yamlBody = YAML__default.default.stringify({ [block.key]: renderValue }).trimEnd();
|
|
346
|
+
const body = unset ? commentLines(yamlBody) : yamlBody;
|
|
347
|
+
return `${header}
|
|
348
|
+
${body}`;
|
|
349
|
+
}
|
|
350
|
+
function renderInitialYaml(yaml) {
|
|
351
|
+
const security = {
|
|
352
|
+
withdrawals_enabled: yaml.security.withdrawals_enabled ?? DEFAULT_SECURITY.withdrawals_enabled,
|
|
353
|
+
agent_switch_enabled: yaml.security.agent_switch_enabled ?? DEFAULT_SECURITY.agent_switch_enabled
|
|
354
|
+
};
|
|
355
|
+
const blocks = [
|
|
356
|
+
{
|
|
357
|
+
description: "Human-readable name shown in UI. Falls back to the folder name when omitted.",
|
|
358
|
+
key: "display_name",
|
|
359
|
+
value: yaml.display_name,
|
|
360
|
+
placeholder: PLACEHOLDER_DISPLAY_NAME
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
description: "Public description shown in discovery results.",
|
|
364
|
+
key: "description",
|
|
365
|
+
value: yaml.description,
|
|
366
|
+
placeholder: ""
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
description: "Avatar - relative path (to this YAML) or absolute URL.",
|
|
370
|
+
key: "picture",
|
|
371
|
+
value: yaml.picture,
|
|
372
|
+
placeholder: PLACEHOLDER_PICTURE
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
description: "Banner - relative path (to this YAML) or absolute URL.",
|
|
376
|
+
key: "banner",
|
|
377
|
+
value: yaml.banner,
|
|
378
|
+
placeholder: PLACEHOLDER_BANNER
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
description: "Nostr relays this agent connects to.",
|
|
382
|
+
key: "relays",
|
|
383
|
+
value: yaml.relays,
|
|
384
|
+
placeholder: [...RELAYS]
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
description: "Payment wallets per chain. Each entry receives every asset on that chain (SOL directly; SPL tokens via the ATA derived from this address).",
|
|
388
|
+
key: "payments",
|
|
389
|
+
value: yaml.payments,
|
|
390
|
+
placeholder: PLACEHOLDER_PAYMENTS
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
description: "LLM configuration. Omit (or comment out) to run as a non-LLM agent (static-file or script skills only).",
|
|
394
|
+
key: "llm",
|
|
395
|
+
value: yaml.llm,
|
|
396
|
+
placeholder: PLACEHOLDER_LLM
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
description: "Capability gates. Both default to false; flip to true to enable.",
|
|
400
|
+
key: "security",
|
|
401
|
+
value: security,
|
|
402
|
+
placeholder: DEFAULT_SECURITY
|
|
403
|
+
}
|
|
404
|
+
];
|
|
405
|
+
return blocks.map(renderBlock).join("\n\n") + "\n";
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/agent-store/writer.ts
|
|
308
409
|
var GITIGNORE_CONTENT = [
|
|
309
410
|
"# elisym private state - do not commit.",
|
|
310
411
|
".secrets.json",
|
|
@@ -349,6 +450,12 @@ async function writeYaml(agentDir, yaml) {
|
|
|
349
450
|
const target = agentPaths(agentDir).yaml;
|
|
350
451
|
await writeFileAtomic(target, body, 420);
|
|
351
452
|
}
|
|
453
|
+
async function writeYamlInitial(agentDir, yaml) {
|
|
454
|
+
const validated = ElisymYamlSchema.parse(yaml);
|
|
455
|
+
const body = renderInitialYaml(validated);
|
|
456
|
+
const target = agentPaths(agentDir).yaml;
|
|
457
|
+
await writeFileAtomic(target, body, 420);
|
|
458
|
+
}
|
|
352
459
|
async function writeSecrets(agentDir, secrets, passphrase) {
|
|
353
460
|
const validated = SecretsSchema.parse(secrets);
|
|
354
461
|
let encryptedLlmKeys;
|
|
@@ -544,6 +651,7 @@ exports.lookupCachedUrl = lookupCachedUrl;
|
|
|
544
651
|
exports.newCacheEntry = newCacheEntry;
|
|
545
652
|
exports.readAgentPublic = readAgentPublic;
|
|
546
653
|
exports.readMediaCache = readMediaCache;
|
|
654
|
+
exports.renderInitialYaml = renderInitialYaml;
|
|
547
655
|
exports.resolveAgent = resolveAgent;
|
|
548
656
|
exports.resolveInHome = resolveInHome;
|
|
549
657
|
exports.resolveInProject = resolveInProject;
|
|
@@ -551,5 +659,6 @@ exports.writeFileAtomic = writeFileAtomic;
|
|
|
551
659
|
exports.writeMediaCache = writeMediaCache;
|
|
552
660
|
exports.writeSecrets = writeSecrets;
|
|
553
661
|
exports.writeYaml = writeYaml;
|
|
662
|
+
exports.writeYamlInitial = writeYamlInitial;
|
|
554
663
|
//# sourceMappingURL=agent-store.cjs.map
|
|
555
664
|
//# sourceMappingURL=agent-store.cjs.map
|
package/dist/agent-store.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/agent-store/schema.ts","../src/agent-store/paths.ts","../src/agent-store/resolver.ts","../src/primitives/config.ts","../src/primitives/encryption.ts","../src/agent-store/loader.ts","../src/agent-store/writer.ts","../src/agent-store/list.ts","../src/agent-store/media-cache.ts"],"names":["z","join","homedir","resolve","existsSync","dirname","statSync","randomBytes","scryptSync","createCipheriv","Buffer","createDecipheriv","readFile","YAML","mkdir","path","writeFile","rename","readdir","createHash"],"mappings":"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","file":"agent-store.cjs","sourcesContent":["import type { Address } from '@solana/kit';\n\nexport const RELAYS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n];\n\nexport const KIND_APP_HANDLER = 31990;\nexport const KIND_JOB_REQUEST_BASE = 5000;\nexport const KIND_JOB_RESULT_BASE = 6000;\nexport const KIND_JOB_FEEDBACK = 7000;\nexport const DEFAULT_KIND_OFFSET = 100;\n\n/** Default job request kind (5000 + 100). */\nexport const KIND_JOB_REQUEST = KIND_JOB_REQUEST_BASE + DEFAULT_KIND_OFFSET;\n/** Default job result kind (6000 + 100). */\nexport const KIND_JOB_RESULT = KIND_JOB_RESULT_BASE + DEFAULT_KIND_OFFSET;\n\n/** Compute a job request kind from an offset (5000 + offset). */\nexport function jobRequestKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_REQUEST_BASE + offset;\n}\n\n/** Compute a job result kind from an offset (6000 + offset). */\nexport function jobResultKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_RESULT_BASE + offset;\n}\n\n/** Ephemeral ping/pong kinds (not stored by relays, forwarded in real-time). */\nexport const KIND_PING = 20200;\nexport const KIND_PONG = 20201;\n\nexport const LAMPORTS_PER_SOL = 1_000_000_000;\n\n/**\n * Solana program ID for the elisym protocol config (devnet deployment).\n *\n * The Anchor program at this address is the source of truth for fee bps,\n * treasury address, and admin rotation state. Read via `getProtocolConfig`.\n */\nexport const PROTOCOL_PROGRAM_ID_DEVNET = 'BrX1CRkSgvcjxBvc2bgc3QqgWjinusofDmeP7ZVxvwrE' as Address;\n\n/**\n * Read-only marker pubkey attached as a non-signer account to every elisym\n * payment transaction. Lets indexers enumerate every elisym tx network-wide\n * via a single `getSignaturesForAddress(ELISYM_PROTOCOL_TAG)` call,\n * independent of fee size or recipient.\n *\n * The account does not need to exist on-chain; including its pubkey as an\n * extra read-only account in the provider transfer instruction is enough for\n * Solana's tx-by-account index to pick it up. The corresponding secret key\n * was generated and discarded - the tag never signs and never holds funds.\n */\nexport const ELISYM_PROTOCOL_TAG = 'ELiZksgwDt41LaeuPDLkUfWgFXhGgVayTMP7L5nTSEL8' as Address;\n\nexport type ProtocolCluster = 'devnet' | 'mainnet' | 'localnet';\n\n/**\n * Resolve the elisym-config program ID for a given Solana cluster.\n * Mainnet is intentionally unsupported until the program ships there.\n */\nexport function getProtocolProgramId(cluster: ProtocolCluster): Address {\n switch (cluster) {\n case 'devnet':\n case 'localnet':\n return PROTOCOL_PROGRAM_ID_DEVNET;\n case 'mainnet':\n throw new Error('Protocol program is not deployed on mainnet yet');\n }\n}\n\n/** Default values for timeouts, retries, and batch sizes. */\nexport const DEFAULTS = {\n SUBSCRIPTION_TIMEOUT_MS: 120_000,\n PING_TIMEOUT_MS: 3_000,\n PING_RETRIES: 2,\n PING_CACHE_TTL_MS: 30_000,\n PAYMENT_EXPIRY_SECS: 600,\n BATCH_SIZE: 250,\n QUERY_TIMEOUT_MS: 15_000,\n EOSE_TIMEOUT_MS: 3_000,\n VERIFY_RETRIES: 10,\n VERIFY_INTERVAL_MS: 3_000,\n VERIFY_BY_REF_RETRIES: 15,\n VERIFY_BY_REF_INTERVAL_MS: 2_000,\n RESULT_RETRY_COUNT: 3,\n RESULT_RETRY_BASE_MS: 1_000,\n QUERY_MAX_CONCURRENCY: 6,\n VERIFY_SIGNATURE_LIMIT: 25,\n} as const;\n\n/** Protocol limits for input validation. */\nexport const LIMITS = {\n MAX_INPUT_LENGTH: 100_000,\n MAX_TIMEOUT_SECS: 600,\n MAX_CAPABILITIES: 20,\n MAX_DESCRIPTION_LENGTH: 500,\n MAX_AGENT_NAME_LENGTH: 64,\n MAX_CAPABILITY_LENGTH: 64,\n} as const;\n","/**\n * Zod schemas for elisym.yaml (public source of truth) and secrets.json (private).\n * Shared between CLI (provider mode) and MCP (customer mode, future provider mode).\n */\n\nimport { z } from 'zod';\nimport { LIMITS } from '../constants';\n\nconst AGENT_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\nexport const AgentNameSchema = z\n .string()\n .min(1)\n .max(LIMITS.MAX_AGENT_NAME_LENGTH)\n .regex(AGENT_NAME_PATTERN, 'alphanumeric, underscore, or hyphen only');\n\n/**\n * Agent wallet entry. One entry per (chain, network) - the address receives\n * every asset on that chain (SOL directly, SPL tokens via their ATA derived\n * from (address, mint)). Per-asset pricing lives in each skill's `SKILL.md`;\n * the canonical mint registry lives in `KNOWN_ASSETS` (payment/assets.ts).\n */\nexport const PaymentSchema = z.object({\n chain: z.literal('solana'),\n network: z.enum(['devnet']),\n address: z.string().min(1),\n});\n\nexport const LlmSchema = z.object({\n provider: z.string().min(1),\n model: z.string().min(1),\n max_tokens: z.number().int().positive().max(200_000).default(4096),\n});\n\nexport const SecurityFlagsSchema = z.object({\n withdrawals_enabled: z.boolean().default(false),\n agent_switch_enabled: z.boolean().default(false),\n});\n\n/**\n * elisym.yaml schema. Public - committed to git.\n * Agent name NOT stored here - derived from containing folder name.\n *\n * The top-level field list is mirrored in `skills/elisym-config/SKILL.md`\n * so the elisym-config agent skill can patch this file directly. Drift\n * is guarded by `packages/sdk/tests/config-skill-drift.test.ts` - when\n * you add or remove a top-level field here, update that SKILL.md too.\n */\nexport const ElisymYamlSchema = z\n .object({\n /** Human-readable name shown in UI (optional). Falls back to folder name. */\n display_name: z.string().max(LIMITS.MAX_AGENT_NAME_LENGTH).optional(),\n description: z.string().max(LIMITS.MAX_DESCRIPTION_LENGTH).default(''),\n /** Relative path (to this YAML) or absolute URL. */\n picture: z.string().optional(),\n /** Relative path (to this YAML) or absolute URL. */\n banner: z.string().optional(),\n relays: z.array(z.string().url()).default([]),\n payments: z.array(PaymentSchema).default([]),\n llm: LlmSchema.optional(),\n security: SecurityFlagsSchema.partial().default({}),\n })\n .strict();\n\nexport type ElisymYaml = z.infer<typeof ElisymYamlSchema>;\nexport type PaymentEntry = z.infer<typeof PaymentSchema>;\nexport type LlmEntry = z.infer<typeof LlmSchema>;\nexport type SecurityFlags = z.infer<typeof SecurityFlagsSchema>;\n\n/**\n * secrets.json schema. Private - .gitignore.\n * Values may be plaintext or `encrypted:v1:...` blobs (AES-256-GCM + scrypt).\n *\n * `llm_api_keys` is a generic record keyed by provider id (e.g. `anthropic`,\n * `openai`, future `xai`/`google`/...). Adding a new LLM provider does not\n * require a schema change. Each value is a separate ciphertext blob when\n * encrypted.\n */\nexport const SecretsSchema = z\n .object({\n nostr_secret_key: z.string().min(1),\n solana_secret_key: z.string().optional(),\n /** Per-provider LLM API keys, keyed by descriptor id (e.g. `anthropic`, `openai`). */\n llm_api_keys: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nexport type Secrets = z.infer<typeof SecretsSchema>;\n\nexport interface MediaCacheEntry {\n url: string;\n sha256: string;\n uploaded_at: string;\n}\n\nexport const MediaCacheEntrySchema: z.ZodType<MediaCacheEntry> = z\n .object({\n url: z.string().url(),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n uploaded_at: z.string(),\n })\n .strict();\n\nexport const MediaCacheSchema = z.record(z.string(), MediaCacheEntrySchema);\n\nexport type MediaCache = z.infer<typeof MediaCacheSchema>;\n","/**\n * Path helpers for .elisym/ layout.\n *\n * Project-local (walk up from CWD until .git or $HOME):\n * <project>/.elisym/<name>/{elisym.yaml, .secrets.json, .media-cache.json, .jobs.json, .gitignore}\n *\n * Home-global (~/.elisym/<name>/): same file structure.\n *\n * Node.js only - relies on `node:fs`/`node:os`/`node:path`.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport const ELISYM_DIRNAME = '.elisym';\nexport const YAML_FILENAME = 'elisym.yaml';\nexport const SECRETS_FILENAME = '.secrets.json';\nexport const MEDIA_CACHE_FILENAME = '.media-cache.json';\nexport const JOBS_FILENAME = '.jobs.json';\nexport const GITIGNORE_FILENAME = '.gitignore';\nexport const SKILLS_DIRNAME = 'skills';\n\n/** Max depth for walk-up search (safety guard against unbounded loops). */\nconst MAX_WALK_UP_DEPTH = 64;\n\n/** ~/.elisym/ */\nexport function homeElisymDir(): string {\n return join(homedir(), ELISYM_DIRNAME);\n}\n\n/** ~/.elisym/config.yaml — global (not per-agent) config file. */\nexport function globalConfigPath(): string {\n return join(homeElisymDir(), 'config.yaml');\n}\n\n/**\n * Walk up from `startDir` looking for `.elisym/` directory.\n * Stops at (a) the first `.git` directory/file, (b) `$HOME`, (c) filesystem root,\n * or (d) MAX_WALK_UP_DEPTH iterations. Returns absolute path or null.\n */\nexport function findProjectElisymDir(startDir: string): string | null {\n const home = homedir();\n let current = resolve(startDir);\n let previous: string | null = null;\n\n for (let depth = 0; depth < MAX_WALK_UP_DEPTH; depth++) {\n if (current === previous) {\n return null;\n }\n\n // At $HOME: ~/.elisym/ is the home-global layout, not a project-local one.\n // Stop without matching to avoid misclassifying home agents as project.\n if (current === home) {\n return null;\n }\n\n const elisymCandidate = join(current, ELISYM_DIRNAME);\n if (existsSync(elisymCandidate) && safeIsDir(elisymCandidate)) {\n return elisymCandidate;\n }\n\n const gitCandidate = join(current, '.git');\n if (existsSync(gitCandidate)) {\n return null;\n }\n\n previous = current;\n current = dirname(current);\n }\n\n return null;\n}\n\nexport interface AgentPaths {\n dir: string;\n yaml: string;\n secrets: string;\n mediaCache: string;\n jobs: string;\n gitignore: string;\n skills: string;\n}\n\n/** Compute all file/dir paths for an agent given its root directory. */\nexport function agentPaths(agentDir: string): AgentPaths {\n return {\n dir: agentDir,\n yaml: join(agentDir, YAML_FILENAME),\n secrets: join(agentDir, SECRETS_FILENAME),\n mediaCache: join(agentDir, MEDIA_CACHE_FILENAME),\n jobs: join(agentDir, JOBS_FILENAME),\n gitignore: join(agentDir, GITIGNORE_FILENAME),\n skills: join(agentDir, SKILLS_DIRNAME),\n };\n}\n\nfunction safeIsDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n","/**\n * Agent resolution: find <name>/elisym.yaml via project-local walk-up, fallback to home.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ELISYM_DIRNAME, YAML_FILENAME, findProjectElisymDir, homeElisymDir } from './paths';\n\nexport type AgentSource = 'project' | 'home';\n\nexport interface ResolvedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n /** true when both a project-local and a home-global agent exist with the same name. */\n shadowsGlobal: boolean;\n}\n\n/**\n * Resolve an agent by name. Precedence: project-local beats home-global.\n * Returns null if not found in either location.\n */\nexport function resolveAgent(name: string, cwd: string): ResolvedAgent | null {\n const projectDir = resolveInProject(name, cwd);\n const homeDir = resolveInHome(name);\n\n if (projectDir) {\n return {\n name,\n dir: projectDir,\n source: 'project',\n shadowsGlobal: homeDir !== null,\n };\n }\n\n if (homeDir) {\n return { name, dir: homeDir, source: 'home', shadowsGlobal: false };\n }\n\n return null;\n}\n\n/** Return project-local agent dir if its YAML exists, else null. */\nexport function resolveInProject(name: string, cwd: string): string | null {\n const projectElisym = findProjectElisymDir(cwd);\n if (!projectElisym) {\n return null;\n }\n const agentDir = join(projectElisym, name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Return home-global agent dir if its YAML exists, else null. */\nexport function resolveInHome(name: string): string | null {\n const agentDir = join(homeElisymDir(), name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Path to the .elisym root (project or home) for a given target. */\nexport function elisymRootFor(target: AgentSource, cwd: string): string | null {\n if (target === 'home') {\n return homeElisymDir();\n }\n return findProjectElisymDir(cwd);\n}\n\n/** Re-export for convenience. */\nexport { ELISYM_DIRNAME };\n","/**\n * Agent-name validation shared between CLI and MCP.\n * Browser-safe - no Node.js imports.\n */\n\nimport { LIMITS } from '../constants';\n\nexport function validateAgentName(name: string): void {\n if (!name || name.length > LIMITS.MAX_AGENT_NAME_LENGTH || !/^[a-zA-Z0-9_-]+$/.test(name)) {\n throw new Error('Agent name must be 1-64 characters, alphanumeric, underscore, or hyphen.');\n }\n}\n","/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Load an agent: parse elisym.yaml + .secrets.json, decrypt if encrypted.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { validateAgentName } from '../primitives/config';\nimport { isEncrypted, decryptSecret } from '../primitives/encryption';\nimport { agentPaths } from './paths';\nimport { resolveAgent, type AgentSource, type ResolvedAgent } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nexport interface LoadedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n yaml: ElisymYaml;\n secrets: Secrets;\n /** true when at least one secret field was encrypted on disk. */\n encrypted: boolean;\n shadowsGlobal: boolean;\n}\n\n/** Raw resolve + read + parse, no decryption yet. Useful for ergonomic list views. */\nexport async function readAgentPublic(\n resolved: ResolvedAgent,\n): Promise<{ resolved: ResolvedAgent; yaml: ElisymYaml }> {\n const paths = agentPaths(resolved.dir);\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsed = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsed ?? {});\n return { resolved, yaml };\n}\n\n/**\n * Load an agent by name. Searches project-local first, then home.\n * Throws with clear error if missing or if encrypted secrets lack a passphrase.\n */\nexport async function loadAgent(\n name: string,\n cwd: string,\n passphrase?: string,\n): Promise<LoadedAgent> {\n validateAgentName(name);\n const resolved = resolveAgent(name, cwd);\n if (!resolved) {\n throw new Error(\n `Agent \"${name}\" not found. Looked for .elisym/${name}/elisym.yaml in project (walking up from ${cwd}) and in home (${homeElisymPathHint(name)}).`,\n );\n }\n return loadResolvedAgent(resolved, passphrase);\n}\n\n/** Load an agent whose location was already resolved. */\nexport async function loadResolvedAgent(\n resolved: ResolvedAgent,\n passphrase?: string,\n): Promise<LoadedAgent> {\n const paths = agentPaths(resolved.dir);\n\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsedYaml = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsedYaml ?? {});\n\n let secretsRaw: string;\n try {\n secretsRaw = await readFile(paths.secrets, 'utf-8');\n } catch {\n throw new Error(\n `Agent \"${resolved.name}\" has elisym.yaml but no secrets at ${paths.secrets}. Run \\`npx @elisym/cli init\\` to initialize secrets.`,\n );\n }\n\n const secrets = SecretsSchema.parse(JSON.parse(secretsRaw));\n const encryptedFields = listEncryptedFields(secrets);\n\n const effectivePassphrase = passphrase ?? process.env.ELISYM_PASSPHRASE;\n if (encryptedFields.length > 0 && !effectivePassphrase) {\n throw new Error(\n `Agent \"${resolved.name}\" has encrypted secrets [${encryptedFields.join(', ')}]. Set ELISYM_PASSPHRASE or pass a passphrase.`,\n );\n }\n\n const decrypted: Secrets = { ...secrets };\n if (effectivePassphrase) {\n if (isEncrypted(decrypted.nostr_secret_key)) {\n decrypted.nostr_secret_key = decryptSecret(decrypted.nostr_secret_key, effectivePassphrase);\n }\n if (decrypted.solana_secret_key && isEncrypted(decrypted.solana_secret_key)) {\n decrypted.solana_secret_key = decryptSecret(decrypted.solana_secret_key, effectivePassphrase);\n }\n if (decrypted.llm_api_keys) {\n const decryptedKeys: Record<string, string> = {};\n for (const [providerId, value] of Object.entries(decrypted.llm_api_keys)) {\n decryptedKeys[providerId] = isEncrypted(value)\n ? decryptSecret(value, effectivePassphrase)\n : value;\n }\n decrypted.llm_api_keys = decryptedKeys;\n }\n }\n\n return {\n name: resolved.name,\n dir: resolved.dir,\n source: resolved.source,\n yaml,\n secrets: decrypted,\n encrypted: encryptedFields.length > 0,\n shadowsGlobal: resolved.shadowsGlobal,\n };\n}\n\nfunction listEncryptedFields(secrets: Secrets): string[] {\n const out: string[] = [];\n if (isEncrypted(secrets.nostr_secret_key)) {\n out.push('nostr_secret_key');\n }\n if (secrets.solana_secret_key && isEncrypted(secrets.solana_secret_key)) {\n out.push('solana_secret_key');\n }\n if (secrets.llm_api_keys) {\n for (const [providerId, value] of Object.entries(secrets.llm_api_keys)) {\n if (isEncrypted(value)) {\n out.push(`llm_api_keys.${providerId}`);\n }\n }\n }\n return out;\n}\n\nfunction homeElisymPathHint(name: string): string {\n return `~/.elisym/${name}/elisym.yaml`;\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * List all agents discoverable from the current working directory:\n * - project-local: nearest .elisym/ (walk up to first .git or $HOME)\n * - home-global: ~/.elisym/\n * Project-local entries shadow home-global entries with the same name.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport YAML from 'yaml';\nimport { findProjectElisymDir, homeElisymDir, YAML_FILENAME } from './paths';\nimport type { AgentSource } from './resolver';\nimport { ElisymYamlSchema } from './schema';\n\nexport interface ListedAgent {\n name: string;\n source: AgentSource;\n dir: string;\n /** display_name from YAML, if present. */\n displayName?: string;\n /** true when this entry is project-local and a home-global agent with the same name exists. */\n shadowsGlobal: boolean;\n}\n\n/** List agents in both locations, deduping by name (project wins). */\nexport async function listAgents(cwd: string): Promise<ListedAgent[]> {\n const homeDir = homeElisymDir();\n const projectDir = findProjectElisymDir(cwd);\n\n const homeAgents = await listAgentsInDir(homeDir, 'home');\n const projectAgents = projectDir ? await listAgentsInDir(projectDir, 'project') : [];\n\n const homeNames = new Set(homeAgents.map((agent) => agent.name));\n\n const merged: ListedAgent[] = [];\n\n for (const entry of projectAgents) {\n merged.push({ ...entry, shadowsGlobal: homeNames.has(entry.name) });\n }\n const projectNames = new Set(projectAgents.map((agent) => agent.name));\n for (const entry of homeAgents) {\n if (!projectNames.has(entry.name)) {\n merged.push(entry);\n }\n }\n\n merged.sort((left, right) => left.name.localeCompare(right.name));\n return merged;\n}\n\nasync function listAgentsInDir(rootDir: string, source: AgentSource): Promise<ListedAgent[]> {\n let entries: string[];\n try {\n entries = await readdir(rootDir);\n } catch {\n return [];\n }\n\n const results: ListedAgent[] = [];\n for (const entry of entries) {\n if (entry.startsWith('.')) {\n continue;\n }\n const agentDir = join(rootDir, entry);\n const yamlPath = join(agentDir, YAML_FILENAME);\n const displayName = await tryReadDisplayName(yamlPath);\n if (displayName === null) {\n continue;\n }\n results.push({\n name: entry,\n source,\n dir: agentDir,\n displayName: displayName || undefined,\n shadowsGlobal: false,\n });\n }\n\n return results;\n}\n\n/**\n * Read display_name from a YAML file. Returns null if the file is missing\n * or cannot be parsed (agent directory is skipped in listings).\n */\nasync function tryReadDisplayName(yamlPath: string): Promise<string | null> {\n let raw: string;\n try {\n raw = await readFile(yamlPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = YAML.parse(raw);\n const yaml = ElisymYamlSchema.partial().safeParse(parsed ?? {});\n if (!yaml.success) {\n return '';\n }\n return yaml.data.display_name ?? '';\n } catch {\n return '';\n }\n}\n","/**\n * Media cache: maps local image paths to uploaded URLs + sha256.\n * On each start, the CLI hashes the file and skips re-upload if the hash matches.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { agentPaths } from './paths';\nimport { MediaCacheSchema, type MediaCache, type MediaCacheEntry } from './schema';\nimport { writeFileAtomic } from './writer';\n\n/** Read .media-cache.json. Returns empty object if missing or corrupt. */\nexport async function readMediaCache(agentDir: string): Promise<MediaCache> {\n const path = agentPaths(agentDir).mediaCache;\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n const result = MediaCacheSchema.safeParse(parsed);\n return result.success ? result.data : {};\n } catch {\n return {};\n }\n}\n\nexport async function writeMediaCache(agentDir: string, cache: MediaCache): Promise<void> {\n const path = agentPaths(agentDir).mediaCache;\n const body = JSON.stringify(cache, null, 2) + '\\n';\n await writeFileAtomic(path, body, 0o600);\n}\n\n/** Compute sha256 hex of a file's contents. */\nexport async function hashFile(filePath: string): Promise<string> {\n const buf = await readFile(filePath);\n return createHash('sha256').update(buf).digest('hex');\n}\n\n/**\n * Look up a cached URL for a local file path. Returns the cached URL if\n * the file's current hash matches the cache entry; otherwise null.\n */\nexport async function lookupCachedUrl(\n cache: MediaCache,\n relativePath: string,\n absolutePath: string,\n): Promise<string | null> {\n const entry = cache[relativePath];\n if (!entry) {\n return null;\n }\n let hash: string;\n try {\n hash = await hashFile(absolutePath);\n } catch {\n return null;\n }\n return hash === entry.sha256 ? entry.url : null;\n}\n\nexport function newCacheEntry(url: string, sha256: string): MediaCacheEntry {\n return { url, sha256, uploaded_at: new Date().toISOString() };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/agent-store/schema.ts","../src/agent-store/paths.ts","../src/agent-store/resolver.ts","../src/primitives/config.ts","../src/primitives/encryption.ts","../src/agent-store/loader.ts","../src/agent-store/template.ts","../src/agent-store/writer.ts","../src/agent-store/list.ts","../src/agent-store/media-cache.ts"],"names":["z","join","homedir","resolve","existsSync","dirname","statSync","randomBytes","scryptSync","createCipheriv","Buffer","createDecipheriv","readFile","YAML","mkdir","path","writeFile","rename","readdir","createHash"],"mappings":"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","file":"agent-store.cjs","sourcesContent":["import type { Address } from '@solana/kit';\n\nexport const RELAYS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n];\n\nexport const KIND_APP_HANDLER = 31990;\nexport const KIND_JOB_REQUEST_BASE = 5000;\nexport const KIND_JOB_RESULT_BASE = 6000;\nexport const KIND_JOB_FEEDBACK = 7000;\nexport const DEFAULT_KIND_OFFSET = 100;\n\n/** Default job request kind (5000 + 100). */\nexport const KIND_JOB_REQUEST = KIND_JOB_REQUEST_BASE + DEFAULT_KIND_OFFSET;\n/** Default job result kind (6000 + 100). */\nexport const KIND_JOB_RESULT = KIND_JOB_RESULT_BASE + DEFAULT_KIND_OFFSET;\n\n/** Compute a job request kind from an offset (5000 + offset). */\nexport function jobRequestKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_REQUEST_BASE + offset;\n}\n\n/** Compute a job result kind from an offset (6000 + offset). */\nexport function jobResultKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_RESULT_BASE + offset;\n}\n\n/** Ephemeral ping/pong kinds (not stored by relays, forwarded in real-time). */\nexport const KIND_PING = 20200;\nexport const KIND_PONG = 20201;\n\nexport const LAMPORTS_PER_SOL = 1_000_000_000;\n\n/**\n * Solana program ID for the elisym protocol config (devnet deployment).\n *\n * The Anchor program at this address is the source of truth for fee bps,\n * treasury address, and admin rotation state. Read via `getProtocolConfig`.\n */\nexport const PROTOCOL_PROGRAM_ID_DEVNET = 'BrX1CRkSgvcjxBvc2bgc3QqgWjinusofDmeP7ZVxvwrE' as Address;\n\n/**\n * Read-only marker pubkey attached as a non-signer account to every elisym\n * payment transaction. Lets indexers enumerate every elisym tx network-wide\n * via a single `getSignaturesForAddress(ELISYM_PROTOCOL_TAG)` call,\n * independent of fee size or recipient.\n *\n * The account does not need to exist on-chain; including its pubkey as an\n * extra read-only account in the provider transfer instruction is enough for\n * Solana's tx-by-account index to pick it up. The corresponding secret key\n * was generated and discarded - the tag never signs and never holds funds.\n */\nexport const ELISYM_PROTOCOL_TAG = 'ELiZksgwDt41LaeuPDLkUfWgFXhGgVayTMP7L5nTSEL8' as Address;\n\nexport type ProtocolCluster = 'devnet' | 'mainnet' | 'localnet';\n\n/**\n * Resolve the elisym-config program ID for a given Solana cluster.\n * Mainnet is intentionally unsupported until the program ships there.\n */\nexport function getProtocolProgramId(cluster: ProtocolCluster): Address {\n switch (cluster) {\n case 'devnet':\n case 'localnet':\n return PROTOCOL_PROGRAM_ID_DEVNET;\n case 'mainnet':\n throw new Error('Protocol program is not deployed on mainnet yet');\n }\n}\n\n/** Default values for timeouts, retries, and batch sizes. */\nexport const DEFAULTS = {\n SUBSCRIPTION_TIMEOUT_MS: 120_000,\n PING_TIMEOUT_MS: 3_000,\n PING_RETRIES: 2,\n PING_CACHE_TTL_MS: 30_000,\n PAYMENT_EXPIRY_SECS: 600,\n BATCH_SIZE: 250,\n QUERY_TIMEOUT_MS: 15_000,\n EOSE_TIMEOUT_MS: 3_000,\n VERIFY_RETRIES: 10,\n VERIFY_INTERVAL_MS: 3_000,\n VERIFY_BY_REF_RETRIES: 15,\n VERIFY_BY_REF_INTERVAL_MS: 2_000,\n RESULT_RETRY_COUNT: 3,\n RESULT_RETRY_BASE_MS: 1_000,\n QUERY_MAX_CONCURRENCY: 6,\n VERIFY_SIGNATURE_LIMIT: 25,\n} as const;\n\n/** Protocol limits for input validation. */\nexport const LIMITS = {\n MAX_INPUT_LENGTH: 100_000,\n MAX_TIMEOUT_SECS: 600,\n MAX_CAPABILITIES: 20,\n MAX_DESCRIPTION_LENGTH: 500,\n MAX_AGENT_NAME_LENGTH: 64,\n MAX_CAPABILITY_LENGTH: 64,\n} as const;\n","/**\n * Zod schemas for elisym.yaml (public source of truth) and secrets.json (private).\n * Shared between CLI (provider mode) and MCP (customer mode, future provider mode).\n */\n\nimport { z } from 'zod';\nimport { LIMITS } from '../constants';\n\nconst AGENT_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\nexport const AgentNameSchema = z\n .string()\n .min(1)\n .max(LIMITS.MAX_AGENT_NAME_LENGTH)\n .regex(AGENT_NAME_PATTERN, 'alphanumeric, underscore, or hyphen only');\n\n/**\n * Agent wallet entry. One entry per (chain, network) - the address receives\n * every asset on that chain (SOL directly, SPL tokens via their ATA derived\n * from (address, mint)). Per-asset pricing lives in each skill's `SKILL.md`;\n * the canonical mint registry lives in `KNOWN_ASSETS` (payment/assets.ts).\n */\nexport const PaymentSchema = z.object({\n chain: z.literal('solana'),\n network: z.enum(['devnet']),\n address: z.string().min(1),\n});\n\nexport const LlmSchema = z.object({\n provider: z.string().min(1),\n model: z.string().min(1),\n max_tokens: z.number().int().positive().max(200_000).default(4096),\n});\n\nexport const SecurityFlagsSchema = z.object({\n withdrawals_enabled: z.boolean().default(false),\n agent_switch_enabled: z.boolean().default(false),\n});\n\n/**\n * elisym.yaml schema. Public - committed to git.\n * Agent name NOT stored here - derived from containing folder name.\n *\n * The top-level field list is mirrored in `skills/elisym-config/SKILL.md`\n * so the elisym-config agent skill can patch this file directly. Drift\n * is guarded by `packages/sdk/tests/config-skill-drift.test.ts` - when\n * you add or remove a top-level field here, update that SKILL.md too.\n */\nexport const ElisymYamlSchema = z\n .object({\n /** Human-readable name shown in UI (optional). Falls back to folder name. */\n display_name: z.string().max(LIMITS.MAX_AGENT_NAME_LENGTH).optional(),\n description: z.string().max(LIMITS.MAX_DESCRIPTION_LENGTH).default(''),\n /** Relative path (to this YAML) or absolute URL. */\n picture: z.string().optional(),\n /** Relative path (to this YAML) or absolute URL. */\n banner: z.string().optional(),\n relays: z.array(z.string().url()).default([]),\n payments: z.array(PaymentSchema).default([]),\n llm: LlmSchema.optional(),\n security: SecurityFlagsSchema.partial().default({}),\n })\n .strict();\n\nexport type ElisymYaml = z.infer<typeof ElisymYamlSchema>;\nexport type PaymentEntry = z.infer<typeof PaymentSchema>;\nexport type LlmEntry = z.infer<typeof LlmSchema>;\nexport type SecurityFlags = z.infer<typeof SecurityFlagsSchema>;\n\n/**\n * secrets.json schema. Private - .gitignore.\n * Values may be plaintext or `encrypted:v1:...` blobs (AES-256-GCM + scrypt).\n *\n * `llm_api_keys` is a generic record keyed by provider id (e.g. `anthropic`,\n * `openai`, future `xai`/`google`/...). Adding a new LLM provider does not\n * require a schema change. Each value is a separate ciphertext blob when\n * encrypted.\n */\nexport const SecretsSchema = z\n .object({\n nostr_secret_key: z.string().min(1),\n solana_secret_key: z.string().optional(),\n /** Per-provider LLM API keys, keyed by descriptor id (e.g. `anthropic`, `openai`). */\n llm_api_keys: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nexport type Secrets = z.infer<typeof SecretsSchema>;\n\nexport interface MediaCacheEntry {\n url: string;\n sha256: string;\n uploaded_at: string;\n}\n\nexport const MediaCacheEntrySchema: z.ZodType<MediaCacheEntry> = z\n .object({\n url: z.string().url(),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n uploaded_at: z.string(),\n })\n .strict();\n\nexport const MediaCacheSchema = z.record(z.string(), MediaCacheEntrySchema);\n\nexport type MediaCache = z.infer<typeof MediaCacheSchema>;\n","/**\n * Path helpers for .elisym/ layout.\n *\n * Project-local (walk up from CWD until .git or $HOME):\n * <project>/.elisym/<name>/{elisym.yaml, .secrets.json, .media-cache.json, .jobs.json, .gitignore}\n *\n * Home-global (~/.elisym/<name>/): same file structure.\n *\n * Node.js only - relies on `node:fs`/`node:os`/`node:path`.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport const ELISYM_DIRNAME = '.elisym';\nexport const YAML_FILENAME = 'elisym.yaml';\nexport const SECRETS_FILENAME = '.secrets.json';\nexport const MEDIA_CACHE_FILENAME = '.media-cache.json';\nexport const JOBS_FILENAME = '.jobs.json';\nexport const GITIGNORE_FILENAME = '.gitignore';\nexport const SKILLS_DIRNAME = 'skills';\n\n/** Max depth for walk-up search (safety guard against unbounded loops). */\nconst MAX_WALK_UP_DEPTH = 64;\n\n/** ~/.elisym/ */\nexport function homeElisymDir(): string {\n return join(homedir(), ELISYM_DIRNAME);\n}\n\n/** ~/.elisym/config.yaml — global (not per-agent) config file. */\nexport function globalConfigPath(): string {\n return join(homeElisymDir(), 'config.yaml');\n}\n\n/**\n * Walk up from `startDir` looking for `.elisym/` directory.\n * Stops at (a) the first `.git` directory/file, (b) `$HOME`, (c) filesystem root,\n * or (d) MAX_WALK_UP_DEPTH iterations. Returns absolute path or null.\n */\nexport function findProjectElisymDir(startDir: string): string | null {\n const home = homedir();\n let current = resolve(startDir);\n let previous: string | null = null;\n\n for (let depth = 0; depth < MAX_WALK_UP_DEPTH; depth++) {\n if (current === previous) {\n return null;\n }\n\n // At $HOME: ~/.elisym/ is the home-global layout, not a project-local one.\n // Stop without matching to avoid misclassifying home agents as project.\n if (current === home) {\n return null;\n }\n\n const elisymCandidate = join(current, ELISYM_DIRNAME);\n if (existsSync(elisymCandidate) && safeIsDir(elisymCandidate)) {\n return elisymCandidate;\n }\n\n const gitCandidate = join(current, '.git');\n if (existsSync(gitCandidate)) {\n return null;\n }\n\n previous = current;\n current = dirname(current);\n }\n\n return null;\n}\n\nexport interface AgentPaths {\n dir: string;\n yaml: string;\n secrets: string;\n mediaCache: string;\n jobs: string;\n gitignore: string;\n skills: string;\n}\n\n/** Compute all file/dir paths for an agent given its root directory. */\nexport function agentPaths(agentDir: string): AgentPaths {\n return {\n dir: agentDir,\n yaml: join(agentDir, YAML_FILENAME),\n secrets: join(agentDir, SECRETS_FILENAME),\n mediaCache: join(agentDir, MEDIA_CACHE_FILENAME),\n jobs: join(agentDir, JOBS_FILENAME),\n gitignore: join(agentDir, GITIGNORE_FILENAME),\n skills: join(agentDir, SKILLS_DIRNAME),\n };\n}\n\nfunction safeIsDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n","/**\n * Agent resolution: find <name>/elisym.yaml via project-local walk-up, fallback to home.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ELISYM_DIRNAME, YAML_FILENAME, findProjectElisymDir, homeElisymDir } from './paths';\n\nexport type AgentSource = 'project' | 'home';\n\nexport interface ResolvedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n /** true when both a project-local and a home-global agent exist with the same name. */\n shadowsGlobal: boolean;\n}\n\n/**\n * Resolve an agent by name. Precedence: project-local beats home-global.\n * Returns null if not found in either location.\n */\nexport function resolveAgent(name: string, cwd: string): ResolvedAgent | null {\n const projectDir = resolveInProject(name, cwd);\n const homeDir = resolveInHome(name);\n\n if (projectDir) {\n return {\n name,\n dir: projectDir,\n source: 'project',\n shadowsGlobal: homeDir !== null,\n };\n }\n\n if (homeDir) {\n return { name, dir: homeDir, source: 'home', shadowsGlobal: false };\n }\n\n return null;\n}\n\n/** Return project-local agent dir if its YAML exists, else null. */\nexport function resolveInProject(name: string, cwd: string): string | null {\n const projectElisym = findProjectElisymDir(cwd);\n if (!projectElisym) {\n return null;\n }\n const agentDir = join(projectElisym, name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Return home-global agent dir if its YAML exists, else null. */\nexport function resolveInHome(name: string): string | null {\n const agentDir = join(homeElisymDir(), name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Path to the .elisym root (project or home) for a given target. */\nexport function elisymRootFor(target: AgentSource, cwd: string): string | null {\n if (target === 'home') {\n return homeElisymDir();\n }\n return findProjectElisymDir(cwd);\n}\n\n/** Re-export for convenience. */\nexport { ELISYM_DIRNAME };\n","/**\n * Agent-name validation shared between CLI and MCP.\n * Browser-safe - no Node.js imports.\n */\n\nimport { LIMITS } from '../constants';\n\nexport function validateAgentName(name: string): void {\n if (!name || name.length > LIMITS.MAX_AGENT_NAME_LENGTH || !/^[a-zA-Z0-9_-]+$/.test(name)) {\n throw new Error('Agent name must be 1-64 characters, alphanumeric, underscore, or hyphen.');\n }\n}\n","/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Load an agent: parse elisym.yaml + .secrets.json, decrypt if encrypted.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { validateAgentName } from '../primitives/config';\nimport { isEncrypted, decryptSecret } from '../primitives/encryption';\nimport { agentPaths } from './paths';\nimport { resolveAgent, type AgentSource, type ResolvedAgent } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nexport interface LoadedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n yaml: ElisymYaml;\n secrets: Secrets;\n /** true when at least one secret field was encrypted on disk. */\n encrypted: boolean;\n shadowsGlobal: boolean;\n}\n\n/** Raw resolve + read + parse, no decryption yet. Useful for ergonomic list views. */\nexport async function readAgentPublic(\n resolved: ResolvedAgent,\n): Promise<{ resolved: ResolvedAgent; yaml: ElisymYaml }> {\n const paths = agentPaths(resolved.dir);\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsed = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsed ?? {});\n return { resolved, yaml };\n}\n\n/**\n * Load an agent by name. Searches project-local first, then home.\n * Throws with clear error if missing or if encrypted secrets lack a passphrase.\n */\nexport async function loadAgent(\n name: string,\n cwd: string,\n passphrase?: string,\n): Promise<LoadedAgent> {\n validateAgentName(name);\n const resolved = resolveAgent(name, cwd);\n if (!resolved) {\n throw new Error(\n `Agent \"${name}\" not found. Looked for .elisym/${name}/elisym.yaml in project (walking up from ${cwd}) and in home (${homeElisymPathHint(name)}).`,\n );\n }\n return loadResolvedAgent(resolved, passphrase);\n}\n\n/** Load an agent whose location was already resolved. */\nexport async function loadResolvedAgent(\n resolved: ResolvedAgent,\n passphrase?: string,\n): Promise<LoadedAgent> {\n const paths = agentPaths(resolved.dir);\n\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsedYaml = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsedYaml ?? {});\n\n let secretsRaw: string;\n try {\n secretsRaw = await readFile(paths.secrets, 'utf-8');\n } catch {\n throw new Error(\n `Agent \"${resolved.name}\" has elisym.yaml but no secrets at ${paths.secrets}. Run \\`npx @elisym/cli init\\` to initialize secrets.`,\n );\n }\n\n const secrets = SecretsSchema.parse(JSON.parse(secretsRaw));\n const encryptedFields = listEncryptedFields(secrets);\n\n const effectivePassphrase = passphrase ?? process.env.ELISYM_PASSPHRASE;\n if (encryptedFields.length > 0 && !effectivePassphrase) {\n throw new Error(\n `Agent \"${resolved.name}\" has encrypted secrets [${encryptedFields.join(', ')}]. Set ELISYM_PASSPHRASE or pass a passphrase.`,\n );\n }\n\n const decrypted: Secrets = { ...secrets };\n if (effectivePassphrase) {\n if (isEncrypted(decrypted.nostr_secret_key)) {\n decrypted.nostr_secret_key = decryptSecret(decrypted.nostr_secret_key, effectivePassphrase);\n }\n if (decrypted.solana_secret_key && isEncrypted(decrypted.solana_secret_key)) {\n decrypted.solana_secret_key = decryptSecret(decrypted.solana_secret_key, effectivePassphrase);\n }\n if (decrypted.llm_api_keys) {\n const decryptedKeys: Record<string, string> = {};\n for (const [providerId, value] of Object.entries(decrypted.llm_api_keys)) {\n decryptedKeys[providerId] = isEncrypted(value)\n ? decryptSecret(value, effectivePassphrase)\n : value;\n }\n decrypted.llm_api_keys = decryptedKeys;\n }\n }\n\n return {\n name: resolved.name,\n dir: resolved.dir,\n source: resolved.source,\n yaml,\n secrets: decrypted,\n encrypted: encryptedFields.length > 0,\n shadowsGlobal: resolved.shadowsGlobal,\n };\n}\n\nfunction listEncryptedFields(secrets: Secrets): string[] {\n const out: string[] = [];\n if (isEncrypted(secrets.nostr_secret_key)) {\n out.push('nostr_secret_key');\n }\n if (secrets.solana_secret_key && isEncrypted(secrets.solana_secret_key)) {\n out.push('solana_secret_key');\n }\n if (secrets.llm_api_keys) {\n for (const [providerId, value] of Object.entries(secrets.llm_api_keys)) {\n if (isEncrypted(value)) {\n out.push(`llm_api_keys.${providerId}`);\n }\n }\n }\n return out;\n}\n\nfunction homeElisymPathHint(name: string): string {\n return `~/.elisym/${name}/elisym.yaml`;\n}\n","/**\n * Render a fresh `elisym.yaml` as a string with descriptive header comments\n * over each top-level field. Optional fields that are not set in the input\n * are emitted as commented-out examples so a new operator can see what else\n * is configurable without leaving the file.\n *\n * Used only at agent-creation time (CLI `init`, MCP `create_agent`). On\n * subsequent writes via `writeYaml`, the document is re-serialized without\n * comments - this template is a one-shot scaffold, not a round-tripping\n * format.\n */\n\nimport YAML from 'yaml';\nimport { RELAYS } from '../constants';\nimport type { ElisymYaml } from './schema';\n\nconst PLACEHOLDER_DISPLAY_NAME = 'My Agent';\nconst PLACEHOLDER_PICTURE = './avatar.png';\nconst PLACEHOLDER_BANNER = './banner.png';\nconst PLACEHOLDER_PAYMENTS = [\n { chain: 'solana', network: 'devnet', address: '<your-solana-address>' },\n];\nconst PLACEHOLDER_LLM = {\n provider: 'anthropic',\n model: 'claude-sonnet-4-6',\n max_tokens: 4096,\n};\nconst DEFAULT_SECURITY = { withdrawals_enabled: false, agent_switch_enabled: false };\n\ninterface FieldBlock {\n description: string;\n key: keyof ElisymYaml;\n value: unknown;\n placeholder: unknown;\n}\n\nfunction commentLines(text: string): string {\n return text\n .split('\\n')\n .map((line) => (line.length > 0 ? `# ${line}` : '#'))\n .join('\\n');\n}\n\nfunction isUnset(value: unknown): boolean {\n if (value === undefined) {\n return true;\n }\n if (Array.isArray(value) && value.length === 0) {\n return true;\n }\n return false;\n}\n\nfunction renderBlock(block: FieldBlock): string {\n const header = commentLines(block.description);\n const unset = isUnset(block.value);\n const renderValue = unset ? block.placeholder : block.value;\n const yamlBody = YAML.stringify({ [block.key]: renderValue }).trimEnd();\n const body = unset ? commentLines(yamlBody) : yamlBody;\n return `${header}\\n${body}`;\n}\n\nexport function renderInitialYaml(yaml: ElisymYaml): string {\n const security = {\n withdrawals_enabled: yaml.security.withdrawals_enabled ?? DEFAULT_SECURITY.withdrawals_enabled,\n agent_switch_enabled:\n yaml.security.agent_switch_enabled ?? DEFAULT_SECURITY.agent_switch_enabled,\n };\n\n const blocks: FieldBlock[] = [\n {\n description: 'Human-readable name shown in UI. Falls back to the folder name when omitted.',\n key: 'display_name',\n value: yaml.display_name,\n placeholder: PLACEHOLDER_DISPLAY_NAME,\n },\n {\n description: 'Public description shown in discovery results.',\n key: 'description',\n value: yaml.description,\n placeholder: '',\n },\n {\n description: 'Avatar - relative path (to this YAML) or absolute URL.',\n key: 'picture',\n value: yaml.picture,\n placeholder: PLACEHOLDER_PICTURE,\n },\n {\n description: 'Banner - relative path (to this YAML) or absolute URL.',\n key: 'banner',\n value: yaml.banner,\n placeholder: PLACEHOLDER_BANNER,\n },\n {\n description: 'Nostr relays this agent connects to.',\n key: 'relays',\n value: yaml.relays,\n placeholder: [...RELAYS],\n },\n {\n description:\n 'Payment wallets per chain. Each entry receives every asset on that chain ' +\n '(SOL directly; SPL tokens via the ATA derived from this address).',\n key: 'payments',\n value: yaml.payments,\n placeholder: PLACEHOLDER_PAYMENTS,\n },\n {\n description:\n 'LLM configuration. Omit (or comment out) to run as a non-LLM agent ' +\n '(static-file or script skills only).',\n key: 'llm',\n value: yaml.llm,\n placeholder: PLACEHOLDER_LLM,\n },\n {\n description: 'Capability gates. Both default to false; flip to true to enable.',\n key: 'security',\n value: security,\n placeholder: DEFAULT_SECURITY,\n },\n ];\n\n return blocks.map(renderBlock).join('\\n\\n') + '\\n';\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\nimport { renderInitialYaml } from './template';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write a brand-new elisym.yaml with descriptive header comments and\n * commented-out examples for unset optional fields. Use only at agent\n * creation time (CLI `init`, MCP `create_agent`). Subsequent edits go\n * through `writeYaml`, which discards comments.\n */\nexport async function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = renderInitialYaml(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * List all agents discoverable from the current working directory:\n * - project-local: nearest .elisym/ (walk up to first .git or $HOME)\n * - home-global: ~/.elisym/\n * Project-local entries shadow home-global entries with the same name.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport YAML from 'yaml';\nimport { findProjectElisymDir, homeElisymDir, YAML_FILENAME } from './paths';\nimport type { AgentSource } from './resolver';\nimport { ElisymYamlSchema } from './schema';\n\nexport interface ListedAgent {\n name: string;\n source: AgentSource;\n dir: string;\n /** display_name from YAML, if present. */\n displayName?: string;\n /** true when this entry is project-local and a home-global agent with the same name exists. */\n shadowsGlobal: boolean;\n}\n\n/** List agents in both locations, deduping by name (project wins). */\nexport async function listAgents(cwd: string): Promise<ListedAgent[]> {\n const homeDir = homeElisymDir();\n const projectDir = findProjectElisymDir(cwd);\n\n const homeAgents = await listAgentsInDir(homeDir, 'home');\n const projectAgents = projectDir ? await listAgentsInDir(projectDir, 'project') : [];\n\n const homeNames = new Set(homeAgents.map((agent) => agent.name));\n\n const merged: ListedAgent[] = [];\n\n for (const entry of projectAgents) {\n merged.push({ ...entry, shadowsGlobal: homeNames.has(entry.name) });\n }\n const projectNames = new Set(projectAgents.map((agent) => agent.name));\n for (const entry of homeAgents) {\n if (!projectNames.has(entry.name)) {\n merged.push(entry);\n }\n }\n\n merged.sort((left, right) => left.name.localeCompare(right.name));\n return merged;\n}\n\nasync function listAgentsInDir(rootDir: string, source: AgentSource): Promise<ListedAgent[]> {\n let entries: string[];\n try {\n entries = await readdir(rootDir);\n } catch {\n return [];\n }\n\n const results: ListedAgent[] = [];\n for (const entry of entries) {\n if (entry.startsWith('.')) {\n continue;\n }\n const agentDir = join(rootDir, entry);\n const yamlPath = join(agentDir, YAML_FILENAME);\n const displayName = await tryReadDisplayName(yamlPath);\n if (displayName === null) {\n continue;\n }\n results.push({\n name: entry,\n source,\n dir: agentDir,\n displayName: displayName || undefined,\n shadowsGlobal: false,\n });\n }\n\n return results;\n}\n\n/**\n * Read display_name from a YAML file. Returns null if the file is missing\n * or cannot be parsed (agent directory is skipped in listings).\n */\nasync function tryReadDisplayName(yamlPath: string): Promise<string | null> {\n let raw: string;\n try {\n raw = await readFile(yamlPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = YAML.parse(raw);\n const yaml = ElisymYamlSchema.partial().safeParse(parsed ?? {});\n if (!yaml.success) {\n return '';\n }\n return yaml.data.display_name ?? '';\n } catch {\n return '';\n }\n}\n","/**\n * Media cache: maps local image paths to uploaded URLs + sha256.\n * On each start, the CLI hashes the file and skips re-upload if the hash matches.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { agentPaths } from './paths';\nimport { MediaCacheSchema, type MediaCache, type MediaCacheEntry } from './schema';\nimport { writeFileAtomic } from './writer';\n\n/** Read .media-cache.json. Returns empty object if missing or corrupt. */\nexport async function readMediaCache(agentDir: string): Promise<MediaCache> {\n const path = agentPaths(agentDir).mediaCache;\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n const result = MediaCacheSchema.safeParse(parsed);\n return result.success ? result.data : {};\n } catch {\n return {};\n }\n}\n\nexport async function writeMediaCache(agentDir: string, cache: MediaCache): Promise<void> {\n const path = agentPaths(agentDir).mediaCache;\n const body = JSON.stringify(cache, null, 2) + '\\n';\n await writeFileAtomic(path, body, 0o600);\n}\n\n/** Compute sha256 hex of a file's contents. */\nexport async function hashFile(filePath: string): Promise<string> {\n const buf = await readFile(filePath);\n return createHash('sha256').update(buf).digest('hex');\n}\n\n/**\n * Look up a cached URL for a local file path. Returns the cached URL if\n * the file's current hash matches the cache entry; otherwise null.\n */\nexport async function lookupCachedUrl(\n cache: MediaCache,\n relativePath: string,\n absolutePath: string,\n): Promise<string | null> {\n const entry = cache[relativePath];\n if (!entry) {\n return null;\n }\n let hash: string;\n try {\n hash = await hashFile(absolutePath);\n } catch {\n return null;\n }\n return hash === entry.sha256 ? entry.url : null;\n}\n\nexport function newCacheEntry(url: string, sha256: string): MediaCacheEntry {\n return { url, sha256, uploaded_at: new Date().toISOString() };\n}\n"]}
|
package/dist/agent-store.d.cts
CHANGED
|
@@ -298,6 +298,13 @@ interface CreatedAgentDir {
|
|
|
298
298
|
declare function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir>;
|
|
299
299
|
/** Write elisym.yaml atomically. Validates via Zod before writing. */
|
|
300
300
|
declare function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* Write a brand-new elisym.yaml with descriptive header comments and
|
|
303
|
+
* commented-out examples for unset optional fields. Use only at agent
|
|
304
|
+
* creation time (CLI `init`, MCP `create_agent`). Subsequent edits go
|
|
305
|
+
* through `writeYaml`, which discards comments.
|
|
306
|
+
*/
|
|
307
|
+
declare function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void>;
|
|
301
308
|
/**
|
|
302
309
|
* Write .secrets.json atomically. If `passphrase` is given, encrypts all
|
|
303
310
|
* plaintext secret fields (already-encrypted values are left as-is).
|
|
@@ -308,6 +315,20 @@ declare function writeSecrets(agentDir: string, secrets: Secrets, passphrase?: s
|
|
|
308
315
|
/** Atomic write: temp file + rename. Preserves mode. */
|
|
309
316
|
declare function writeFileAtomic(path: string, data: string | Buffer, mode: number): Promise<void>;
|
|
310
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Render a fresh `elisym.yaml` as a string with descriptive header comments
|
|
320
|
+
* over each top-level field. Optional fields that are not set in the input
|
|
321
|
+
* are emitted as commented-out examples so a new operator can see what else
|
|
322
|
+
* is configurable without leaving the file.
|
|
323
|
+
*
|
|
324
|
+
* Used only at agent-creation time (CLI `init`, MCP `create_agent`). On
|
|
325
|
+
* subsequent writes via `writeYaml`, the document is re-serialized without
|
|
326
|
+
* comments - this template is a one-shot scaffold, not a round-tripping
|
|
327
|
+
* format.
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
declare function renderInitialYaml(yaml: ElisymYaml): string;
|
|
331
|
+
|
|
311
332
|
/**
|
|
312
333
|
* List all agents discoverable from the current working directory:
|
|
313
334
|
* - project-local: nearest .elisym/ (walk up to first .git or $HOME)
|
|
@@ -344,4 +365,4 @@ declare function hashFile(filePath: string): Promise<string>;
|
|
|
344
365
|
declare function lookupCachedUrl(cache: MediaCache, relativePath: string, absolutePath: string): Promise<string | null>;
|
|
345
366
|
declare function newCacheEntry(url: string, sha256: string): MediaCacheEntry;
|
|
346
367
|
|
|
347
|
-
export { AgentNameSchema, type AgentPaths, type AgentSource, type CreateAgentDirOptions, type CreatedAgentDir, ELISYM_DIRNAME, type ElisymYaml, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, type ListedAgent, type LlmEntry, LlmSchema, type LoadedAgent, MEDIA_CACHE_FILENAME, type MediaCache, type MediaCacheEntry, MediaCacheEntrySchema, MediaCacheSchema, type PaymentEntry, PaymentSchema, type ResolvedAgent, SECRETS_FILENAME, SKILLS_DIRNAME, type Secrets, SecretsSchema, type SecurityFlags, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml };
|
|
368
|
+
export { AgentNameSchema, type AgentPaths, type AgentSource, type CreateAgentDirOptions, type CreatedAgentDir, ELISYM_DIRNAME, type ElisymYaml, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, type ListedAgent, type LlmEntry, LlmSchema, type LoadedAgent, MEDIA_CACHE_FILENAME, type MediaCache, type MediaCacheEntry, MediaCacheEntrySchema, MediaCacheSchema, type PaymentEntry, PaymentSchema, type ResolvedAgent, SECRETS_FILENAME, SKILLS_DIRNAME, type Secrets, SecretsSchema, type SecurityFlags, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, renderInitialYaml, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml, writeYamlInitial };
|
package/dist/agent-store.d.ts
CHANGED
|
@@ -298,6 +298,13 @@ interface CreatedAgentDir {
|
|
|
298
298
|
declare function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir>;
|
|
299
299
|
/** Write elisym.yaml atomically. Validates via Zod before writing. */
|
|
300
300
|
declare function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* Write a brand-new elisym.yaml with descriptive header comments and
|
|
303
|
+
* commented-out examples for unset optional fields. Use only at agent
|
|
304
|
+
* creation time (CLI `init`, MCP `create_agent`). Subsequent edits go
|
|
305
|
+
* through `writeYaml`, which discards comments.
|
|
306
|
+
*/
|
|
307
|
+
declare function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void>;
|
|
301
308
|
/**
|
|
302
309
|
* Write .secrets.json atomically. If `passphrase` is given, encrypts all
|
|
303
310
|
* plaintext secret fields (already-encrypted values are left as-is).
|
|
@@ -308,6 +315,20 @@ declare function writeSecrets(agentDir: string, secrets: Secrets, passphrase?: s
|
|
|
308
315
|
/** Atomic write: temp file + rename. Preserves mode. */
|
|
309
316
|
declare function writeFileAtomic(path: string, data: string | Buffer, mode: number): Promise<void>;
|
|
310
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Render a fresh `elisym.yaml` as a string with descriptive header comments
|
|
320
|
+
* over each top-level field. Optional fields that are not set in the input
|
|
321
|
+
* are emitted as commented-out examples so a new operator can see what else
|
|
322
|
+
* is configurable without leaving the file.
|
|
323
|
+
*
|
|
324
|
+
* Used only at agent-creation time (CLI `init`, MCP `create_agent`). On
|
|
325
|
+
* subsequent writes via `writeYaml`, the document is re-serialized without
|
|
326
|
+
* comments - this template is a one-shot scaffold, not a round-tripping
|
|
327
|
+
* format.
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
declare function renderInitialYaml(yaml: ElisymYaml): string;
|
|
331
|
+
|
|
311
332
|
/**
|
|
312
333
|
* List all agents discoverable from the current working directory:
|
|
313
334
|
* - project-local: nearest .elisym/ (walk up to first .git or $HOME)
|
|
@@ -344,4 +365,4 @@ declare function hashFile(filePath: string): Promise<string>;
|
|
|
344
365
|
declare function lookupCachedUrl(cache: MediaCache, relativePath: string, absolutePath: string): Promise<string | null>;
|
|
345
366
|
declare function newCacheEntry(url: string, sha256: string): MediaCacheEntry;
|
|
346
367
|
|
|
347
|
-
export { AgentNameSchema, type AgentPaths, type AgentSource, type CreateAgentDirOptions, type CreatedAgentDir, ELISYM_DIRNAME, type ElisymYaml, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, type ListedAgent, type LlmEntry, LlmSchema, type LoadedAgent, MEDIA_CACHE_FILENAME, type MediaCache, type MediaCacheEntry, MediaCacheEntrySchema, MediaCacheSchema, type PaymentEntry, PaymentSchema, type ResolvedAgent, SECRETS_FILENAME, SKILLS_DIRNAME, type Secrets, SecretsSchema, type SecurityFlags, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml };
|
|
368
|
+
export { AgentNameSchema, type AgentPaths, type AgentSource, type CreateAgentDirOptions, type CreatedAgentDir, ELISYM_DIRNAME, type ElisymYaml, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, type ListedAgent, type LlmEntry, LlmSchema, type LoadedAgent, MEDIA_CACHE_FILENAME, type MediaCache, type MediaCacheEntry, MediaCacheEntrySchema, MediaCacheSchema, type PaymentEntry, PaymentSchema, type ResolvedAgent, SECRETS_FILENAME, SKILLS_DIRNAME, type Secrets, SecretsSchema, type SecurityFlags, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, renderInitialYaml, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml, writeYamlInitial };
|
package/dist/agent-store.js
CHANGED
|
@@ -8,6 +8,15 @@ import { Buffer } from 'node:buffer';
|
|
|
8
8
|
import { randomBytes, createHash, scryptSync, createDecipheriv, createCipheriv } from 'node:crypto';
|
|
9
9
|
|
|
10
10
|
// src/agent-store/schema.ts
|
|
11
|
+
|
|
12
|
+
// src/constants.ts
|
|
13
|
+
var RELAYS = [
|
|
14
|
+
"wss://relay.damus.io",
|
|
15
|
+
"wss://nos.lol",
|
|
16
|
+
"wss://relay.nostr.band",
|
|
17
|
+
"wss://relay.primal.net",
|
|
18
|
+
"wss://relay.snort.social"
|
|
19
|
+
];
|
|
11
20
|
var LIMITS = {
|
|
12
21
|
MAX_DESCRIPTION_LENGTH: 500,
|
|
13
22
|
MAX_AGENT_NAME_LENGTH: 64};
|
|
@@ -299,6 +308,98 @@ function listEncryptedFields(secrets) {
|
|
|
299
308
|
function homeElisymPathHint(name) {
|
|
300
309
|
return `~/.elisym/${name}/elisym.yaml`;
|
|
301
310
|
}
|
|
311
|
+
var PLACEHOLDER_DISPLAY_NAME = "My Agent";
|
|
312
|
+
var PLACEHOLDER_PICTURE = "./avatar.png";
|
|
313
|
+
var PLACEHOLDER_BANNER = "./banner.png";
|
|
314
|
+
var PLACEHOLDER_PAYMENTS = [
|
|
315
|
+
{ chain: "solana", network: "devnet", address: "<your-solana-address>" }
|
|
316
|
+
];
|
|
317
|
+
var PLACEHOLDER_LLM = {
|
|
318
|
+
provider: "anthropic",
|
|
319
|
+
model: "claude-sonnet-4-6",
|
|
320
|
+
max_tokens: 4096
|
|
321
|
+
};
|
|
322
|
+
var DEFAULT_SECURITY = { withdrawals_enabled: false, agent_switch_enabled: false };
|
|
323
|
+
function commentLines(text) {
|
|
324
|
+
return text.split("\n").map((line) => line.length > 0 ? `# ${line}` : "#").join("\n");
|
|
325
|
+
}
|
|
326
|
+
function isUnset(value) {
|
|
327
|
+
if (value === void 0) {
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
function renderBlock(block) {
|
|
336
|
+
const header = commentLines(block.description);
|
|
337
|
+
const unset = isUnset(block.value);
|
|
338
|
+
const renderValue = unset ? block.placeholder : block.value;
|
|
339
|
+
const yamlBody = YAML.stringify({ [block.key]: renderValue }).trimEnd();
|
|
340
|
+
const body = unset ? commentLines(yamlBody) : yamlBody;
|
|
341
|
+
return `${header}
|
|
342
|
+
${body}`;
|
|
343
|
+
}
|
|
344
|
+
function renderInitialYaml(yaml) {
|
|
345
|
+
const security = {
|
|
346
|
+
withdrawals_enabled: yaml.security.withdrawals_enabled ?? DEFAULT_SECURITY.withdrawals_enabled,
|
|
347
|
+
agent_switch_enabled: yaml.security.agent_switch_enabled ?? DEFAULT_SECURITY.agent_switch_enabled
|
|
348
|
+
};
|
|
349
|
+
const blocks = [
|
|
350
|
+
{
|
|
351
|
+
description: "Human-readable name shown in UI. Falls back to the folder name when omitted.",
|
|
352
|
+
key: "display_name",
|
|
353
|
+
value: yaml.display_name,
|
|
354
|
+
placeholder: PLACEHOLDER_DISPLAY_NAME
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
description: "Public description shown in discovery results.",
|
|
358
|
+
key: "description",
|
|
359
|
+
value: yaml.description,
|
|
360
|
+
placeholder: ""
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
description: "Avatar - relative path (to this YAML) or absolute URL.",
|
|
364
|
+
key: "picture",
|
|
365
|
+
value: yaml.picture,
|
|
366
|
+
placeholder: PLACEHOLDER_PICTURE
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
description: "Banner - relative path (to this YAML) or absolute URL.",
|
|
370
|
+
key: "banner",
|
|
371
|
+
value: yaml.banner,
|
|
372
|
+
placeholder: PLACEHOLDER_BANNER
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
description: "Nostr relays this agent connects to.",
|
|
376
|
+
key: "relays",
|
|
377
|
+
value: yaml.relays,
|
|
378
|
+
placeholder: [...RELAYS]
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
description: "Payment wallets per chain. Each entry receives every asset on that chain (SOL directly; SPL tokens via the ATA derived from this address).",
|
|
382
|
+
key: "payments",
|
|
383
|
+
value: yaml.payments,
|
|
384
|
+
placeholder: PLACEHOLDER_PAYMENTS
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
description: "LLM configuration. Omit (or comment out) to run as a non-LLM agent (static-file or script skills only).",
|
|
388
|
+
key: "llm",
|
|
389
|
+
value: yaml.llm,
|
|
390
|
+
placeholder: PLACEHOLDER_LLM
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
description: "Capability gates. Both default to false; flip to true to enable.",
|
|
394
|
+
key: "security",
|
|
395
|
+
value: security,
|
|
396
|
+
placeholder: DEFAULT_SECURITY
|
|
397
|
+
}
|
|
398
|
+
];
|
|
399
|
+
return blocks.map(renderBlock).join("\n\n") + "\n";
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/agent-store/writer.ts
|
|
302
403
|
var GITIGNORE_CONTENT = [
|
|
303
404
|
"# elisym private state - do not commit.",
|
|
304
405
|
".secrets.json",
|
|
@@ -343,6 +444,12 @@ async function writeYaml(agentDir, yaml) {
|
|
|
343
444
|
const target = agentPaths(agentDir).yaml;
|
|
344
445
|
await writeFileAtomic(target, body, 420);
|
|
345
446
|
}
|
|
447
|
+
async function writeYamlInitial(agentDir, yaml) {
|
|
448
|
+
const validated = ElisymYamlSchema.parse(yaml);
|
|
449
|
+
const body = renderInitialYaml(validated);
|
|
450
|
+
const target = agentPaths(agentDir).yaml;
|
|
451
|
+
await writeFileAtomic(target, body, 420);
|
|
452
|
+
}
|
|
346
453
|
async function writeSecrets(agentDir, secrets, passphrase) {
|
|
347
454
|
const validated = SecretsSchema.parse(secrets);
|
|
348
455
|
let encryptedLlmKeys;
|
|
@@ -509,6 +616,6 @@ function newCacheEntry(url, sha256) {
|
|
|
509
616
|
return { url, sha256, uploaded_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
510
617
|
}
|
|
511
618
|
|
|
512
|
-
export { AgentNameSchema, ELISYM_DIRNAME, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, LlmSchema, MEDIA_CACHE_FILENAME, MediaCacheEntrySchema, MediaCacheSchema, PaymentSchema, SECRETS_FILENAME, SKILLS_DIRNAME, SecretsSchema, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml };
|
|
619
|
+
export { AgentNameSchema, ELISYM_DIRNAME, ElisymYamlSchema, GITIGNORE_FILENAME, JOBS_FILENAME, LlmSchema, MEDIA_CACHE_FILENAME, MediaCacheEntrySchema, MediaCacheSchema, PaymentSchema, SECRETS_FILENAME, SKILLS_DIRNAME, SecretsSchema, SecurityFlagsSchema, YAML_FILENAME, agentPaths, createAgentDir, elisymRootFor, findProjectElisymDir, globalConfigPath, hashFile, homeElisymDir, listAgents, loadAgent, loadResolvedAgent, lookupCachedUrl, newCacheEntry, readAgentPublic, readMediaCache, renderInitialYaml, resolveAgent, resolveInHome, resolveInProject, writeFileAtomic, writeMediaCache, writeSecrets, writeYaml, writeYamlInitial };
|
|
513
620
|
//# sourceMappingURL=agent-store.js.map
|
|
514
621
|
//# sourceMappingURL=agent-store.js.map
|
package/dist/agent-store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/agent-store/schema.ts","../src/agent-store/paths.ts","../src/agent-store/resolver.ts","../src/primitives/config.ts","../src/primitives/encryption.ts","../src/agent-store/loader.ts","../src/agent-store/writer.ts","../src/agent-store/list.ts","../src/agent-store/media-cache.ts"],"names":["join","existsSync","YAML","dirname","randomBytes","readFile"],"mappings":"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","file":"agent-store.js","sourcesContent":["import type { Address } from '@solana/kit';\n\nexport const RELAYS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n];\n\nexport const KIND_APP_HANDLER = 31990;\nexport const KIND_JOB_REQUEST_BASE = 5000;\nexport const KIND_JOB_RESULT_BASE = 6000;\nexport const KIND_JOB_FEEDBACK = 7000;\nexport const DEFAULT_KIND_OFFSET = 100;\n\n/** Default job request kind (5000 + 100). */\nexport const KIND_JOB_REQUEST = KIND_JOB_REQUEST_BASE + DEFAULT_KIND_OFFSET;\n/** Default job result kind (6000 + 100). */\nexport const KIND_JOB_RESULT = KIND_JOB_RESULT_BASE + DEFAULT_KIND_OFFSET;\n\n/** Compute a job request kind from an offset (5000 + offset). */\nexport function jobRequestKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_REQUEST_BASE + offset;\n}\n\n/** Compute a job result kind from an offset (6000 + offset). */\nexport function jobResultKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_RESULT_BASE + offset;\n}\n\n/** Ephemeral ping/pong kinds (not stored by relays, forwarded in real-time). */\nexport const KIND_PING = 20200;\nexport const KIND_PONG = 20201;\n\nexport const LAMPORTS_PER_SOL = 1_000_000_000;\n\n/**\n * Solana program ID for the elisym protocol config (devnet deployment).\n *\n * The Anchor program at this address is the source of truth for fee bps,\n * treasury address, and admin rotation state. Read via `getProtocolConfig`.\n */\nexport const PROTOCOL_PROGRAM_ID_DEVNET = 'BrX1CRkSgvcjxBvc2bgc3QqgWjinusofDmeP7ZVxvwrE' as Address;\n\n/**\n * Read-only marker pubkey attached as a non-signer account to every elisym\n * payment transaction. Lets indexers enumerate every elisym tx network-wide\n * via a single `getSignaturesForAddress(ELISYM_PROTOCOL_TAG)` call,\n * independent of fee size or recipient.\n *\n * The account does not need to exist on-chain; including its pubkey as an\n * extra read-only account in the provider transfer instruction is enough for\n * Solana's tx-by-account index to pick it up. The corresponding secret key\n * was generated and discarded - the tag never signs and never holds funds.\n */\nexport const ELISYM_PROTOCOL_TAG = 'ELiZksgwDt41LaeuPDLkUfWgFXhGgVayTMP7L5nTSEL8' as Address;\n\nexport type ProtocolCluster = 'devnet' | 'mainnet' | 'localnet';\n\n/**\n * Resolve the elisym-config program ID for a given Solana cluster.\n * Mainnet is intentionally unsupported until the program ships there.\n */\nexport function getProtocolProgramId(cluster: ProtocolCluster): Address {\n switch (cluster) {\n case 'devnet':\n case 'localnet':\n return PROTOCOL_PROGRAM_ID_DEVNET;\n case 'mainnet':\n throw new Error('Protocol program is not deployed on mainnet yet');\n }\n}\n\n/** Default values for timeouts, retries, and batch sizes. */\nexport const DEFAULTS = {\n SUBSCRIPTION_TIMEOUT_MS: 120_000,\n PING_TIMEOUT_MS: 3_000,\n PING_RETRIES: 2,\n PING_CACHE_TTL_MS: 30_000,\n PAYMENT_EXPIRY_SECS: 600,\n BATCH_SIZE: 250,\n QUERY_TIMEOUT_MS: 15_000,\n EOSE_TIMEOUT_MS: 3_000,\n VERIFY_RETRIES: 10,\n VERIFY_INTERVAL_MS: 3_000,\n VERIFY_BY_REF_RETRIES: 15,\n VERIFY_BY_REF_INTERVAL_MS: 2_000,\n RESULT_RETRY_COUNT: 3,\n RESULT_RETRY_BASE_MS: 1_000,\n QUERY_MAX_CONCURRENCY: 6,\n VERIFY_SIGNATURE_LIMIT: 25,\n} as const;\n\n/** Protocol limits for input validation. */\nexport const LIMITS = {\n MAX_INPUT_LENGTH: 100_000,\n MAX_TIMEOUT_SECS: 600,\n MAX_CAPABILITIES: 20,\n MAX_DESCRIPTION_LENGTH: 500,\n MAX_AGENT_NAME_LENGTH: 64,\n MAX_CAPABILITY_LENGTH: 64,\n} as const;\n","/**\n * Zod schemas for elisym.yaml (public source of truth) and secrets.json (private).\n * Shared between CLI (provider mode) and MCP (customer mode, future provider mode).\n */\n\nimport { z } from 'zod';\nimport { LIMITS } from '../constants';\n\nconst AGENT_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\nexport const AgentNameSchema = z\n .string()\n .min(1)\n .max(LIMITS.MAX_AGENT_NAME_LENGTH)\n .regex(AGENT_NAME_PATTERN, 'alphanumeric, underscore, or hyphen only');\n\n/**\n * Agent wallet entry. One entry per (chain, network) - the address receives\n * every asset on that chain (SOL directly, SPL tokens via their ATA derived\n * from (address, mint)). Per-asset pricing lives in each skill's `SKILL.md`;\n * the canonical mint registry lives in `KNOWN_ASSETS` (payment/assets.ts).\n */\nexport const PaymentSchema = z.object({\n chain: z.literal('solana'),\n network: z.enum(['devnet']),\n address: z.string().min(1),\n});\n\nexport const LlmSchema = z.object({\n provider: z.string().min(1),\n model: z.string().min(1),\n max_tokens: z.number().int().positive().max(200_000).default(4096),\n});\n\nexport const SecurityFlagsSchema = z.object({\n withdrawals_enabled: z.boolean().default(false),\n agent_switch_enabled: z.boolean().default(false),\n});\n\n/**\n * elisym.yaml schema. Public - committed to git.\n * Agent name NOT stored here - derived from containing folder name.\n *\n * The top-level field list is mirrored in `skills/elisym-config/SKILL.md`\n * so the elisym-config agent skill can patch this file directly. Drift\n * is guarded by `packages/sdk/tests/config-skill-drift.test.ts` - when\n * you add or remove a top-level field here, update that SKILL.md too.\n */\nexport const ElisymYamlSchema = z\n .object({\n /** Human-readable name shown in UI (optional). Falls back to folder name. */\n display_name: z.string().max(LIMITS.MAX_AGENT_NAME_LENGTH).optional(),\n description: z.string().max(LIMITS.MAX_DESCRIPTION_LENGTH).default(''),\n /** Relative path (to this YAML) or absolute URL. */\n picture: z.string().optional(),\n /** Relative path (to this YAML) or absolute URL. */\n banner: z.string().optional(),\n relays: z.array(z.string().url()).default([]),\n payments: z.array(PaymentSchema).default([]),\n llm: LlmSchema.optional(),\n security: SecurityFlagsSchema.partial().default({}),\n })\n .strict();\n\nexport type ElisymYaml = z.infer<typeof ElisymYamlSchema>;\nexport type PaymentEntry = z.infer<typeof PaymentSchema>;\nexport type LlmEntry = z.infer<typeof LlmSchema>;\nexport type SecurityFlags = z.infer<typeof SecurityFlagsSchema>;\n\n/**\n * secrets.json schema. Private - .gitignore.\n * Values may be plaintext or `encrypted:v1:...` blobs (AES-256-GCM + scrypt).\n *\n * `llm_api_keys` is a generic record keyed by provider id (e.g. `anthropic`,\n * `openai`, future `xai`/`google`/...). Adding a new LLM provider does not\n * require a schema change. Each value is a separate ciphertext blob when\n * encrypted.\n */\nexport const SecretsSchema = z\n .object({\n nostr_secret_key: z.string().min(1),\n solana_secret_key: z.string().optional(),\n /** Per-provider LLM API keys, keyed by descriptor id (e.g. `anthropic`, `openai`). */\n llm_api_keys: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nexport type Secrets = z.infer<typeof SecretsSchema>;\n\nexport interface MediaCacheEntry {\n url: string;\n sha256: string;\n uploaded_at: string;\n}\n\nexport const MediaCacheEntrySchema: z.ZodType<MediaCacheEntry> = z\n .object({\n url: z.string().url(),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n uploaded_at: z.string(),\n })\n .strict();\n\nexport const MediaCacheSchema = z.record(z.string(), MediaCacheEntrySchema);\n\nexport type MediaCache = z.infer<typeof MediaCacheSchema>;\n","/**\n * Path helpers for .elisym/ layout.\n *\n * Project-local (walk up from CWD until .git or $HOME):\n * <project>/.elisym/<name>/{elisym.yaml, .secrets.json, .media-cache.json, .jobs.json, .gitignore}\n *\n * Home-global (~/.elisym/<name>/): same file structure.\n *\n * Node.js only - relies on `node:fs`/`node:os`/`node:path`.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport const ELISYM_DIRNAME = '.elisym';\nexport const YAML_FILENAME = 'elisym.yaml';\nexport const SECRETS_FILENAME = '.secrets.json';\nexport const MEDIA_CACHE_FILENAME = '.media-cache.json';\nexport const JOBS_FILENAME = '.jobs.json';\nexport const GITIGNORE_FILENAME = '.gitignore';\nexport const SKILLS_DIRNAME = 'skills';\n\n/** Max depth for walk-up search (safety guard against unbounded loops). */\nconst MAX_WALK_UP_DEPTH = 64;\n\n/** ~/.elisym/ */\nexport function homeElisymDir(): string {\n return join(homedir(), ELISYM_DIRNAME);\n}\n\n/** ~/.elisym/config.yaml — global (not per-agent) config file. */\nexport function globalConfigPath(): string {\n return join(homeElisymDir(), 'config.yaml');\n}\n\n/**\n * Walk up from `startDir` looking for `.elisym/` directory.\n * Stops at (a) the first `.git` directory/file, (b) `$HOME`, (c) filesystem root,\n * or (d) MAX_WALK_UP_DEPTH iterations. Returns absolute path or null.\n */\nexport function findProjectElisymDir(startDir: string): string | null {\n const home = homedir();\n let current = resolve(startDir);\n let previous: string | null = null;\n\n for (let depth = 0; depth < MAX_WALK_UP_DEPTH; depth++) {\n if (current === previous) {\n return null;\n }\n\n // At $HOME: ~/.elisym/ is the home-global layout, not a project-local one.\n // Stop without matching to avoid misclassifying home agents as project.\n if (current === home) {\n return null;\n }\n\n const elisymCandidate = join(current, ELISYM_DIRNAME);\n if (existsSync(elisymCandidate) && safeIsDir(elisymCandidate)) {\n return elisymCandidate;\n }\n\n const gitCandidate = join(current, '.git');\n if (existsSync(gitCandidate)) {\n return null;\n }\n\n previous = current;\n current = dirname(current);\n }\n\n return null;\n}\n\nexport interface AgentPaths {\n dir: string;\n yaml: string;\n secrets: string;\n mediaCache: string;\n jobs: string;\n gitignore: string;\n skills: string;\n}\n\n/** Compute all file/dir paths for an agent given its root directory. */\nexport function agentPaths(agentDir: string): AgentPaths {\n return {\n dir: agentDir,\n yaml: join(agentDir, YAML_FILENAME),\n secrets: join(agentDir, SECRETS_FILENAME),\n mediaCache: join(agentDir, MEDIA_CACHE_FILENAME),\n jobs: join(agentDir, JOBS_FILENAME),\n gitignore: join(agentDir, GITIGNORE_FILENAME),\n skills: join(agentDir, SKILLS_DIRNAME),\n };\n}\n\nfunction safeIsDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n","/**\n * Agent resolution: find <name>/elisym.yaml via project-local walk-up, fallback to home.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ELISYM_DIRNAME, YAML_FILENAME, findProjectElisymDir, homeElisymDir } from './paths';\n\nexport type AgentSource = 'project' | 'home';\n\nexport interface ResolvedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n /** true when both a project-local and a home-global agent exist with the same name. */\n shadowsGlobal: boolean;\n}\n\n/**\n * Resolve an agent by name. Precedence: project-local beats home-global.\n * Returns null if not found in either location.\n */\nexport function resolveAgent(name: string, cwd: string): ResolvedAgent | null {\n const projectDir = resolveInProject(name, cwd);\n const homeDir = resolveInHome(name);\n\n if (projectDir) {\n return {\n name,\n dir: projectDir,\n source: 'project',\n shadowsGlobal: homeDir !== null,\n };\n }\n\n if (homeDir) {\n return { name, dir: homeDir, source: 'home', shadowsGlobal: false };\n }\n\n return null;\n}\n\n/** Return project-local agent dir if its YAML exists, else null. */\nexport function resolveInProject(name: string, cwd: string): string | null {\n const projectElisym = findProjectElisymDir(cwd);\n if (!projectElisym) {\n return null;\n }\n const agentDir = join(projectElisym, name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Return home-global agent dir if its YAML exists, else null. */\nexport function resolveInHome(name: string): string | null {\n const agentDir = join(homeElisymDir(), name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Path to the .elisym root (project or home) for a given target. */\nexport function elisymRootFor(target: AgentSource, cwd: string): string | null {\n if (target === 'home') {\n return homeElisymDir();\n }\n return findProjectElisymDir(cwd);\n}\n\n/** Re-export for convenience. */\nexport { ELISYM_DIRNAME };\n","/**\n * Agent-name validation shared between CLI and MCP.\n * Browser-safe - no Node.js imports.\n */\n\nimport { LIMITS } from '../constants';\n\nexport function validateAgentName(name: string): void {\n if (!name || name.length > LIMITS.MAX_AGENT_NAME_LENGTH || !/^[a-zA-Z0-9_-]+$/.test(name)) {\n throw new Error('Agent name must be 1-64 characters, alphanumeric, underscore, or hyphen.');\n }\n}\n","/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Load an agent: parse elisym.yaml + .secrets.json, decrypt if encrypted.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { validateAgentName } from '../primitives/config';\nimport { isEncrypted, decryptSecret } from '../primitives/encryption';\nimport { agentPaths } from './paths';\nimport { resolveAgent, type AgentSource, type ResolvedAgent } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nexport interface LoadedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n yaml: ElisymYaml;\n secrets: Secrets;\n /** true when at least one secret field was encrypted on disk. */\n encrypted: boolean;\n shadowsGlobal: boolean;\n}\n\n/** Raw resolve + read + parse, no decryption yet. Useful for ergonomic list views. */\nexport async function readAgentPublic(\n resolved: ResolvedAgent,\n): Promise<{ resolved: ResolvedAgent; yaml: ElisymYaml }> {\n const paths = agentPaths(resolved.dir);\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsed = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsed ?? {});\n return { resolved, yaml };\n}\n\n/**\n * Load an agent by name. Searches project-local first, then home.\n * Throws with clear error if missing or if encrypted secrets lack a passphrase.\n */\nexport async function loadAgent(\n name: string,\n cwd: string,\n passphrase?: string,\n): Promise<LoadedAgent> {\n validateAgentName(name);\n const resolved = resolveAgent(name, cwd);\n if (!resolved) {\n throw new Error(\n `Agent \"${name}\" not found. Looked for .elisym/${name}/elisym.yaml in project (walking up from ${cwd}) and in home (${homeElisymPathHint(name)}).`,\n );\n }\n return loadResolvedAgent(resolved, passphrase);\n}\n\n/** Load an agent whose location was already resolved. */\nexport async function loadResolvedAgent(\n resolved: ResolvedAgent,\n passphrase?: string,\n): Promise<LoadedAgent> {\n const paths = agentPaths(resolved.dir);\n\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsedYaml = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsedYaml ?? {});\n\n let secretsRaw: string;\n try {\n secretsRaw = await readFile(paths.secrets, 'utf-8');\n } catch {\n throw new Error(\n `Agent \"${resolved.name}\" has elisym.yaml but no secrets at ${paths.secrets}. Run \\`npx @elisym/cli init\\` to initialize secrets.`,\n );\n }\n\n const secrets = SecretsSchema.parse(JSON.parse(secretsRaw));\n const encryptedFields = listEncryptedFields(secrets);\n\n const effectivePassphrase = passphrase ?? process.env.ELISYM_PASSPHRASE;\n if (encryptedFields.length > 0 && !effectivePassphrase) {\n throw new Error(\n `Agent \"${resolved.name}\" has encrypted secrets [${encryptedFields.join(', ')}]. Set ELISYM_PASSPHRASE or pass a passphrase.`,\n );\n }\n\n const decrypted: Secrets = { ...secrets };\n if (effectivePassphrase) {\n if (isEncrypted(decrypted.nostr_secret_key)) {\n decrypted.nostr_secret_key = decryptSecret(decrypted.nostr_secret_key, effectivePassphrase);\n }\n if (decrypted.solana_secret_key && isEncrypted(decrypted.solana_secret_key)) {\n decrypted.solana_secret_key = decryptSecret(decrypted.solana_secret_key, effectivePassphrase);\n }\n if (decrypted.llm_api_keys) {\n const decryptedKeys: Record<string, string> = {};\n for (const [providerId, value] of Object.entries(decrypted.llm_api_keys)) {\n decryptedKeys[providerId] = isEncrypted(value)\n ? decryptSecret(value, effectivePassphrase)\n : value;\n }\n decrypted.llm_api_keys = decryptedKeys;\n }\n }\n\n return {\n name: resolved.name,\n dir: resolved.dir,\n source: resolved.source,\n yaml,\n secrets: decrypted,\n encrypted: encryptedFields.length > 0,\n shadowsGlobal: resolved.shadowsGlobal,\n };\n}\n\nfunction listEncryptedFields(secrets: Secrets): string[] {\n const out: string[] = [];\n if (isEncrypted(secrets.nostr_secret_key)) {\n out.push('nostr_secret_key');\n }\n if (secrets.solana_secret_key && isEncrypted(secrets.solana_secret_key)) {\n out.push('solana_secret_key');\n }\n if (secrets.llm_api_keys) {\n for (const [providerId, value] of Object.entries(secrets.llm_api_keys)) {\n if (isEncrypted(value)) {\n out.push(`llm_api_keys.${providerId}`);\n }\n }\n }\n return out;\n}\n\nfunction homeElisymPathHint(name: string): string {\n return `~/.elisym/${name}/elisym.yaml`;\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * List all agents discoverable from the current working directory:\n * - project-local: nearest .elisym/ (walk up to first .git or $HOME)\n * - home-global: ~/.elisym/\n * Project-local entries shadow home-global entries with the same name.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport YAML from 'yaml';\nimport { findProjectElisymDir, homeElisymDir, YAML_FILENAME } from './paths';\nimport type { AgentSource } from './resolver';\nimport { ElisymYamlSchema } from './schema';\n\nexport interface ListedAgent {\n name: string;\n source: AgentSource;\n dir: string;\n /** display_name from YAML, if present. */\n displayName?: string;\n /** true when this entry is project-local and a home-global agent with the same name exists. */\n shadowsGlobal: boolean;\n}\n\n/** List agents in both locations, deduping by name (project wins). */\nexport async function listAgents(cwd: string): Promise<ListedAgent[]> {\n const homeDir = homeElisymDir();\n const projectDir = findProjectElisymDir(cwd);\n\n const homeAgents = await listAgentsInDir(homeDir, 'home');\n const projectAgents = projectDir ? await listAgentsInDir(projectDir, 'project') : [];\n\n const homeNames = new Set(homeAgents.map((agent) => agent.name));\n\n const merged: ListedAgent[] = [];\n\n for (const entry of projectAgents) {\n merged.push({ ...entry, shadowsGlobal: homeNames.has(entry.name) });\n }\n const projectNames = new Set(projectAgents.map((agent) => agent.name));\n for (const entry of homeAgents) {\n if (!projectNames.has(entry.name)) {\n merged.push(entry);\n }\n }\n\n merged.sort((left, right) => left.name.localeCompare(right.name));\n return merged;\n}\n\nasync function listAgentsInDir(rootDir: string, source: AgentSource): Promise<ListedAgent[]> {\n let entries: string[];\n try {\n entries = await readdir(rootDir);\n } catch {\n return [];\n }\n\n const results: ListedAgent[] = [];\n for (const entry of entries) {\n if (entry.startsWith('.')) {\n continue;\n }\n const agentDir = join(rootDir, entry);\n const yamlPath = join(agentDir, YAML_FILENAME);\n const displayName = await tryReadDisplayName(yamlPath);\n if (displayName === null) {\n continue;\n }\n results.push({\n name: entry,\n source,\n dir: agentDir,\n displayName: displayName || undefined,\n shadowsGlobal: false,\n });\n }\n\n return results;\n}\n\n/**\n * Read display_name from a YAML file. Returns null if the file is missing\n * or cannot be parsed (agent directory is skipped in listings).\n */\nasync function tryReadDisplayName(yamlPath: string): Promise<string | null> {\n let raw: string;\n try {\n raw = await readFile(yamlPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = YAML.parse(raw);\n const yaml = ElisymYamlSchema.partial().safeParse(parsed ?? {});\n if (!yaml.success) {\n return '';\n }\n return yaml.data.display_name ?? '';\n } catch {\n return '';\n }\n}\n","/**\n * Media cache: maps local image paths to uploaded URLs + sha256.\n * On each start, the CLI hashes the file and skips re-upload if the hash matches.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { agentPaths } from './paths';\nimport { MediaCacheSchema, type MediaCache, type MediaCacheEntry } from './schema';\nimport { writeFileAtomic } from './writer';\n\n/** Read .media-cache.json. Returns empty object if missing or corrupt. */\nexport async function readMediaCache(agentDir: string): Promise<MediaCache> {\n const path = agentPaths(agentDir).mediaCache;\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n const result = MediaCacheSchema.safeParse(parsed);\n return result.success ? result.data : {};\n } catch {\n return {};\n }\n}\n\nexport async function writeMediaCache(agentDir: string, cache: MediaCache): Promise<void> {\n const path = agentPaths(agentDir).mediaCache;\n const body = JSON.stringify(cache, null, 2) + '\\n';\n await writeFileAtomic(path, body, 0o600);\n}\n\n/** Compute sha256 hex of a file's contents. */\nexport async function hashFile(filePath: string): Promise<string> {\n const buf = await readFile(filePath);\n return createHash('sha256').update(buf).digest('hex');\n}\n\n/**\n * Look up a cached URL for a local file path. Returns the cached URL if\n * the file's current hash matches the cache entry; otherwise null.\n */\nexport async function lookupCachedUrl(\n cache: MediaCache,\n relativePath: string,\n absolutePath: string,\n): Promise<string | null> {\n const entry = cache[relativePath];\n if (!entry) {\n return null;\n }\n let hash: string;\n try {\n hash = await hashFile(absolutePath);\n } catch {\n return null;\n }\n return hash === entry.sha256 ? entry.url : null;\n}\n\nexport function newCacheEntry(url: string, sha256: string): MediaCacheEntry {\n return { url, sha256, uploaded_at: new Date().toISOString() };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/agent-store/schema.ts","../src/agent-store/paths.ts","../src/agent-store/resolver.ts","../src/primitives/config.ts","../src/primitives/encryption.ts","../src/agent-store/loader.ts","../src/agent-store/template.ts","../src/agent-store/writer.ts","../src/agent-store/list.ts","../src/agent-store/media-cache.ts"],"names":["join","existsSync","YAML","dirname","randomBytes","readFile"],"mappings":"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","file":"agent-store.js","sourcesContent":["import type { Address } from '@solana/kit';\n\nexport const RELAYS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n];\n\nexport const KIND_APP_HANDLER = 31990;\nexport const KIND_JOB_REQUEST_BASE = 5000;\nexport const KIND_JOB_RESULT_BASE = 6000;\nexport const KIND_JOB_FEEDBACK = 7000;\nexport const DEFAULT_KIND_OFFSET = 100;\n\n/** Default job request kind (5000 + 100). */\nexport const KIND_JOB_REQUEST = KIND_JOB_REQUEST_BASE + DEFAULT_KIND_OFFSET;\n/** Default job result kind (6000 + 100). */\nexport const KIND_JOB_RESULT = KIND_JOB_RESULT_BASE + DEFAULT_KIND_OFFSET;\n\n/** Compute a job request kind from an offset (5000 + offset). */\nexport function jobRequestKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_REQUEST_BASE + offset;\n}\n\n/** Compute a job result kind from an offset (6000 + offset). */\nexport function jobResultKind(offset: number): number {\n if (!Number.isInteger(offset) || offset < 0 || offset >= 1000) {\n throw new Error(`Invalid kind offset: ${offset}. Must be integer 0-999.`);\n }\n return KIND_JOB_RESULT_BASE + offset;\n}\n\n/** Ephemeral ping/pong kinds (not stored by relays, forwarded in real-time). */\nexport const KIND_PING = 20200;\nexport const KIND_PONG = 20201;\n\nexport const LAMPORTS_PER_SOL = 1_000_000_000;\n\n/**\n * Solana program ID for the elisym protocol config (devnet deployment).\n *\n * The Anchor program at this address is the source of truth for fee bps,\n * treasury address, and admin rotation state. Read via `getProtocolConfig`.\n */\nexport const PROTOCOL_PROGRAM_ID_DEVNET = 'BrX1CRkSgvcjxBvc2bgc3QqgWjinusofDmeP7ZVxvwrE' as Address;\n\n/**\n * Read-only marker pubkey attached as a non-signer account to every elisym\n * payment transaction. Lets indexers enumerate every elisym tx network-wide\n * via a single `getSignaturesForAddress(ELISYM_PROTOCOL_TAG)` call,\n * independent of fee size or recipient.\n *\n * The account does not need to exist on-chain; including its pubkey as an\n * extra read-only account in the provider transfer instruction is enough for\n * Solana's tx-by-account index to pick it up. The corresponding secret key\n * was generated and discarded - the tag never signs and never holds funds.\n */\nexport const ELISYM_PROTOCOL_TAG = 'ELiZksgwDt41LaeuPDLkUfWgFXhGgVayTMP7L5nTSEL8' as Address;\n\nexport type ProtocolCluster = 'devnet' | 'mainnet' | 'localnet';\n\n/**\n * Resolve the elisym-config program ID for a given Solana cluster.\n * Mainnet is intentionally unsupported until the program ships there.\n */\nexport function getProtocolProgramId(cluster: ProtocolCluster): Address {\n switch (cluster) {\n case 'devnet':\n case 'localnet':\n return PROTOCOL_PROGRAM_ID_DEVNET;\n case 'mainnet':\n throw new Error('Protocol program is not deployed on mainnet yet');\n }\n}\n\n/** Default values for timeouts, retries, and batch sizes. */\nexport const DEFAULTS = {\n SUBSCRIPTION_TIMEOUT_MS: 120_000,\n PING_TIMEOUT_MS: 3_000,\n PING_RETRIES: 2,\n PING_CACHE_TTL_MS: 30_000,\n PAYMENT_EXPIRY_SECS: 600,\n BATCH_SIZE: 250,\n QUERY_TIMEOUT_MS: 15_000,\n EOSE_TIMEOUT_MS: 3_000,\n VERIFY_RETRIES: 10,\n VERIFY_INTERVAL_MS: 3_000,\n VERIFY_BY_REF_RETRIES: 15,\n VERIFY_BY_REF_INTERVAL_MS: 2_000,\n RESULT_RETRY_COUNT: 3,\n RESULT_RETRY_BASE_MS: 1_000,\n QUERY_MAX_CONCURRENCY: 6,\n VERIFY_SIGNATURE_LIMIT: 25,\n} as const;\n\n/** Protocol limits for input validation. */\nexport const LIMITS = {\n MAX_INPUT_LENGTH: 100_000,\n MAX_TIMEOUT_SECS: 600,\n MAX_CAPABILITIES: 20,\n MAX_DESCRIPTION_LENGTH: 500,\n MAX_AGENT_NAME_LENGTH: 64,\n MAX_CAPABILITY_LENGTH: 64,\n} as const;\n","/**\n * Zod schemas for elisym.yaml (public source of truth) and secrets.json (private).\n * Shared between CLI (provider mode) and MCP (customer mode, future provider mode).\n */\n\nimport { z } from 'zod';\nimport { LIMITS } from '../constants';\n\nconst AGENT_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\nexport const AgentNameSchema = z\n .string()\n .min(1)\n .max(LIMITS.MAX_AGENT_NAME_LENGTH)\n .regex(AGENT_NAME_PATTERN, 'alphanumeric, underscore, or hyphen only');\n\n/**\n * Agent wallet entry. One entry per (chain, network) - the address receives\n * every asset on that chain (SOL directly, SPL tokens via their ATA derived\n * from (address, mint)). Per-asset pricing lives in each skill's `SKILL.md`;\n * the canonical mint registry lives in `KNOWN_ASSETS` (payment/assets.ts).\n */\nexport const PaymentSchema = z.object({\n chain: z.literal('solana'),\n network: z.enum(['devnet']),\n address: z.string().min(1),\n});\n\nexport const LlmSchema = z.object({\n provider: z.string().min(1),\n model: z.string().min(1),\n max_tokens: z.number().int().positive().max(200_000).default(4096),\n});\n\nexport const SecurityFlagsSchema = z.object({\n withdrawals_enabled: z.boolean().default(false),\n agent_switch_enabled: z.boolean().default(false),\n});\n\n/**\n * elisym.yaml schema. Public - committed to git.\n * Agent name NOT stored here - derived from containing folder name.\n *\n * The top-level field list is mirrored in `skills/elisym-config/SKILL.md`\n * so the elisym-config agent skill can patch this file directly. Drift\n * is guarded by `packages/sdk/tests/config-skill-drift.test.ts` - when\n * you add or remove a top-level field here, update that SKILL.md too.\n */\nexport const ElisymYamlSchema = z\n .object({\n /** Human-readable name shown in UI (optional). Falls back to folder name. */\n display_name: z.string().max(LIMITS.MAX_AGENT_NAME_LENGTH).optional(),\n description: z.string().max(LIMITS.MAX_DESCRIPTION_LENGTH).default(''),\n /** Relative path (to this YAML) or absolute URL. */\n picture: z.string().optional(),\n /** Relative path (to this YAML) or absolute URL. */\n banner: z.string().optional(),\n relays: z.array(z.string().url()).default([]),\n payments: z.array(PaymentSchema).default([]),\n llm: LlmSchema.optional(),\n security: SecurityFlagsSchema.partial().default({}),\n })\n .strict();\n\nexport type ElisymYaml = z.infer<typeof ElisymYamlSchema>;\nexport type PaymentEntry = z.infer<typeof PaymentSchema>;\nexport type LlmEntry = z.infer<typeof LlmSchema>;\nexport type SecurityFlags = z.infer<typeof SecurityFlagsSchema>;\n\n/**\n * secrets.json schema. Private - .gitignore.\n * Values may be plaintext or `encrypted:v1:...` blobs (AES-256-GCM + scrypt).\n *\n * `llm_api_keys` is a generic record keyed by provider id (e.g. `anthropic`,\n * `openai`, future `xai`/`google`/...). Adding a new LLM provider does not\n * require a schema change. Each value is a separate ciphertext blob when\n * encrypted.\n */\nexport const SecretsSchema = z\n .object({\n nostr_secret_key: z.string().min(1),\n solana_secret_key: z.string().optional(),\n /** Per-provider LLM API keys, keyed by descriptor id (e.g. `anthropic`, `openai`). */\n llm_api_keys: z.record(z.string(), z.string()).optional(),\n })\n .strict();\n\nexport type Secrets = z.infer<typeof SecretsSchema>;\n\nexport interface MediaCacheEntry {\n url: string;\n sha256: string;\n uploaded_at: string;\n}\n\nexport const MediaCacheEntrySchema: z.ZodType<MediaCacheEntry> = z\n .object({\n url: z.string().url(),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n uploaded_at: z.string(),\n })\n .strict();\n\nexport const MediaCacheSchema = z.record(z.string(), MediaCacheEntrySchema);\n\nexport type MediaCache = z.infer<typeof MediaCacheSchema>;\n","/**\n * Path helpers for .elisym/ layout.\n *\n * Project-local (walk up from CWD until .git or $HOME):\n * <project>/.elisym/<name>/{elisym.yaml, .secrets.json, .media-cache.json, .jobs.json, .gitignore}\n *\n * Home-global (~/.elisym/<name>/): same file structure.\n *\n * Node.js only - relies on `node:fs`/`node:os`/`node:path`.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport const ELISYM_DIRNAME = '.elisym';\nexport const YAML_FILENAME = 'elisym.yaml';\nexport const SECRETS_FILENAME = '.secrets.json';\nexport const MEDIA_CACHE_FILENAME = '.media-cache.json';\nexport const JOBS_FILENAME = '.jobs.json';\nexport const GITIGNORE_FILENAME = '.gitignore';\nexport const SKILLS_DIRNAME = 'skills';\n\n/** Max depth for walk-up search (safety guard against unbounded loops). */\nconst MAX_WALK_UP_DEPTH = 64;\n\n/** ~/.elisym/ */\nexport function homeElisymDir(): string {\n return join(homedir(), ELISYM_DIRNAME);\n}\n\n/** ~/.elisym/config.yaml — global (not per-agent) config file. */\nexport function globalConfigPath(): string {\n return join(homeElisymDir(), 'config.yaml');\n}\n\n/**\n * Walk up from `startDir` looking for `.elisym/` directory.\n * Stops at (a) the first `.git` directory/file, (b) `$HOME`, (c) filesystem root,\n * or (d) MAX_WALK_UP_DEPTH iterations. Returns absolute path or null.\n */\nexport function findProjectElisymDir(startDir: string): string | null {\n const home = homedir();\n let current = resolve(startDir);\n let previous: string | null = null;\n\n for (let depth = 0; depth < MAX_WALK_UP_DEPTH; depth++) {\n if (current === previous) {\n return null;\n }\n\n // At $HOME: ~/.elisym/ is the home-global layout, not a project-local one.\n // Stop without matching to avoid misclassifying home agents as project.\n if (current === home) {\n return null;\n }\n\n const elisymCandidate = join(current, ELISYM_DIRNAME);\n if (existsSync(elisymCandidate) && safeIsDir(elisymCandidate)) {\n return elisymCandidate;\n }\n\n const gitCandidate = join(current, '.git');\n if (existsSync(gitCandidate)) {\n return null;\n }\n\n previous = current;\n current = dirname(current);\n }\n\n return null;\n}\n\nexport interface AgentPaths {\n dir: string;\n yaml: string;\n secrets: string;\n mediaCache: string;\n jobs: string;\n gitignore: string;\n skills: string;\n}\n\n/** Compute all file/dir paths for an agent given its root directory. */\nexport function agentPaths(agentDir: string): AgentPaths {\n return {\n dir: agentDir,\n yaml: join(agentDir, YAML_FILENAME),\n secrets: join(agentDir, SECRETS_FILENAME),\n mediaCache: join(agentDir, MEDIA_CACHE_FILENAME),\n jobs: join(agentDir, JOBS_FILENAME),\n gitignore: join(agentDir, GITIGNORE_FILENAME),\n skills: join(agentDir, SKILLS_DIRNAME),\n };\n}\n\nfunction safeIsDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n","/**\n * Agent resolution: find <name>/elisym.yaml via project-local walk-up, fallback to home.\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ELISYM_DIRNAME, YAML_FILENAME, findProjectElisymDir, homeElisymDir } from './paths';\n\nexport type AgentSource = 'project' | 'home';\n\nexport interface ResolvedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n /** true when both a project-local and a home-global agent exist with the same name. */\n shadowsGlobal: boolean;\n}\n\n/**\n * Resolve an agent by name. Precedence: project-local beats home-global.\n * Returns null if not found in either location.\n */\nexport function resolveAgent(name: string, cwd: string): ResolvedAgent | null {\n const projectDir = resolveInProject(name, cwd);\n const homeDir = resolveInHome(name);\n\n if (projectDir) {\n return {\n name,\n dir: projectDir,\n source: 'project',\n shadowsGlobal: homeDir !== null,\n };\n }\n\n if (homeDir) {\n return { name, dir: homeDir, source: 'home', shadowsGlobal: false };\n }\n\n return null;\n}\n\n/** Return project-local agent dir if its YAML exists, else null. */\nexport function resolveInProject(name: string, cwd: string): string | null {\n const projectElisym = findProjectElisymDir(cwd);\n if (!projectElisym) {\n return null;\n }\n const agentDir = join(projectElisym, name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Return home-global agent dir if its YAML exists, else null. */\nexport function resolveInHome(name: string): string | null {\n const agentDir = join(homeElisymDir(), name);\n const yamlPath = join(agentDir, YAML_FILENAME);\n return existsSync(yamlPath) ? agentDir : null;\n}\n\n/** Path to the .elisym root (project or home) for a given target. */\nexport function elisymRootFor(target: AgentSource, cwd: string): string | null {\n if (target === 'home') {\n return homeElisymDir();\n }\n return findProjectElisymDir(cwd);\n}\n\n/** Re-export for convenience. */\nexport { ELISYM_DIRNAME };\n","/**\n * Agent-name validation shared between CLI and MCP.\n * Browser-safe - no Node.js imports.\n */\n\nimport { LIMITS } from '../constants';\n\nexport function validateAgentName(name: string): void {\n if (!name || name.length > LIMITS.MAX_AGENT_NAME_LENGTH || !/^[a-zA-Z0-9_-]+$/.test(name)) {\n throw new Error('Agent name must be 1-64 characters, alphanumeric, underscore, or hyphen.');\n }\n}\n","/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Load an agent: parse elisym.yaml + .secrets.json, decrypt if encrypted.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { validateAgentName } from '../primitives/config';\nimport { isEncrypted, decryptSecret } from '../primitives/encryption';\nimport { agentPaths } from './paths';\nimport { resolveAgent, type AgentSource, type ResolvedAgent } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nexport interface LoadedAgent {\n name: string;\n dir: string;\n source: AgentSource;\n yaml: ElisymYaml;\n secrets: Secrets;\n /** true when at least one secret field was encrypted on disk. */\n encrypted: boolean;\n shadowsGlobal: boolean;\n}\n\n/** Raw resolve + read + parse, no decryption yet. Useful for ergonomic list views. */\nexport async function readAgentPublic(\n resolved: ResolvedAgent,\n): Promise<{ resolved: ResolvedAgent; yaml: ElisymYaml }> {\n const paths = agentPaths(resolved.dir);\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsed = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsed ?? {});\n return { resolved, yaml };\n}\n\n/**\n * Load an agent by name. Searches project-local first, then home.\n * Throws with clear error if missing or if encrypted secrets lack a passphrase.\n */\nexport async function loadAgent(\n name: string,\n cwd: string,\n passphrase?: string,\n): Promise<LoadedAgent> {\n validateAgentName(name);\n const resolved = resolveAgent(name, cwd);\n if (!resolved) {\n throw new Error(\n `Agent \"${name}\" not found. Looked for .elisym/${name}/elisym.yaml in project (walking up from ${cwd}) and in home (${homeElisymPathHint(name)}).`,\n );\n }\n return loadResolvedAgent(resolved, passphrase);\n}\n\n/** Load an agent whose location was already resolved. */\nexport async function loadResolvedAgent(\n resolved: ResolvedAgent,\n passphrase?: string,\n): Promise<LoadedAgent> {\n const paths = agentPaths(resolved.dir);\n\n const yamlRaw = await readFile(paths.yaml, 'utf-8');\n const parsedYaml = YAML.parse(yamlRaw);\n const yaml = ElisymYamlSchema.parse(parsedYaml ?? {});\n\n let secretsRaw: string;\n try {\n secretsRaw = await readFile(paths.secrets, 'utf-8');\n } catch {\n throw new Error(\n `Agent \"${resolved.name}\" has elisym.yaml but no secrets at ${paths.secrets}. Run \\`npx @elisym/cli init\\` to initialize secrets.`,\n );\n }\n\n const secrets = SecretsSchema.parse(JSON.parse(secretsRaw));\n const encryptedFields = listEncryptedFields(secrets);\n\n const effectivePassphrase = passphrase ?? process.env.ELISYM_PASSPHRASE;\n if (encryptedFields.length > 0 && !effectivePassphrase) {\n throw new Error(\n `Agent \"${resolved.name}\" has encrypted secrets [${encryptedFields.join(', ')}]. Set ELISYM_PASSPHRASE or pass a passphrase.`,\n );\n }\n\n const decrypted: Secrets = { ...secrets };\n if (effectivePassphrase) {\n if (isEncrypted(decrypted.nostr_secret_key)) {\n decrypted.nostr_secret_key = decryptSecret(decrypted.nostr_secret_key, effectivePassphrase);\n }\n if (decrypted.solana_secret_key && isEncrypted(decrypted.solana_secret_key)) {\n decrypted.solana_secret_key = decryptSecret(decrypted.solana_secret_key, effectivePassphrase);\n }\n if (decrypted.llm_api_keys) {\n const decryptedKeys: Record<string, string> = {};\n for (const [providerId, value] of Object.entries(decrypted.llm_api_keys)) {\n decryptedKeys[providerId] = isEncrypted(value)\n ? decryptSecret(value, effectivePassphrase)\n : value;\n }\n decrypted.llm_api_keys = decryptedKeys;\n }\n }\n\n return {\n name: resolved.name,\n dir: resolved.dir,\n source: resolved.source,\n yaml,\n secrets: decrypted,\n encrypted: encryptedFields.length > 0,\n shadowsGlobal: resolved.shadowsGlobal,\n };\n}\n\nfunction listEncryptedFields(secrets: Secrets): string[] {\n const out: string[] = [];\n if (isEncrypted(secrets.nostr_secret_key)) {\n out.push('nostr_secret_key');\n }\n if (secrets.solana_secret_key && isEncrypted(secrets.solana_secret_key)) {\n out.push('solana_secret_key');\n }\n if (secrets.llm_api_keys) {\n for (const [providerId, value] of Object.entries(secrets.llm_api_keys)) {\n if (isEncrypted(value)) {\n out.push(`llm_api_keys.${providerId}`);\n }\n }\n }\n return out;\n}\n\nfunction homeElisymPathHint(name: string): string {\n return `~/.elisym/${name}/elisym.yaml`;\n}\n","/**\n * Render a fresh `elisym.yaml` as a string with descriptive header comments\n * over each top-level field. Optional fields that are not set in the input\n * are emitted as commented-out examples so a new operator can see what else\n * is configurable without leaving the file.\n *\n * Used only at agent-creation time (CLI `init`, MCP `create_agent`). On\n * subsequent writes via `writeYaml`, the document is re-serialized without\n * comments - this template is a one-shot scaffold, not a round-tripping\n * format.\n */\n\nimport YAML from 'yaml';\nimport { RELAYS } from '../constants';\nimport type { ElisymYaml } from './schema';\n\nconst PLACEHOLDER_DISPLAY_NAME = 'My Agent';\nconst PLACEHOLDER_PICTURE = './avatar.png';\nconst PLACEHOLDER_BANNER = './banner.png';\nconst PLACEHOLDER_PAYMENTS = [\n { chain: 'solana', network: 'devnet', address: '<your-solana-address>' },\n];\nconst PLACEHOLDER_LLM = {\n provider: 'anthropic',\n model: 'claude-sonnet-4-6',\n max_tokens: 4096,\n};\nconst DEFAULT_SECURITY = { withdrawals_enabled: false, agent_switch_enabled: false };\n\ninterface FieldBlock {\n description: string;\n key: keyof ElisymYaml;\n value: unknown;\n placeholder: unknown;\n}\n\nfunction commentLines(text: string): string {\n return text\n .split('\\n')\n .map((line) => (line.length > 0 ? `# ${line}` : '#'))\n .join('\\n');\n}\n\nfunction isUnset(value: unknown): boolean {\n if (value === undefined) {\n return true;\n }\n if (Array.isArray(value) && value.length === 0) {\n return true;\n }\n return false;\n}\n\nfunction renderBlock(block: FieldBlock): string {\n const header = commentLines(block.description);\n const unset = isUnset(block.value);\n const renderValue = unset ? block.placeholder : block.value;\n const yamlBody = YAML.stringify({ [block.key]: renderValue }).trimEnd();\n const body = unset ? commentLines(yamlBody) : yamlBody;\n return `${header}\\n${body}`;\n}\n\nexport function renderInitialYaml(yaml: ElisymYaml): string {\n const security = {\n withdrawals_enabled: yaml.security.withdrawals_enabled ?? DEFAULT_SECURITY.withdrawals_enabled,\n agent_switch_enabled:\n yaml.security.agent_switch_enabled ?? DEFAULT_SECURITY.agent_switch_enabled,\n };\n\n const blocks: FieldBlock[] = [\n {\n description: 'Human-readable name shown in UI. Falls back to the folder name when omitted.',\n key: 'display_name',\n value: yaml.display_name,\n placeholder: PLACEHOLDER_DISPLAY_NAME,\n },\n {\n description: 'Public description shown in discovery results.',\n key: 'description',\n value: yaml.description,\n placeholder: '',\n },\n {\n description: 'Avatar - relative path (to this YAML) or absolute URL.',\n key: 'picture',\n value: yaml.picture,\n placeholder: PLACEHOLDER_PICTURE,\n },\n {\n description: 'Banner - relative path (to this YAML) or absolute URL.',\n key: 'banner',\n value: yaml.banner,\n placeholder: PLACEHOLDER_BANNER,\n },\n {\n description: 'Nostr relays this agent connects to.',\n key: 'relays',\n value: yaml.relays,\n placeholder: [...RELAYS],\n },\n {\n description:\n 'Payment wallets per chain. Each entry receives every asset on that chain ' +\n '(SOL directly; SPL tokens via the ATA derived from this address).',\n key: 'payments',\n value: yaml.payments,\n placeholder: PLACEHOLDER_PAYMENTS,\n },\n {\n description:\n 'LLM configuration. Omit (or comment out) to run as a non-LLM agent ' +\n '(static-file or script skills only).',\n key: 'llm',\n value: yaml.llm,\n placeholder: PLACEHOLDER_LLM,\n },\n {\n description: 'Capability gates. Both default to false; flip to true to enable.',\n key: 'security',\n value: security,\n placeholder: DEFAULT_SECURITY,\n },\n ];\n\n return blocks.map(renderBlock).join('\\n\\n') + '\\n';\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\nimport { renderInitialYaml } from './template';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write a brand-new elisym.yaml with descriptive header comments and\n * commented-out examples for unset optional fields. Use only at agent\n * creation time (CLI `init`, MCP `create_agent`). Subsequent edits go\n * through `writeYaml`, which discards comments.\n */\nexport async function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = renderInitialYaml(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * List all agents discoverable from the current working directory:\n * - project-local: nearest .elisym/ (walk up to first .git or $HOME)\n * - home-global: ~/.elisym/\n * Project-local entries shadow home-global entries with the same name.\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport YAML from 'yaml';\nimport { findProjectElisymDir, homeElisymDir, YAML_FILENAME } from './paths';\nimport type { AgentSource } from './resolver';\nimport { ElisymYamlSchema } from './schema';\n\nexport interface ListedAgent {\n name: string;\n source: AgentSource;\n dir: string;\n /** display_name from YAML, if present. */\n displayName?: string;\n /** true when this entry is project-local and a home-global agent with the same name exists. */\n shadowsGlobal: boolean;\n}\n\n/** List agents in both locations, deduping by name (project wins). */\nexport async function listAgents(cwd: string): Promise<ListedAgent[]> {\n const homeDir = homeElisymDir();\n const projectDir = findProjectElisymDir(cwd);\n\n const homeAgents = await listAgentsInDir(homeDir, 'home');\n const projectAgents = projectDir ? await listAgentsInDir(projectDir, 'project') : [];\n\n const homeNames = new Set(homeAgents.map((agent) => agent.name));\n\n const merged: ListedAgent[] = [];\n\n for (const entry of projectAgents) {\n merged.push({ ...entry, shadowsGlobal: homeNames.has(entry.name) });\n }\n const projectNames = new Set(projectAgents.map((agent) => agent.name));\n for (const entry of homeAgents) {\n if (!projectNames.has(entry.name)) {\n merged.push(entry);\n }\n }\n\n merged.sort((left, right) => left.name.localeCompare(right.name));\n return merged;\n}\n\nasync function listAgentsInDir(rootDir: string, source: AgentSource): Promise<ListedAgent[]> {\n let entries: string[];\n try {\n entries = await readdir(rootDir);\n } catch {\n return [];\n }\n\n const results: ListedAgent[] = [];\n for (const entry of entries) {\n if (entry.startsWith('.')) {\n continue;\n }\n const agentDir = join(rootDir, entry);\n const yamlPath = join(agentDir, YAML_FILENAME);\n const displayName = await tryReadDisplayName(yamlPath);\n if (displayName === null) {\n continue;\n }\n results.push({\n name: entry,\n source,\n dir: agentDir,\n displayName: displayName || undefined,\n shadowsGlobal: false,\n });\n }\n\n return results;\n}\n\n/**\n * Read display_name from a YAML file. Returns null if the file is missing\n * or cannot be parsed (agent directory is skipped in listings).\n */\nasync function tryReadDisplayName(yamlPath: string): Promise<string | null> {\n let raw: string;\n try {\n raw = await readFile(yamlPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n const parsed = YAML.parse(raw);\n const yaml = ElisymYamlSchema.partial().safeParse(parsed ?? {});\n if (!yaml.success) {\n return '';\n }\n return yaml.data.display_name ?? '';\n } catch {\n return '';\n }\n}\n","/**\n * Media cache: maps local image paths to uploaded URLs + sha256.\n * On each start, the CLI hashes the file and skips re-upload if the hash matches.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { agentPaths } from './paths';\nimport { MediaCacheSchema, type MediaCache, type MediaCacheEntry } from './schema';\nimport { writeFileAtomic } from './writer';\n\n/** Read .media-cache.json. Returns empty object if missing or corrupt. */\nexport async function readMediaCache(agentDir: string): Promise<MediaCache> {\n const path = agentPaths(agentDir).mediaCache;\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return {};\n }\n try {\n const parsed = JSON.parse(raw);\n const result = MediaCacheSchema.safeParse(parsed);\n return result.success ? result.data : {};\n } catch {\n return {};\n }\n}\n\nexport async function writeMediaCache(agentDir: string, cache: MediaCache): Promise<void> {\n const path = agentPaths(agentDir).mediaCache;\n const body = JSON.stringify(cache, null, 2) + '\\n';\n await writeFileAtomic(path, body, 0o600);\n}\n\n/** Compute sha256 hex of a file's contents. */\nexport async function hashFile(filePath: string): Promise<string> {\n const buf = await readFile(filePath);\n return createHash('sha256').update(buf).digest('hex');\n}\n\n/**\n * Look up a cached URL for a local file path. Returns the cached URL if\n * the file's current hash matches the cache entry; otherwise null.\n */\nexport async function lookupCachedUrl(\n cache: MediaCache,\n relativePath: string,\n absolutePath: string,\n): Promise<string | null> {\n const entry = cache[relativePath];\n if (!entry) {\n return null;\n }\n let hash: string;\n try {\n hash = await hashFile(absolutePath);\n } catch {\n return null;\n }\n return hash === entry.sha256 ? entry.url : null;\n}\n\nexport function newCacheEntry(url: string, sha256: string): MediaCacheEntry {\n return { url, sha256, uploaded_at: new Date().toISOString() };\n}\n"]}
|
package/dist/node.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/primitives/encryption.ts","../src/agent-store/writer.ts","../src/config/global-schema.ts","../src/config/global.ts"],"names":["randomBytes","scryptSync","createCipheriv","Buffer","createDecipheriv","path","mkdir","dirname","writeFile","rename","z","readFile","YAML"],"mappings":"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","file":"node.cjs","sourcesContent":["/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * Zod schemas and types for `~/.elisym/config.yaml`.\n *\n * Split from `./global` so the schemas can be re-exported from the\n * browser-safe `@elisym/sdk` entry point without dragging in `node:fs/promises`\n * (which the loader/writer in `./global` needs).\n */\n\nimport { z } from 'zod';\n\nexport const SessionSpendLimitEntrySchema = z\n .object({\n chain: z.enum(['solana']),\n token: z\n .string()\n .min(1)\n .max(16)\n .regex(/^[a-z0-9]+$/, 'token must be lowercase alphanumeric'),\n mint: z.string().min(1).max(64).optional(),\n amount: z.number().positive().finite(),\n })\n .strict();\n\nexport const GlobalConfigSchema = z\n .object({\n session_spend_limits: z.array(SessionSpendLimitEntrySchema).max(16).optional(),\n })\n .strict();\n\nexport type SessionSpendLimitEntry = z.infer<typeof SessionSpendLimitEntrySchema>;\nexport type GlobalConfig = z.infer<typeof GlobalConfigSchema>;\n","/**\n * Global (not per-agent) config stored at `~/.elisym/config.yaml`.\n *\n * Node.js/Bun only - reads and writes the filesystem. Browser code must not\n * import this module; import the schemas from `./global-schema` instead, or\n * the loader/writer from `@elisym/sdk/node`.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { writeFileAtomic } from '../agent-store/writer';\nimport { GlobalConfigSchema, type GlobalConfig } from './global-schema';\n\nexport {\n GlobalConfigSchema,\n SessionSpendLimitEntrySchema,\n type GlobalConfig,\n type SessionSpendLimitEntry,\n} from './global-schema';\n\nfunction isEnoent(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'ENOENT'\n );\n}\n\n/**\n * Read and validate `~/.elisym/config.yaml`. Returns `{}` if missing. Throws\n * on malformed YAML or schema violations — the MCP server treats these as fatal\n * at startup rather than silently ignoring bad overrides.\n */\nexport async function loadGlobalConfig(path: string): Promise<GlobalConfig> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (e) {\n if (isEnoent(e)) {\n return {};\n }\n throw e;\n }\n if (raw.trim() === '') {\n return {};\n }\n const parsed: unknown = YAML.parse(raw);\n return GlobalConfigSchema.parse(parsed ?? {});\n}\n\n/** Write the config YAML atomically. Validates via Zod before writing. */\nexport async function writeGlobalConfig(path: string, config: GlobalConfig): Promise<void> {\n const validated = GlobalConfigSchema.parse(config);\n const body = YAML.stringify(validated);\n await writeFileAtomic(path, body, 0o644);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/primitives/encryption.ts","../src/agent-store/writer.ts","../src/config/global-schema.ts","../src/config/global.ts"],"names":["randomBytes","scryptSync","createCipheriv","Buffer","createDecipheriv","path","mkdir","dirname","writeFile","rename","z","readFile","YAML"],"mappings":"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","file":"node.cjs","sourcesContent":["/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\nimport { renderInitialYaml } from './template';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write a brand-new elisym.yaml with descriptive header comments and\n * commented-out examples for unset optional fields. Use only at agent\n * creation time (CLI `init`, MCP `create_agent`). Subsequent edits go\n * through `writeYaml`, which discards comments.\n */\nexport async function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = renderInitialYaml(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * Zod schemas and types for `~/.elisym/config.yaml`.\n *\n * Split from `./global` so the schemas can be re-exported from the\n * browser-safe `@elisym/sdk` entry point without dragging in `node:fs/promises`\n * (which the loader/writer in `./global` needs).\n */\n\nimport { z } from 'zod';\n\nexport const SessionSpendLimitEntrySchema = z\n .object({\n chain: z.enum(['solana']),\n token: z\n .string()\n .min(1)\n .max(16)\n .regex(/^[a-z0-9]+$/, 'token must be lowercase alphanumeric'),\n mint: z.string().min(1).max(64).optional(),\n amount: z.number().positive().finite(),\n })\n .strict();\n\nexport const GlobalConfigSchema = z\n .object({\n session_spend_limits: z.array(SessionSpendLimitEntrySchema).max(16).optional(),\n })\n .strict();\n\nexport type SessionSpendLimitEntry = z.infer<typeof SessionSpendLimitEntrySchema>;\nexport type GlobalConfig = z.infer<typeof GlobalConfigSchema>;\n","/**\n * Global (not per-agent) config stored at `~/.elisym/config.yaml`.\n *\n * Node.js/Bun only - reads and writes the filesystem. Browser code must not\n * import this module; import the schemas from `./global-schema` instead, or\n * the loader/writer from `@elisym/sdk/node`.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { writeFileAtomic } from '../agent-store/writer';\nimport { GlobalConfigSchema, type GlobalConfig } from './global-schema';\n\nexport {\n GlobalConfigSchema,\n SessionSpendLimitEntrySchema,\n type GlobalConfig,\n type SessionSpendLimitEntry,\n} from './global-schema';\n\nfunction isEnoent(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'ENOENT'\n );\n}\n\n/**\n * Read and validate `~/.elisym/config.yaml`. Returns `{}` if missing. Throws\n * on malformed YAML or schema violations — the MCP server treats these as fatal\n * at startup rather than silently ignoring bad overrides.\n */\nexport async function loadGlobalConfig(path: string): Promise<GlobalConfig> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (e) {\n if (isEnoent(e)) {\n return {};\n }\n throw e;\n }\n if (raw.trim() === '') {\n return {};\n }\n const parsed: unknown = YAML.parse(raw);\n return GlobalConfigSchema.parse(parsed ?? {});\n}\n\n/** Write the config YAML atomically. Validates via Zod before writing. */\nexport async function writeGlobalConfig(path: string, config: GlobalConfig): Promise<void> {\n const validated = GlobalConfigSchema.parse(config);\n const body = YAML.stringify(validated);\n await writeFileAtomic(path, body, 0o644);\n}\n"]}
|
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/primitives/encryption.ts","../src/agent-store/writer.ts","../src/config/global-schema.ts","../src/config/global.ts"],"names":["randomBytes","YAML"],"mappings":"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","file":"node.js","sourcesContent":["/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * Zod schemas and types for `~/.elisym/config.yaml`.\n *\n * Split from `./global` so the schemas can be re-exported from the\n * browser-safe `@elisym/sdk` entry point without dragging in `node:fs/promises`\n * (which the loader/writer in `./global` needs).\n */\n\nimport { z } from 'zod';\n\nexport const SessionSpendLimitEntrySchema = z\n .object({\n chain: z.enum(['solana']),\n token: z\n .string()\n .min(1)\n .max(16)\n .regex(/^[a-z0-9]+$/, 'token must be lowercase alphanumeric'),\n mint: z.string().min(1).max(64).optional(),\n amount: z.number().positive().finite(),\n })\n .strict();\n\nexport const GlobalConfigSchema = z\n .object({\n session_spend_limits: z.array(SessionSpendLimitEntrySchema).max(16).optional(),\n })\n .strict();\n\nexport type SessionSpendLimitEntry = z.infer<typeof SessionSpendLimitEntrySchema>;\nexport type GlobalConfig = z.infer<typeof GlobalConfigSchema>;\n","/**\n * Global (not per-agent) config stored at `~/.elisym/config.yaml`.\n *\n * Node.js/Bun only - reads and writes the filesystem. Browser code must not\n * import this module; import the schemas from `./global-schema` instead, or\n * the loader/writer from `@elisym/sdk/node`.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { writeFileAtomic } from '../agent-store/writer';\nimport { GlobalConfigSchema, type GlobalConfig } from './global-schema';\n\nexport {\n GlobalConfigSchema,\n SessionSpendLimitEntrySchema,\n type GlobalConfig,\n type SessionSpendLimitEntry,\n} from './global-schema';\n\nfunction isEnoent(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'ENOENT'\n );\n}\n\n/**\n * Read and validate `~/.elisym/config.yaml`. Returns `{}` if missing. Throws\n * on malformed YAML or schema violations — the MCP server treats these as fatal\n * at startup rather than silently ignoring bad overrides.\n */\nexport async function loadGlobalConfig(path: string): Promise<GlobalConfig> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (e) {\n if (isEnoent(e)) {\n return {};\n }\n throw e;\n }\n if (raw.trim() === '') {\n return {};\n }\n const parsed: unknown = YAML.parse(raw);\n return GlobalConfigSchema.parse(parsed ?? {});\n}\n\n/** Write the config YAML atomically. Validates via Zod before writing. */\nexport async function writeGlobalConfig(path: string, config: GlobalConfig): Promise<void> {\n const validated = GlobalConfigSchema.parse(config);\n const body = YAML.stringify(validated);\n await writeFileAtomic(path, body, 0o644);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/primitives/encryption.ts","../src/agent-store/writer.ts","../src/config/global-schema.ts","../src/config/global.ts"],"names":["randomBytes","YAML"],"mappings":"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","file":"node.js","sourcesContent":["/**\n * Secret encryption/decryption for agent config files.\n * Uses scrypt (KDF) + AES-256-GCM (cipher).\n * Format: \"encrypted:v1:\" + base64(salt[16] + iv[12] + ciphertext + tag[16])\n *\n * scrypt params: N=2^17, r=8, p=1 (~128 MB RAM per derivation).\n *\n * Node.js/Bun only - not available in browsers. Reachable only via the\n * '@elisym/sdk/node' subpath, which browser bundlers will not resolve.\n */\n\nimport { Buffer } from 'node:buffer';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst PREFIX = 'encrypted:v1:';\nconst SALT_LENGTH = 16;\nconst IV_LENGTH = 12;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32; // AES-256\n// v1: N=2^17 (OWASP minimum). v2 will use N=2^20 with format migration.\nconst SCRYPT_N = 2 ** 17;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 128 * SCRYPT_N * SCRYPT_R * 2; // 2x the minimum required memory\n\n/** Check if a value is encrypted (has the encrypted:v1: prefix). */\nexport function isEncrypted(value: string): boolean {\n return value.startsWith(PREFIX);\n}\n\n/** Encrypt a plaintext secret with a passphrase. Returns \"encrypted:v1:base64...\". Node.js/Bun only. */\nexport function encryptSecret(plaintext: string, passphrase: string): string {\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const salt = randomBytes(SALT_LENGTH);\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n const payload = Buffer.concat([salt, iv, encrypted, tag]);\n return PREFIX + payload.toString('base64');\n}\n\n/** Decrypt an encrypted secret with a passphrase. Throws on wrong passphrase or corrupted data. Node.js/Bun only. */\nexport function decryptSecret(encrypted: string, passphrase: string): string {\n if (!isEncrypted(encrypted)) {\n throw new Error('Value is not encrypted (missing encrypted:v1: prefix).');\n }\n if (!passphrase) {\n throw new Error('Passphrase must not be empty.');\n }\n\n const payload = Buffer.from(encrypted.slice(PREFIX.length), 'base64');\n if (payload.length < SALT_LENGTH + IV_LENGTH + TAG_LENGTH) {\n throw new Error('Encrypted payload is too short.');\n }\n\n const salt = payload.subarray(0, SALT_LENGTH);\n const iv = payload.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const tag = payload.subarray(payload.length - TAG_LENGTH);\n const ciphertext = payload.subarray(SALT_LENGTH + IV_LENGTH, payload.length - TAG_LENGTH);\n\n const key = scryptSync(passphrase, salt, KEY_LENGTH, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n\n try {\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed. Wrong passphrase or corrupted data.');\n }\n}\n","/**\n * Write agent files: elisym.yaml, .secrets.json, .gitignore, and create agent dirs.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport YAML from 'yaml';\nimport { encryptSecret, isEncrypted } from '../primitives/encryption';\nimport { agentPaths, type AgentPaths } from './paths';\nimport { elisymRootFor, type AgentSource } from './resolver';\nimport { ElisymYamlSchema, SecretsSchema, type ElisymYaml, type Secrets } from './schema';\nimport { renderInitialYaml } from './template';\n\nconst GITIGNORE_CONTENT = [\n '# elisym private state - do not commit.',\n '.secrets.json',\n '.media-cache.json',\n '.jobs.json',\n '.jobs.json.corrupt.*',\n '.customer-history.json',\n '.contacts.json',\n '',\n].join('\\n');\n\nexport interface CreateAgentDirOptions {\n target: AgentSource;\n name: string;\n cwd: string;\n /**\n * For `target: 'project'`: if no .elisym/ dir exists above cwd,\n * where should we create one? Defaults to cwd.\n */\n projectRoot?: string;\n}\n\nexport interface CreatedAgentDir {\n dir: string;\n paths: AgentPaths;\n source: AgentSource;\n createdNewElisymRoot: boolean;\n}\n\n/**\n * Create (or reuse) the directory layout for a new agent. Idempotent: if the\n * agent directory already exists, returns its paths without overwriting.\n * Writes `.gitignore` in project-local .elisym/ on first creation.\n */\nexport async function createAgentDir(options: CreateAgentDirOptions): Promise<CreatedAgentDir> {\n const { target, name, cwd, projectRoot } = options;\n\n const existingRoot = elisymRootFor(target, cwd);\n let elisymRoot: string;\n let createdNewElisymRoot = false;\n\n if (existingRoot) {\n elisymRoot = existingRoot;\n } else if (target === 'project') {\n elisymRoot = join(projectRoot ?? cwd, '.elisym');\n createdNewElisymRoot = true;\n } else {\n throw new Error('homeElisymDir should always exist conceptually - this is unreachable');\n }\n\n const agentDir = join(elisymRoot, name);\n const mode = target === 'home' ? 0o700 : 0o755;\n await mkdir(agentDir, { recursive: true, mode });\n await mkdir(join(agentDir, 'skills'), { recursive: true, mode });\n\n if (target === 'project') {\n const gitignorePath = join(elisymRoot, '.gitignore');\n await writeFileIfMissing(gitignorePath, GITIGNORE_CONTENT, 0o644);\n }\n\n return {\n dir: agentDir,\n paths: agentPaths(agentDir),\n source: target,\n createdNewElisymRoot,\n };\n}\n\n/** Write elisym.yaml atomically. Validates via Zod before writing. */\nexport async function writeYaml(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = YAML.stringify(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write a brand-new elisym.yaml with descriptive header comments and\n * commented-out examples for unset optional fields. Use only at agent\n * creation time (CLI `init`, MCP `create_agent`). Subsequent edits go\n * through `writeYaml`, which discards comments.\n */\nexport async function writeYamlInitial(agentDir: string, yaml: ElisymYaml): Promise<void> {\n const validated = ElisymYamlSchema.parse(yaml);\n const body = renderInitialYaml(validated);\n const target = agentPaths(agentDir).yaml;\n await writeFileAtomic(target, body, 0o644);\n}\n\n/**\n * Write .secrets.json atomically. If `passphrase` is given, encrypts all\n * plaintext secret fields (already-encrypted values are left as-is).\n * Generic over `llm_api_keys` so any registered provider's key is\n * encrypted without per-provider plumbing here.\n */\nexport async function writeSecrets(\n agentDir: string,\n secrets: Secrets,\n passphrase?: string,\n): Promise<void> {\n const validated = SecretsSchema.parse(secrets);\n let encryptedLlmKeys: Record<string, string> | undefined;\n if (validated.llm_api_keys) {\n encryptedLlmKeys = {};\n for (const [providerId, value] of Object.entries(validated.llm_api_keys)) {\n if (value) {\n encryptedLlmKeys[providerId] = maybeEncrypt(value, passphrase);\n }\n }\n if (Object.keys(encryptedLlmKeys).length === 0) {\n encryptedLlmKeys = undefined;\n }\n }\n const finalSecrets: Secrets = {\n nostr_secret_key: maybeEncrypt(validated.nostr_secret_key, passphrase),\n solana_secret_key: validated.solana_secret_key\n ? maybeEncrypt(validated.solana_secret_key, passphrase)\n : undefined,\n llm_api_keys: encryptedLlmKeys,\n };\n const body = JSON.stringify(finalSecrets, null, 2) + '\\n';\n const target = agentPaths(agentDir).secrets;\n await writeFileAtomic(target, body, 0o600);\n}\n\nfunction maybeEncrypt(value: string, passphrase: string | undefined): string {\n if (!passphrase) {\n return value;\n }\n if (isEncrypted(value)) {\n return value;\n }\n return encryptSecret(value, passphrase);\n}\n\n/** Atomic write: temp file + rename. Preserves mode. */\nexport async function writeFileAtomic(\n path: string,\n data: string | Buffer,\n mode: number,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.tmp.${randomBytes(6).toString('hex')}`;\n await writeFile(tmpPath, data, { mode });\n try {\n await rename(tmpPath, path);\n } catch (e) {\n // Best-effort cleanup of temp file on rename failure.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(tmpPath);\n } catch {\n /* ignore */\n }\n throw e;\n }\n}\n\nasync function writeFileIfMissing(path: string, data: string, mode: number): Promise<void> {\n try {\n await writeFile(path, data, { mode, flag: 'wx' });\n } catch (e: unknown) {\n // wx fails with EEXIST if file exists - that's fine.\n if (!isEexist(e)) {\n throw e;\n }\n }\n}\n\nfunction isEexist(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'EEXIST'\n );\n}\n","/**\n * Zod schemas and types for `~/.elisym/config.yaml`.\n *\n * Split from `./global` so the schemas can be re-exported from the\n * browser-safe `@elisym/sdk` entry point without dragging in `node:fs/promises`\n * (which the loader/writer in `./global` needs).\n */\n\nimport { z } from 'zod';\n\nexport const SessionSpendLimitEntrySchema = z\n .object({\n chain: z.enum(['solana']),\n token: z\n .string()\n .min(1)\n .max(16)\n .regex(/^[a-z0-9]+$/, 'token must be lowercase alphanumeric'),\n mint: z.string().min(1).max(64).optional(),\n amount: z.number().positive().finite(),\n })\n .strict();\n\nexport const GlobalConfigSchema = z\n .object({\n session_spend_limits: z.array(SessionSpendLimitEntrySchema).max(16).optional(),\n })\n .strict();\n\nexport type SessionSpendLimitEntry = z.infer<typeof SessionSpendLimitEntrySchema>;\nexport type GlobalConfig = z.infer<typeof GlobalConfigSchema>;\n","/**\n * Global (not per-agent) config stored at `~/.elisym/config.yaml`.\n *\n * Node.js/Bun only - reads and writes the filesystem. Browser code must not\n * import this module; import the schemas from `./global-schema` instead, or\n * the loader/writer from `@elisym/sdk/node`.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport YAML from 'yaml';\nimport { writeFileAtomic } from '../agent-store/writer';\nimport { GlobalConfigSchema, type GlobalConfig } from './global-schema';\n\nexport {\n GlobalConfigSchema,\n SessionSpendLimitEntrySchema,\n type GlobalConfig,\n type SessionSpendLimitEntry,\n} from './global-schema';\n\nfunction isEnoent(e: unknown): boolean {\n return (\n typeof e === 'object' && e !== null && 'code' in e && (e as { code: string }).code === 'ENOENT'\n );\n}\n\n/**\n * Read and validate `~/.elisym/config.yaml`. Returns `{}` if missing. Throws\n * on malformed YAML or schema violations — the MCP server treats these as fatal\n * at startup rather than silently ignoring bad overrides.\n */\nexport async function loadGlobalConfig(path: string): Promise<GlobalConfig> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (e) {\n if (isEnoent(e)) {\n return {};\n }\n throw e;\n }\n if (raw.trim() === '') {\n return {};\n }\n const parsed: unknown = YAML.parse(raw);\n return GlobalConfigSchema.parse(parsed ?? {});\n}\n\n/** Write the config YAML atomically. Validates via Zod before writing. */\nexport async function writeGlobalConfig(path: string, config: GlobalConfig): Promise<void> {\n const validated = GlobalConfigSchema.parse(config);\n const body = YAML.stringify(validated);\n await writeFileAtomic(path, body, 0o644);\n}\n"]}
|