@agentskit/cli 0.11.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createCli } from './chunk-7SBFFCM7.js';
2
+ import { createCli } from './chunk-X4PVLZSO.js';
3
3
 
4
4
  // src/bin.ts
5
5
  async function main() {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { readdir, stat, mkdir, writeFile, glob, readFile } from 'fs/promises';
3
3
  import { homedir } from 'os';
4
- import path, { join, resolve, isAbsolute, basename } from 'path';
4
+ import path, { join, resolve, isAbsolute, basename, dirname } from 'path';
5
5
  import { kimi, grok, deepseek, ollama, gemini, anthropic, openai } from '@agentskit/adapters';
6
6
  import { randomBytes, createHash } from 'crypto';
7
7
  import { writeFileSync, existsSync, readdirSync, statSync, readFileSync, mkdirSync } from 'fs';
@@ -12,6 +12,7 @@ import { useChat, StatusHeader, ChatContainer, Message, ToolCallView, ToolConfir
12
12
  import { shell, filesystem, fetchUrl, webSearch } from '@agentskit/tools';
13
13
  import { summarizer, critic, planner, coder, researcher, composeSkills } from '@agentskit/skills';
14
14
  import { fileVectorMemory, fileChatMemory, sqliteChatMemory } from '@agentskit/memory';
15
+ import { getIntegration, integrationToolsFromEnv } from '@agentskit/integrations';
15
16
  import { jsxs, jsx } from 'react/jsx-runtime';
16
17
  import { pathToFileURL } from 'url';
17
18
  import { createRuntime, validateFlow, flowToMermaid, compileFlow, createFileStepLog } from '@agentskit/runtime';
@@ -22,6 +23,8 @@ import { Command } from 'commander';
22
23
  import { input, select, checkbox, confirm } from '@inquirer/prompts';
23
24
  import { validateAgentSchema } from '@agentskit/core/agent-schema';
24
25
  import { parse } from 'yaml';
26
+ import { validatePIITaxonomy } from '@agentskit/core/security';
27
+ import { ConfigError, ErrorCodes } from '@agentskit/core';
25
28
 
26
29
  async function loadJsonConfig(path5) {
27
30
  try {
@@ -143,7 +146,7 @@ function createDemoAdapter(provider, model) {
143
146
  ].join(" ");
144
147
  for (const chunk of reply.match(/.{1,18}/g) ?? []) {
145
148
  if (cancelled) return;
146
- await new Promise((resolve4) => setTimeout(resolve4, 35));
149
+ await new Promise((resolve6) => setTimeout(resolve6, 35));
147
150
  yield { type: "text", content: chunk };
148
151
  }
149
152
  yield { type: "done" };
@@ -464,20 +467,39 @@ function configHooksToHandlers(config) {
464
467
  function runShellHook(entry, payload) {
465
468
  return new Promise((resolvePromise) => {
466
469
  const timeoutMs = entry.timeout ?? 5e3;
470
+ let settled = false;
471
+ const settle = (result) => {
472
+ if (settled) return;
473
+ settled = true;
474
+ clearTimeout(timer);
475
+ resolvePromise(result);
476
+ };
467
477
  const child = spawn("sh", ["-c", entry.run], {
468
- stdio: ["pipe", "pipe", "inherit"]
478
+ stdio: ["pipe", "pipe", "inherit"],
479
+ detached: true
469
480
  });
470
481
  let stdout = "";
471
482
  child.stdout.on("data", (chunk) => {
472
483
  stdout += chunk.toString();
473
484
  });
474
485
  const timer = setTimeout(() => {
475
- child.kill("SIGTERM");
486
+ if (child.pid !== void 0) {
487
+ try {
488
+ process.kill(-child.pid, "SIGKILL");
489
+ } catch {
490
+ }
491
+ }
492
+ try {
493
+ child.kill("SIGKILL");
494
+ } catch {
495
+ }
496
+ settle({ decision: "block", reason: `shell hook timed out after ${timeoutMs}ms` });
476
497
  }, timeoutMs);
498
+ child.stdin.on("error", () => {
499
+ });
477
500
  child.on("close", (code) => {
478
- clearTimeout(timer);
479
501
  if (code !== 0) {
480
- resolvePromise({
502
+ settle({
481
503
  decision: "block",
482
504
  reason: `shell hook exited with code ${code}`
483
505
  });
@@ -485,19 +507,18 @@ function runShellHook(entry, payload) {
485
507
  }
486
508
  const trimmed = stdout.trim();
487
509
  if (!trimmed) {
488
- resolvePromise({ decision: "continue" });
510
+ settle({ decision: "continue" });
489
511
  return;
490
512
  }
491
513
  try {
492
514
  const parsed = JSON.parse(trimmed);
493
- resolvePromise(parsed);
515
+ settle(parsed);
494
516
  } catch {
495
- resolvePromise({ decision: "continue" });
517
+ settle({ decision: "continue" });
496
518
  }
497
519
  });
498
520
  child.on("error", (err) => {
499
- clearTimeout(timer);
500
- resolvePromise({ decision: "block", reason: err.message });
521
+ settle({ decision: "block", reason: err.message });
501
522
  });
502
523
  try {
503
524
  child.stdin.write(JSON.stringify(payload));
@@ -737,7 +758,7 @@ function instantiate(kind) {
737
758
  case "filesystem":
738
759
  return filesystem({ basePath: process.cwd() });
739
760
  case "shell":
740
- return [shell({ timeout: 3e4 })];
761
+ return [shell({ timeout: 3e4, allowAny: true })];
741
762
  }
742
763
  }
743
764
  function gateTool(tool) {
@@ -757,9 +778,19 @@ function resolveTools(toolNames) {
757
778
  case "shell":
758
779
  tools.push(...instantiate(name));
759
780
  break;
760
- default:
761
- process.stderr.write(`Unknown tool: ${name}
781
+ default: {
782
+ if (getIntegration(name)) {
783
+ const { tools: projected, credentialFound, envVar } = integrationToolsFromEnv(name, process.env);
784
+ if (!credentialFound) {
785
+ process.stderr.write(`Integration "${name}" needs ${envVar} set in the environment.
786
+ `);
787
+ }
788
+ tools.push(...projected);
789
+ } else {
790
+ process.stderr.write(`Unknown tool: ${name}
762
791
  `);
792
+ }
793
+ }
763
794
  }
764
795
  }
765
796
  return tools;
@@ -3813,13 +3844,6 @@ function registerConfigCommand(program) {
3813
3844
  `);
3814
3845
  process.exit(2);
3815
3846
  }
3816
- if (existsSync(targetPath) && !options.force) {
3817
- process.stderr.write(
3818
- `Config already exists at ${targetPath}. Re-run with --force to overwrite.
3819
- `
3820
- );
3821
- process.exit(1);
3822
- }
3823
3847
  const template = {
3824
3848
  defaults: {
3825
3849
  provider: "openai",
@@ -3830,7 +3854,20 @@ function registerConfigCommand(program) {
3830
3854
  }
3831
3855
  };
3832
3856
  mkdirSync(path.dirname(targetPath), { recursive: true });
3833
- writeFileSync(targetPath, JSON.stringify(template, null, 2) + "\n");
3857
+ try {
3858
+ writeFileSync(targetPath, JSON.stringify(template, null, 2) + "\n", {
3859
+ flag: options.force ? "w" : "wx"
3860
+ });
3861
+ } catch (err) {
3862
+ if (err.code === "EEXIST") {
3863
+ process.stderr.write(
3864
+ `Config already exists at ${targetPath}. Re-run with --force to overwrite.
3865
+ `
3866
+ );
3867
+ process.exit(1);
3868
+ }
3869
+ throw err;
3870
+ }
3834
3871
  process.stdout.write(
3835
3872
  `Wrote ${targetPath}
3836
3873
  Edit it to taste, then run:
@@ -3993,12 +4030,12 @@ function scaffoldAgent(schema) {
3993
4030
  return files;
3994
4031
  }
3995
4032
  async function writeScaffold(files, outDir, opts = {}) {
3996
- const { writeFile: writeFile2, mkdir: mkdir2, access } = await import('fs/promises');
3997
- const { dirname, join: join5 } = await import('path');
4033
+ const { writeFile: writeFile3, mkdir: mkdir3, access } = await import('fs/promises');
4034
+ const { dirname: dirname2, join: join6 } = await import('path');
3998
4035
  const written = [];
3999
4036
  for (const f of files) {
4000
- const full = join5(outDir, f.path);
4001
- await mkdir2(dirname(full), { recursive: true });
4037
+ const full = join6(outDir, f.path);
4038
+ await mkdir3(dirname2(full), { recursive: true });
4002
4039
  if (!opts.overwrite) {
4003
4040
  try {
4004
4041
  await access(full);
@@ -4006,7 +4043,7 @@ async function writeScaffold(files, outDir, opts = {}) {
4006
4043
  } catch {
4007
4044
  }
4008
4045
  }
4009
- await writeFile2(full, f.content, "utf8");
4046
+ await writeFile3(full, f.content, "utf8");
4010
4047
  written.push(f.path);
4011
4048
  }
4012
4049
  return written;
@@ -4159,6 +4196,469 @@ function registerFlowCommand(program) {
4159
4196
  }
4160
4197
  });
4161
4198
  }
4199
+ function lintTaxonomyFile(filePath) {
4200
+ const absolute = resolve(filePath);
4201
+ let raw;
4202
+ try {
4203
+ raw = readFileSync(absolute, "utf8");
4204
+ } catch (err) {
4205
+ return {
4206
+ file: absolute,
4207
+ ruleCount: 0,
4208
+ result: {
4209
+ ok: false,
4210
+ issues: [{ index: -1, path: "", message: `cannot read file: ${err.message}` }]
4211
+ }
4212
+ };
4213
+ }
4214
+ let parsed;
4215
+ try {
4216
+ parsed = JSON.parse(raw);
4217
+ } catch (err) {
4218
+ return {
4219
+ file: absolute,
4220
+ ruleCount: 0,
4221
+ result: {
4222
+ ok: false,
4223
+ issues: [{ index: -1, path: "", message: `invalid JSON: ${err.message}` }]
4224
+ }
4225
+ };
4226
+ }
4227
+ const result = validatePIITaxonomy(parsed);
4228
+ const ruleCount = parsed && typeof parsed === "object" && Array.isArray(parsed.rules) ? parsed.rules.length : 0;
4229
+ return { file: absolute, result, ruleCount };
4230
+ }
4231
+ function renderLintReport(report, opts = {}) {
4232
+ const { color = false } = opts;
4233
+ const red = (s) => color ? `\x1B[31m${s}\x1B[0m` : s;
4234
+ const green = (s) => color ? `\x1B[32m${s}\x1B[0m` : s;
4235
+ const dim = (s) => color ? `\x1B[2m${s}\x1B[0m` : s;
4236
+ const lines = [];
4237
+ lines.push(dim(report.file));
4238
+ if (report.result.ok) {
4239
+ lines.push(green(`\u2713 valid \xB7 ${report.ruleCount} rule${report.ruleCount === 1 ? "" : "s"}`));
4240
+ } else {
4241
+ lines.push(red(`\u2717 ${report.result.issues.length} issue${report.result.issues.length === 1 ? "" : "s"}`));
4242
+ for (const issue of report.result.issues) {
4243
+ lines.push(` ${red("\u2022")} ${issue.path || "<root>"}: ${issue.message}`);
4244
+ }
4245
+ }
4246
+ return `${lines.join("\n")}
4247
+ `;
4248
+ }
4249
+
4250
+ // src/commands/pii.ts
4251
+ function registerPiiCommand(program) {
4252
+ const pii = program.command("pii").description("Inspect and validate PII taxonomies.");
4253
+ pii.command("lint <file...>").description("Validate one or more PII taxonomy JSON files.").option("--json", "Emit JSON instead of formatted output").action((files, options) => {
4254
+ const reports = files.map(lintTaxonomyFile);
4255
+ const failed = reports.filter((r) => !r.result.ok).length;
4256
+ if (options.json) {
4257
+ process.stdout.write(JSON.stringify(reports, null, 2) + "\n");
4258
+ } else {
4259
+ for (const report of reports) {
4260
+ process.stdout.write(renderLintReport(report, { color: process.stdout.isTTY }));
4261
+ }
4262
+ if (failed > 0) {
4263
+ process.stderr.write(`
4264
+ ${failed} of ${reports.length} taxonomy file${reports.length === 1 ? "" : "s"} failed validation
4265
+ `);
4266
+ }
4267
+ }
4268
+ if (failed > 0) process.exit(1);
4269
+ });
4270
+ }
4271
+
4272
+ // src/rules/cursor.ts
4273
+ var CURSOR_RULE = `---
4274
+ description: AgentsKit conventions \u2014 apply to every file in this workspace
4275
+ globs: ["**/*.ts", "**/*.tsx"]
4276
+ alwaysApply: true
4277
+ ---
4278
+
4279
+ # AgentsKit project rules
4280
+
4281
+ When writing or editing TypeScript in this workspace, follow these rules. They
4282
+ are non-negotiable and enforced by CI.
4283
+
4284
+ ## Imports
4285
+
4286
+ - Use **named exports only**. No \`export default\`.
4287
+ - Import from package roots: \`@agentskit/core\`, \`@agentskit/runtime\`, \`@agentskit/react\`,
4288
+ \`@agentskit/ink\`, \`@agentskit/adapters\`, \`@agentskit/tools\`, \`@agentskit/skills\`,
4289
+ \`@agentskit/memory\`, \`@agentskit/rag\`, \`@agentskit/observability\`, \`@agentskit/eval\`,
4290
+ \`@agentskit/sandbox\`, \`@agentskit/cli\`, \`@agentskit/templates\`.
4291
+ - For tools subpaths, use \`@agentskit/tools/integrations\`, \`@agentskit/tools/mcp\`,
4292
+ \`@agentskit/tools/mcp-devtools\`.
4293
+
4294
+ ## Types
4295
+
4296
+ - TypeScript strict mode is on. **Do not use \`any\`** \u2014 use \`unknown\` and narrow.
4297
+ - Headless React components: no hardcoded styles, use \`data-ak-*\` attributes.
4298
+
4299
+ ## Errors
4300
+
4301
+ - Never \`throw new Error(...)\` inside package source. Use the typed errors from
4302
+ \`@agentskit/core\`: \`AdapterError\`, \`ToolError\`, \`MemoryError\`, \`RuntimeError\`,
4303
+ \`SandboxError\`, \`SkillError\`, \`ConfigError\`. Pair with \`ErrorCodes.<...>\`.
4304
+
4305
+ ## Tests
4306
+
4307
+ - vitest. Place tests under \`packages/<pkg>/tests/\` mirroring \`src/\`.
4308
+ - E2E lives in \`apps/example-*\` with Playwright.
4309
+
4310
+ ## Versioning
4311
+
4312
+ - Every PR with a behavior change requires a Changeset (\`pnpm changeset\`).
4313
+
4314
+ ## Where to look first
4315
+
4316
+ - Architecture, contracts, ADRs: \`docs/architecture/adrs/\`
4317
+ - Per-package conventions: \`packages/<pkg>/CONVENTIONS.md\`
4318
+ - Agent-facing index: \`AGENTS.md\` and \`apps/docs-next/content/docs/for-agents/\`
4319
+ `;
4320
+
4321
+ // src/rules/windsurf.ts
4322
+ var WINDSURF_RULE = `# AgentsKit project rules (read first)
4323
+
4324
+ This workspace builds AgentsKit \u2014 a JavaScript agent toolkit with a 10 KB core,
4325
+ six formal contracts, and ~19 plug-and-play packages. When generating or
4326
+ editing code, follow these rules \u2014 they are enforced by CI.
4327
+
4328
+ ## Imports
4329
+ - **Named exports only.** No \`export default\`.
4330
+ - Import from package roots (\`@agentskit/core\`, \`@agentskit/runtime\`, \`@agentskit/react\`, etc.).
4331
+ - Tools subpaths: \`@agentskit/tools/integrations\`, \`@agentskit/tools/mcp\`, \`@agentskit/tools/mcp-devtools\`.
4332
+
4333
+ ## Types
4334
+ - Strict mode TypeScript. **No \`any\`** \u2014 use \`unknown\` and narrow.
4335
+
4336
+ ## Errors
4337
+ - **Do not** \`throw new Error(...)\` in package source. Use \`AdapterError\` /
4338
+ \`ToolError\` / \`MemoryError\` / \`RuntimeError\` / \`SandboxError\` / \`SkillError\` /
4339
+ \`ConfigError\` from \`@agentskit/core\`, paired with \`ErrorCodes\`.
4340
+
4341
+ ## Tests
4342
+ - vitest. Tests live in \`packages/<pkg>/tests/\` mirroring \`src/\`.
4343
+ - E2E lives in \`apps/example-*\` with Playwright.
4344
+
4345
+ ## Versioning
4346
+ - Every behavior change needs a Changeset (\`pnpm changeset\`).
4347
+
4348
+ ## Read first
4349
+ - \`AGENTS.md\` \u2014 universal agent guidance
4350
+ - \`apps/docs-next/content/docs/for-agents/\` \u2014 per-package agent docs
4351
+ - \`docs/architecture/adrs/\` \u2014 six core contracts (Adapter, Tool, Memory, Retriever, Skill, Runtime)
4352
+ - \`packages/<pkg>/CONVENTIONS.md\` \u2014 per-package contribution rules
4353
+ `;
4354
+
4355
+ // src/rules/codex.ts
4356
+ var CODEX_PROFILE = `<!-- agentskit-codex-profile:start -->
4357
+ ## Codex / Aider profile
4358
+
4359
+ Structured hints for CLI coding agents (OpenAI Codex, Aider, Claude Code,
4360
+ Cursor) running against this workspace. Update via \`agentskit rules codex\`.
4361
+
4362
+ \`\`\`yaml
4363
+ # AgentsKit Codex profile v1
4364
+ profile: agentskit
4365
+ runtime: node-25
4366
+ package_manager: pnpm
4367
+ test_runner: vitest
4368
+ build_runner: turborepo
4369
+
4370
+ allowed_commands:
4371
+ - pnpm install
4372
+ - pnpm build
4373
+ - pnpm test
4374
+ - pnpm lint
4375
+ - pnpm changeset
4376
+ - pnpm --filter @agentskit/* test
4377
+ - pnpm --filter @agentskit/* lint
4378
+ - pnpm --filter @agentskit/* build
4379
+
4380
+ restricted_paths:
4381
+ - packages/core/src/errors.ts # Touch carefully \u2014 every package depends on the typed errors here.
4382
+ - packages/core/src/security/ # Security-sensitive \u2014 small surface, requires review.
4383
+ - docs/architecture/adrs/ # Contract changes need a new ADR + major bump.
4384
+
4385
+ models_recommended:
4386
+ - claude-sonnet-4-6 # Default \u2014 long context, fast.
4387
+ - gpt-5 # Strong reasoning for refactors / cross-package work.
4388
+ - claude-opus-4-7 # Heavy refactors, contract redesigns.
4389
+
4390
+ invariants:
4391
+ core_max_kb_gzip: 10
4392
+ no_default_exports: true
4393
+ strict_typescript: true
4394
+ no_bare_throw_new_error: true
4395
+ named_exports_only: true
4396
+ changeset_required_for_behavior_changes: true
4397
+
4398
+ read_first:
4399
+ - AGENTS.md
4400
+ - apps/docs-next/content/docs/for-agents/
4401
+ - docs/architecture/adrs/
4402
+ \`\`\`
4403
+ <!-- agentskit-codex-profile:end -->
4404
+ `;
4405
+
4406
+ // src/rules/claude-code.ts
4407
+ var CLAUDE_CODE_SKILL = [
4408
+ {
4409
+ path: "SKILL.md",
4410
+ contents: `---
4411
+ name: agentskit
4412
+ description: Scaffold AgentsKit projects, add tools/skills, run doctor, and inspect the runtime \u2014 wraps the agentskit CLI.
4413
+ ---
4414
+
4415
+ # AgentsKit
4416
+
4417
+ Skill bundle for working with the AgentsKit toolkit from inside Claude Code.
4418
+
4419
+ Pair this skill with the project-scoped slash commands at \`.claude/commands/agentskit-*.md\`:
4420
+
4421
+ - \`/agentskit-new-agent\` \u2014 interactive scaffold (\`agentskit init\`)
4422
+ - \`/agentskit-doctor\` \u2014 diagnose the local environment (\`agentskit doctor\`)
4423
+ - \`/agentskit-add-tool\` \u2014 add a tool integration template
4424
+ - \`/agentskit-add-skill\` \u2014 add a skill template
4425
+ - \`/agentskit-lint-pii\` \u2014 validate a PII taxonomy file
4426
+ - \`/agentskit-rules\` \u2014 write \`.cursor/rules\` / \`.windsurfrules\` / Codex profile
4427
+
4428
+ When the user is inside an AgentsKit workspace, prefer the slash commands over
4429
+ hand-rolling shell invocations \u2014 they share the canonical defaults.
4430
+
4431
+ For convention reminders (named exports only, no bare throw, etc.), read
4432
+ \`AGENTS.md\` at the workspace root.
4433
+ `
4434
+ }
4435
+ ];
4436
+ var CLAUDE_CODE_SLASH_COMMANDS = [
4437
+ {
4438
+ path: "agentskit-new-agent.md",
4439
+ contents: `---
4440
+ description: Scaffold a new AgentsKit project (interactive)
4441
+ allowed-tools: Bash(npx agentskit init:*)
4442
+ ---
4443
+
4444
+ Run \`npx @agentskit/cli init\` interactively in the user's chosen directory.
4445
+ After scaffold completes, summarise the layout (templates created, next
4446
+ commands the user should run).
4447
+ `
4448
+ },
4449
+ {
4450
+ path: "agentskit-doctor.md",
4451
+ contents: `---
4452
+ description: Run the AgentsKit environment doctor and summarise findings
4453
+ allowed-tools: Bash(npx agentskit doctor:*)
4454
+ ---
4455
+
4456
+ Run \`npx @agentskit/cli doctor\` in the workspace root. Format the output
4457
+ into pass / warn / fail buckets and propose a fix for each fail / warn.
4458
+ `
4459
+ },
4460
+ {
4461
+ path: "agentskit-add-tool.md",
4462
+ contents: `---
4463
+ description: Add a tool template to the current package
4464
+ ---
4465
+
4466
+ Ask the user which tool to add. Use \`packages/templates/src/blueprints/tool.ts\`
4467
+ to scaffold the file under \`packages/<pkg>/src/tools/\`. Update the package's
4468
+ \`src/index.ts\` to re-export the new tool. Add a vitest mock test under
4469
+ \`packages/<pkg>/tests/\`.
4470
+ `
4471
+ },
4472
+ {
4473
+ path: "agentskit-add-skill.md",
4474
+ contents: `---
4475
+ description: Add a skill template to @agentskit/skills
4476
+ ---
4477
+
4478
+ Use \`packages/templates/src/blueprints/skill.ts\` to scaffold a new skill
4479
+ under \`packages/skills/src/\`. Re-export from the package index. Add a
4480
+ golden-dataset test fixture under \`packages/skills/tests/\` (10\u201350 input/
4481
+ expected examples, per the conventions).
4482
+ `
4483
+ },
4484
+ {
4485
+ path: "agentskit-lint-pii.md",
4486
+ contents: `---
4487
+ description: Validate a PII taxonomy JSON file
4488
+ allowed-tools: Bash(npx agentskit pii lint:*)
4489
+ ---
4490
+
4491
+ Ask the user for a path. Run \`npx @agentskit/cli pii lint <path>\` and
4492
+ display the report. If issues exist, suggest concrete fixes per the
4493
+ issue messages.
4494
+ `
4495
+ },
4496
+ {
4497
+ path: "agentskit-rules.md",
4498
+ contents: `---
4499
+ description: Write editor rule files (Cursor / Windsurf / Codex / Claude Code)
4500
+ allowed-tools: Bash(npx agentskit rules:*)
4501
+ ---
4502
+
4503
+ Ask which editor (or "all"). Run the matching:
4504
+ - \`npx @agentskit/cli rules cursor\`
4505
+ - \`npx @agentskit/cli rules windsurf\`
4506
+ - \`npx @agentskit/cli rules codex\`
4507
+ - \`npx @agentskit/cli rules claude-code\`
4508
+
4509
+ After writing, summarise which files landed and what each one does.
4510
+ `
4511
+ }
4512
+ ];
4513
+
4514
+ // src/rules.ts
4515
+ var CODEX_BLOCK_START = "<!-- agentskit-codex-profile:start -->";
4516
+ var CODEX_BLOCK_END = "<!-- agentskit-codex-profile:end -->";
4517
+ async function ensureDir2(path5) {
4518
+ await mkdir(dirname(path5), { recursive: true });
4519
+ }
4520
+ async function writeIfChanged(absPath, contents, force) {
4521
+ let existing;
4522
+ try {
4523
+ existing = await readFile(absPath, "utf8");
4524
+ } catch {
4525
+ }
4526
+ if (existing === contents) return "skipped";
4527
+ if (existing !== void 0 && !force) {
4528
+ return "skipped";
4529
+ }
4530
+ await ensureDir2(absPath);
4531
+ await writeFile(absPath, contents, "utf8");
4532
+ return existing === void 0 ? "wrote" : "updated";
4533
+ }
4534
+ async function writeCursor(rootDir, force) {
4535
+ const path5 = join(rootDir, ".cursor", "rules", "agentskit.mdc");
4536
+ const action = await writeIfChanged(path5, CURSOR_RULE, force);
4537
+ return [{ path: path5, action }];
4538
+ }
4539
+ async function writeWindsurf(rootDir, force) {
4540
+ const path5 = join(rootDir, ".windsurfrules");
4541
+ const action = await writeIfChanged(path5, WINDSURF_RULE, force);
4542
+ return [{ path: path5, action }];
4543
+ }
4544
+ async function writeCodex(rootDir, force) {
4545
+ const path5 = join(rootDir, "AGENTS.md");
4546
+ let existing = "";
4547
+ try {
4548
+ existing = await readFile(path5, "utf8");
4549
+ } catch {
4550
+ }
4551
+ const startIdx = existing.indexOf(CODEX_BLOCK_START);
4552
+ const endIdx = startIdx >= 0 ? existing.lastIndexOf(CODEX_BLOCK_END, existing.length) : -1;
4553
+ if (startIdx >= 0 && endIdx <= startIdx) {
4554
+ throw new ConfigError({
4555
+ code: ErrorCodes.AK_CONFIG_INVALID,
4556
+ message: `${path5}: found agentskit-codex-profile:start sentinel but no matching :end after it \u2014 refusing to modify a half-edited block.`,
4557
+ hint: "Restore the closing sentinel or remove the partial block, then re-run."
4558
+ });
4559
+ }
4560
+ let next;
4561
+ if (startIdx >= 0 && endIdx > startIdx) {
4562
+ next = existing.slice(0, startIdx) + CODEX_PROFILE.trimEnd() + existing.slice(endIdx + CODEX_BLOCK_END.length);
4563
+ } else if (existing) {
4564
+ next = `${existing.replace(/\s+$/, "")}
4565
+
4566
+ ${CODEX_PROFILE}`;
4567
+ } else {
4568
+ next = CODEX_PROFILE;
4569
+ }
4570
+ if (next === existing) return [{ path: path5, action: "skipped" }];
4571
+ if (existing && !force) {
4572
+ return [{ path: path5, action: "skipped" }];
4573
+ }
4574
+ await ensureDir2(path5);
4575
+ await writeFile(path5, next, "utf8");
4576
+ return [{ path: path5, action: existing ? "updated" : "wrote" }];
4577
+ }
4578
+ async function writeClaudeCode(rootDir, force) {
4579
+ const out = [];
4580
+ const skillRoot = join(rootDir, ".claude", "skills", "agentskit");
4581
+ for (const file of CLAUDE_CODE_SKILL) {
4582
+ const abs = join(skillRoot, file.path);
4583
+ const action = await writeIfChanged(abs, file.contents, force);
4584
+ out.push({ path: abs, action });
4585
+ }
4586
+ const commandsRoot = join(rootDir, ".claude", "commands");
4587
+ for (const cmd of CLAUDE_CODE_SLASH_COMMANDS) {
4588
+ const abs = join(commandsRoot, cmd.path);
4589
+ const action = await writeIfChanged(abs, cmd.contents, force);
4590
+ out.push({ path: abs, action });
4591
+ }
4592
+ return out;
4593
+ }
4594
+ async function writeRules(editor, options = {}) {
4595
+ const root = resolve(options.rootDir ?? process.cwd());
4596
+ const force = options.force === true;
4597
+ if (editor === "all") {
4598
+ return [
4599
+ { editor: "cursor", files: await writeCursor(root, force) },
4600
+ { editor: "windsurf", files: await writeWindsurf(root, force) },
4601
+ { editor: "codex", files: await writeCodex(root, force) },
4602
+ { editor: "claude-code", files: await writeClaudeCode(root, force) }
4603
+ ];
4604
+ }
4605
+ switch (editor) {
4606
+ case "cursor":
4607
+ return [{ editor, files: await writeCursor(root, force) }];
4608
+ case "windsurf":
4609
+ return [{ editor, files: await writeWindsurf(root, force) }];
4610
+ case "codex":
4611
+ return [{ editor, files: await writeCodex(root, force) }];
4612
+ case "claude-code":
4613
+ return [{ editor, files: await writeClaudeCode(root, force) }];
4614
+ }
4615
+ }
4616
+
4617
+ // src/commands/rules.ts
4618
+ var VALID = ["cursor", "windsurf", "codex", "claude-code", "all"];
4619
+ function registerRulesCommand(program) {
4620
+ program.command("rules <editor>").description(
4621
+ "Write editor rule files (cursor | windsurf | codex | claude-code | all). Teaches the editor AgentsKit conventions so generated code respects named-export-only, package boundaries, and the for-agents/* manifest."
4622
+ ).option("--out <dir>", "Workspace root to write files into (default: cwd)").option("-f, --force", "Overwrite existing rule files (codex / claude-code skill always update in place)").action(async (editor, options) => {
4623
+ if (!VALID.includes(editor)) {
4624
+ process.stderr.write(`unknown editor "${editor}". Valid: ${VALID.join(", ")}
4625
+ `);
4626
+ process.exit(1);
4627
+ }
4628
+ try {
4629
+ const results = await writeRules(editor, {
4630
+ rootDir: options.out,
4631
+ force: options.force === true
4632
+ });
4633
+ const counts = { wrote: 0, updated: 0, skipped: 0 };
4634
+ for (const { editor: ed, files } of results) {
4635
+ process.stdout.write(`
4636
+ [${ed}]
4637
+ `);
4638
+ for (const f of files) {
4639
+ counts[f.action]++;
4640
+ process.stdout.write(` ${f.action.padEnd(7)} ${f.path}
4641
+ `);
4642
+ }
4643
+ }
4644
+ process.stdout.write(
4645
+ `
4646
+ Done \u2014 ${counts.wrote} wrote, ${counts.updated} updated, ${counts.skipped} skipped.
4647
+ `
4648
+ );
4649
+ if (counts.skipped > 0 && options.force !== true) {
4650
+ process.stdout.write(`(re-run with --force to overwrite skipped files)
4651
+ `);
4652
+ }
4653
+ } catch (err) {
4654
+ const message = err instanceof Error ? err.message : String(err);
4655
+ process.stderr.write(`
4656
+ rules failed: ${message}
4657
+ `);
4658
+ process.exit(1);
4659
+ }
4660
+ });
4661
+ }
4162
4662
 
4163
4663
  // src/commands/index.ts
4164
4664
  function createCli() {
@@ -4174,9 +4674,11 @@ function createCli() {
4174
4674
  registerRagCommand(program);
4175
4675
  registerAiCommand(program);
4176
4676
  registerFlowCommand(program);
4677
+ registerPiiCommand(program);
4678
+ registerRulesCommand(program);
4177
4679
  return program;
4178
4680
  }
4179
4681
 
4180
4682
  export { ChatApp, HookDispatcher, McpClient, applyPolicyToTool, applyPolicyToTools, bridgeMcpServers, buildRagFromConfig, computeCost, configHooksToHandlers, createCli, createOpenAiEmbedder, defaultPolicy, derivePreview, disposeMcpClients, evaluatePolicy, findLatestSession, findSession, forkSession, generateSessionId, getPricing, indexSources, listSessions, loadConfig, loadPlugins, mergePluginsIntoBundle, registerPricing, renameSession, renderChatHeader, renderReport, resolveChatProvider, resolveSession, runAgent, runDoctor, sessionFilePath, startDev, startTunnel, writeSessionMeta, writeStarterProject };
4181
- //# sourceMappingURL=chunk-7SBFFCM7.js.map
4182
- //# sourceMappingURL=chunk-7SBFFCM7.js.map
4683
+ //# sourceMappingURL=chunk-X4PVLZSO.js.map
4684
+ //# sourceMappingURL=chunk-X4PVLZSO.js.map