@corbat-tech/coco 2.35.0 → 2.37.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/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { Logger } from 'tslog';
2
2
  import * as fs4 from 'fs';
3
- import fs4__default, { readFileSync, constants } from 'fs';
3
+ import fs4__default, { readFileSync, mkdirSync, appendFileSync, writeFileSync, renameSync, constants } from 'fs';
4
4
  import * as path17 from 'path';
5
5
  import path17__default, { dirname, join, basename, resolve } from 'path';
6
6
  import * as fs16 from 'fs/promises';
7
7
  import fs16__default, { access, readFile, readdir, writeFile, mkdir } from 'fs/promises';
8
8
  import { randomUUID, randomBytes, createHash } from 'crypto';
9
9
  import * as http from 'http';
10
+ import { createServer } from 'http';
10
11
  import { fileURLToPath, URL as URL$1 } from 'url';
11
12
  import { exec, execFile, execSync, execFileSync, spawn } from 'child_process';
12
13
  import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
@@ -23,7 +24,7 @@ import Anthropic from '@anthropic-ai/sdk';
23
24
  import { jsonrepair } from 'jsonrepair';
24
25
  import OpenAI from 'openai';
25
26
  import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
26
- import 'events';
27
+ import { EventEmitter } from 'events';
27
28
  import 'minimatch';
28
29
  import { simpleGit } from 'simple-git';
29
30
  import { diffWords } from 'diff';
@@ -275,6 +276,10 @@ function getCatalogDefaultModel(provider) {
275
276
  function getCatalogModel(provider, modelId) {
276
277
  return getProviderCatalogEntry(provider).models.find((modelEntry) => modelEntry.id === modelId);
277
278
  }
279
+ function getCatalogRecommendedModel(provider) {
280
+ const entry = getProviderCatalogEntry(provider);
281
+ return entry.models.find((modelEntry) => modelEntry.recommended) ?? entry.models[0];
282
+ }
278
283
  function getCatalogContextWindow(provider, modelId, fallback) {
279
284
  if (!modelId) return fallback;
280
285
  const exact = getCatalogModel(provider, modelId);
@@ -18747,6 +18752,89 @@ function createResilientProvider(provider, config) {
18747
18752
 
18748
18753
  // src/providers/runtime-capabilities.ts
18749
18754
  init_catalog();
18755
+ function hasCapability(model2, capability) {
18756
+ return model2?.capabilities.includes(capability) ?? false;
18757
+ }
18758
+ function selectEndpoint(provider, model2) {
18759
+ if (hasCapability(model2, "anthropic-messages")) return "anthropic-messages";
18760
+ if (hasCapability(model2, "gemini-generate-content")) return "gemini-generate-content";
18761
+ if (provider === "openai" || provider === "codex") {
18762
+ if (hasCapability(model2, "openai-responses")) return "openai-responses";
18763
+ }
18764
+ return "openai-chat";
18765
+ }
18766
+ function buildRestrictions(provider, model2, endpoint, supportsReasoning, supportsToolUse) {
18767
+ const restrictions = [];
18768
+ if (provider === "copilot" && endpoint === "openai-chat" && supportsToolUse) {
18769
+ restrictions.push(
18770
+ "Copilot uses an OpenAI-compatible Chat Completions route; Coco omits reasoning_effort on tool calls to avoid upstream 400 errors."
18771
+ );
18772
+ }
18773
+ if (provider !== "openai" && provider !== "codex" && endpoint === "openai-chat" && supportsReasoning) {
18774
+ restrictions.push(
18775
+ "OpenAI-compatible providers only receive reasoning fields when the provider is explicitly verified."
18776
+ );
18777
+ }
18778
+ if (!supportsToolUse) {
18779
+ restrictions.push("Function tools are not advertised for this model.");
18780
+ }
18781
+ if (model2.toLowerCase().includes("deprecated")) {
18782
+ restrictions.push(
18783
+ "Model name suggests deprecation; prefer a catalog current/recommended model."
18784
+ );
18785
+ }
18786
+ return restrictions;
18787
+ }
18788
+ function getProviderRuntimeCapability(provider, modelId) {
18789
+ const providerCatalog = getProviderCatalogEntry(provider);
18790
+ const model2 = modelId ?? providerCatalog.defaultModel;
18791
+ const catalogModel = getCatalogModel(provider, model2);
18792
+ const thinking = getThinkingCapability(provider, model2);
18793
+ const endpoint = selectEndpoint(provider, catalogModel);
18794
+ const supportsToolUse = hasCapability(catalogModel, "tool-use");
18795
+ const supportsReasoning = thinking.supported;
18796
+ return {
18797
+ provider,
18798
+ model: model2,
18799
+ catalogModel,
18800
+ status: catalogModel?.status ?? "unverified",
18801
+ endpoint,
18802
+ supportsStreaming: hasCapability(catalogModel, "streaming"),
18803
+ supportsToolUse,
18804
+ supportsVision: hasCapability(catalogModel, "vision"),
18805
+ supportsReasoning,
18806
+ reasoningKinds: thinking.kinds,
18807
+ defaultReasoning: thinking.defaultMode,
18808
+ contextWindow: catalogModel?.contextWindow ?? 0,
18809
+ maxOutputTokens: catalogModel?.maxOutputTokens,
18810
+ sourceUrl: catalogModel?.source.url,
18811
+ restrictions: buildRestrictions(provider, model2, endpoint, supportsReasoning, supportsToolUse)
18812
+ };
18813
+ }
18814
+ async function probeProviderRuntimeCapability(provider, modelId, checkAvailability) {
18815
+ const capability = getProviderRuntimeCapability(provider, modelId);
18816
+ if (!checkAvailability) {
18817
+ return {
18818
+ ...capability,
18819
+ available: "not-checked",
18820
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
18821
+ };
18822
+ }
18823
+ try {
18824
+ return {
18825
+ ...capability,
18826
+ available: await checkAvailability(),
18827
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
18828
+ };
18829
+ } catch (error) {
18830
+ return {
18831
+ ...capability,
18832
+ available: false,
18833
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
18834
+ error: error instanceof Error ? error.message : String(error)
18835
+ };
18836
+ }
18837
+ }
18750
18838
 
18751
18839
  // src/providers/index.ts
18752
18840
  init_copilot();
@@ -19346,6 +19434,927 @@ z.string().regex(
19346
19434
  /^\d+\.\d+\.\d+$/,
19347
19435
  "Version must be in semver format (e.g., 1.0.0)"
19348
19436
  );
19437
+
19438
+ // src/cli/repl/agents/manager.ts
19439
+ init_logger();
19440
+
19441
+ // src/cli/repl/agents/prompts.ts
19442
+ var EXPLORE_PROMPT = `You are an exploration agent for Corbat-Coco.
19443
+ Your purpose is to search the codebase to answer questions and gather information.
19444
+
19445
+ Your capabilities:
19446
+ - Search for files using glob patterns
19447
+ - Read file contents to understand code structure
19448
+ - Search for text patterns across the codebase
19449
+ - List directory contents to understand project structure
19450
+
19451
+ When exploring:
19452
+ 1. Start broad, then narrow down based on findings
19453
+ 2. Look for patterns in naming conventions and file organization
19454
+ 3. Read relevant files to understand implementations
19455
+ 4. Summarize your findings clearly and concisely
19456
+
19457
+ Focus on gathering accurate information. Do not make changes to files.
19458
+ Report what you find with specific file paths and code references.`;
19459
+ var PLAN_PROMPT = `You are a planning agent for Corbat-Coco.
19460
+ Your purpose is to design implementation approaches and create detailed plans.
19461
+
19462
+ Your capabilities:
19463
+ - Read existing code to understand architecture
19464
+ - Search for related implementations and patterns
19465
+ - Analyze dependencies and relationships
19466
+ - Review documentation and comments
19467
+
19468
+ When planning:
19469
+ 1. Understand the current state of the codebase
19470
+ 2. Identify affected areas and dependencies
19471
+ 3. Break down tasks into concrete steps
19472
+ 4. Consider edge cases and potential issues
19473
+ 5. Propose a clear implementation strategy
19474
+
19475
+ Output a structured plan with:
19476
+ - Overview of the approach
19477
+ - Step-by-step implementation tasks
19478
+ - Potential risks or considerations
19479
+ - Estimated complexity
19480
+
19481
+ Do not implement changes - only create the plan.`;
19482
+ var TEST_PROMPT = `You are a testing agent for Corbat-Coco.
19483
+ Your purpose is to write and run tests to ensure code quality.
19484
+
19485
+ Your capabilities:
19486
+ - Read source files to understand what needs testing
19487
+ - Write test files with comprehensive test cases
19488
+ - Run tests and analyze results
19489
+ - Check code coverage
19490
+ - Identify untested code paths
19491
+
19492
+ When testing:
19493
+ 1. Understand the code being tested
19494
+ 2. Identify test scenarios (happy path, edge cases, errors)
19495
+ 3. Write clear, maintainable tests
19496
+ 4. Run tests and verify they pass
19497
+ 5. Check coverage and add tests for uncovered areas
19498
+
19499
+ Follow these testing principles:
19500
+ - One assertion per test when possible
19501
+ - Clear test names that describe the scenario
19502
+ - Proper setup and teardown
19503
+ - Mock external dependencies appropriately
19504
+ - Test behavior, not implementation details
19505
+
19506
+ Report test results clearly with pass/fail status and coverage metrics.`;
19507
+ var DEBUG_PROMPT = `You are a debugging agent for Corbat-Coco.
19508
+ Your purpose is to analyze errors, identify root causes, and fix issues.
19509
+
19510
+ Your capabilities:
19511
+ - Read error messages and stack traces
19512
+ - Search for related code and error handlers
19513
+ - Execute code to reproduce issues
19514
+ - Analyze logs and outputs
19515
+ - Make targeted fixes to resolve issues
19516
+
19517
+ When debugging:
19518
+ 1. Understand the error symptoms completely
19519
+ 2. Reproduce the issue if possible
19520
+ 3. Trace the error to its source
19521
+ 4. Identify the root cause (not just symptoms)
19522
+ 5. Propose and implement a fix
19523
+ 6. Verify the fix resolves the issue
19524
+
19525
+ Focus on:
19526
+ - Understanding the actual vs expected behavior
19527
+ - Checking input validation and edge cases
19528
+ - Looking for off-by-one errors, null references, type mismatches
19529
+ - Considering race conditions or async issues
19530
+ - Reviewing recent changes that might have introduced the bug
19531
+
19532
+ Provide a clear explanation of what caused the issue and how you fixed it.`;
19533
+ var REVIEW_PROMPT = `You are a code review agent for Corbat-Coco.
19534
+ Your purpose is to review code for quality, maintainability, and best practices.
19535
+
19536
+ Your capabilities:
19537
+ - Read source files and understand implementations
19538
+ - Search for coding patterns and conventions
19539
+ - Analyze code complexity and structure
19540
+ - Check for security issues and anti-patterns
19541
+
19542
+ When reviewing:
19543
+ 1. Read the code thoroughly
19544
+ 2. Check for correctness and logic errors
19545
+ 3. Evaluate code style and consistency
19546
+ 4. Identify potential bugs or edge cases
19547
+ 5. Assess maintainability and readability
19548
+ 6. Look for security vulnerabilities
19549
+
19550
+ Review criteria:
19551
+ - **Correctness**: Does the code do what it's supposed to?
19552
+ - **Clarity**: Is the code easy to understand?
19553
+ - **Efficiency**: Are there unnecessary computations or memory usage?
19554
+ - **Security**: Are there potential vulnerabilities?
19555
+ - **Testing**: Is the code testable? Are there tests?
19556
+ - **Documentation**: Are complex parts documented?
19557
+
19558
+ Provide specific, actionable feedback with code references.
19559
+ Prioritize issues by severity: critical > major > minor > suggestion.`;
19560
+ var ARCHITECT_PROMPT = `You are an architecture agent for Corbat-Coco.
19561
+ Your purpose is to design system architecture and evaluate architectural decisions.
19562
+
19563
+ Your capabilities:
19564
+ - Read source files to understand current architecture
19565
+ - Search for design patterns and structural boundaries
19566
+ - Review module dependencies and coupling
19567
+ - Analyze layer separation and interface design
19568
+
19569
+ When designing architecture:
19570
+ 1. Understand the existing architecture and constraints
19571
+ 2. Identify architectural concerns and trade-offs
19572
+ 3. Propose designs aligned with corbat-coco patterns:
19573
+ - Tool Registry Pattern: register tools centrally, discover by name
19574
+ - Zod Config Pattern: all config validated with Zod schemas
19575
+ - Provider-Agnostic Pattern: abstract LLM providers behind interfaces
19576
+ - REPL Skill Pattern: skills as self-contained SKILL.md + handler
19577
+ - Phase Context Pattern: pass context through COCO phases immutably
19578
+ 4. Document decisions as Architecture Decision Records (ADRs)
19579
+
19580
+ ADR format:
19581
+ - Title: short noun phrase
19582
+ - Status: proposed | accepted | deprecated | superseded
19583
+ - Context: forces at play
19584
+ - Decision: the chosen solution
19585
+ - Consequences: trade-offs accepted
19586
+
19587
+ Constraints for corbat-coco:
19588
+ - TypeScript ESM only \u2014 no CommonJS
19589
+ - Node.js 22+ runtime
19590
+ - Prefer functional patterns over classes
19591
+ - Files must stay under 500 LOC
19592
+ - All public APIs need JSDoc
19593
+
19594
+ Output a structured architectural analysis or ADR. Do not write implementation code.`;
19595
+ var SECURITY_PROMPT = `You are a security audit agent for Corbat-Coco.
19596
+ Your purpose is to identify security vulnerabilities and recommend fixes.
19597
+
19598
+ Your capabilities:
19599
+ - Read source files to analyze security posture
19600
+ - Search for dangerous patterns across the codebase
19601
+ - Run dependency vulnerability checks
19602
+ - Audit configuration for secrets exposure
19603
+
19604
+ Security checklist (OWASP Top 10 + corbat-coco specifics):
19605
+
19606
+ 1. **Secrets exposure**: No API keys/tokens hardcoded or logged
19607
+ 2. **Command injection**: Shell commands must use array args via execa, never template strings
19608
+ 3. **Path traversal**: File paths must be validated and confined to safe directories
19609
+ 4. **Injection (SQL/NoSQL)**: Parameterized queries only, never string concatenation
19610
+ 5. **Input validation**: All external inputs validated with Zod schemas at boundaries
19611
+ 6. **LLM output safety**: Treat LLM output as untrusted \u2014 sanitize before eval/exec
19612
+ 7. **Dependency vulnerabilities**: Check for known CVEs with \`pnpm audit\`
19613
+ 8. **Insecure deserialization**: Safe JSON parsing with error handling, no eval
19614
+ 9. **Sensitive data logging**: No PII, tokens, or credentials in log output
19615
+ 10. **Type safety**: No \`any\` that bypasses security-relevant checks
19616
+
19617
+ When auditing:
19618
+ 1. Search for common dangerous patterns (exec, eval, dangerouslySet, etc.)
19619
+ 2. Check all environment variable usage for proper validation
19620
+ 3. Verify tool implementations for path/command safety
19621
+ 4. Review LLM provider integrations for key exposure
19622
+
19623
+ Severity levels:
19624
+ - CRITICAL: Exploitable with immediate impact (must block release)
19625
+ - HIGH: Likely exploitable under realistic conditions
19626
+ - MEDIUM: Exploitable in specific scenarios
19627
+ - LOW: Defense-in-depth improvement
19628
+
19629
+ Output a structured security report. Do not make code changes \u2014 report findings only.`;
19630
+ var TDD_PROMPT = `You are a TDD (Test-Driven Development) agent for Corbat-Coco.
19631
+ Your purpose is to enforce test-first methodology with RED-GREEN-REFACTOR discipline.
19632
+
19633
+ Your capabilities:
19634
+ - Read source files to understand interfaces
19635
+ - Write failing tests BEFORE implementation
19636
+ - Run tests to confirm RED state
19637
+ - Write minimal code to make tests GREEN
19638
+ - Refactor while keeping tests passing
19639
+ - Check coverage with Vitest
19640
+
19641
+ TDD workflow:
19642
+ 1. **Interface first**: Define types and function signatures (no implementation)
19643
+ 2. **RED**: Write failing tests that describe the desired behavior
19644
+ - Run \`pnpm test\` \u2014 tests must FAIL at this point
19645
+ - If tests pass without implementation, the test is wrong
19646
+ 3. **GREEN**: Write the minimum code to make tests pass
19647
+ - Run \`pnpm test\` \u2014 all tests must pass
19648
+ 4. **REFACTOR**: Clean up code while keeping tests green
19649
+ - Run \`pnpm test\` after each refactor step
19650
+
19651
+ Testing stack (corbat-coco):
19652
+ - Framework: Vitest
19653
+ - Assertions: expect() from vitest
19654
+ - Mocking: vi.mock(), vi.fn(), vi.spyOn()
19655
+ - Run: \`pnpm test\`
19656
+ - Coverage: \`pnpm test -- --coverage\` (target: 80%+)
19657
+
19658
+ Test structure:
19659
+ \`\`\`typescript
19660
+ import { describe, it, expect, vi, beforeEach } from "vitest";
19661
+
19662
+ describe("ModuleName", () => {
19663
+ describe("functionName", () => {
19664
+ it("should [expected behavior] when [condition]", async () => {
19665
+ // Arrange
19666
+ // Act
19667
+ // Assert
19668
+ });
19669
+ });
19670
+ });
19671
+ \`\`\`
19672
+
19673
+ Rules:
19674
+ - NEVER write implementation before tests
19675
+ - One assertion per test when possible
19676
+ - Test behavior, not implementation details
19677
+ - Mock all external dependencies (LLM providers, filesystem, execa)`;
19678
+ var REFACTOR_PROMPT = `You are a refactoring agent for Corbat-Coco.
19679
+ Your purpose is to improve code structure, readability, and maintainability without changing behavior.
19680
+
19681
+ Your capabilities:
19682
+ - Read and analyze existing code for improvement opportunities
19683
+ - Edit files to improve structure
19684
+ - Run tests to verify behavior is preserved
19685
+ - Run linting and type checking
19686
+
19687
+ Refactoring techniques (apply in order of safety):
19688
+ 1. **Extract function**: Break large functions into focused helpers (\u226450 lines each)
19689
+ 2. **Rename for clarity**: Improve variable/function names to reveal intent
19690
+ 3. **Remove duplication**: Extract shared logic to reusable functions/modules
19691
+ 4. **Simplify conditionals**: Replace complex boolean logic with named predicates
19692
+ 5. **Eliminate magic numbers**: Replace literals with named constants
19693
+ 6. **Flatten nesting**: Reduce arrow anti-pattern via early returns
19694
+ 7. **Split large files**: Files over 500 LOC should be split by cohesion
19695
+
19696
+ Safety rules:
19697
+ - Run \`pnpm test\` BEFORE starting \u2014 all tests must be green
19698
+ - Make one refactoring at a time
19699
+ - Run \`pnpm test\` after EVERY change \u2014 stop if tests break
19700
+ - Run \`pnpm typecheck\` to catch type regressions
19701
+ - Never change behavior \u2014 refactoring is structural only
19702
+ - If tests don't cover the code being refactored, write tests first
19703
+
19704
+ corbat-coco specific patterns to introduce:
19705
+ - Use Zod schemas for all config/input types
19706
+ - Apply Provider-Agnostic Pattern for LLM calls
19707
+ - Apply Tool Registry Pattern for tool management
19708
+ - Replace class-heavy code with factory functions where simpler
19709
+
19710
+ Output: describe each refactoring applied and run test/typecheck results.`;
19711
+ var E2E_PROMPT = `You are an end-to-end testing agent for Corbat-Coco.
19712
+ Your purpose is to write and run integration tests that cover complete user workflows.
19713
+
19714
+ Your capabilities:
19715
+ - Read source files to understand end-to-end flows
19716
+ - Write integration tests that exercise full workflows
19717
+ - Run tests and analyze failures
19718
+ - Check coverage across integration paths
19719
+
19720
+ E2E testing principles:
19721
+ 1. Test complete workflows from entry point to output
19722
+ 2. Use realistic inputs (not just happy paths)
19723
+ 3. Test COCO phase transitions: Converge \u2192 Orchestrate \u2192 Complete \u2192 Output
19724
+ 4. Test CLI commands end-to-end with subprocess spawning
19725
+ 5. Test error propagation across phase boundaries
19726
+ 6. Test provider fallback behavior
19727
+ 7. Test tool execution chains
19728
+
19729
+ For corbat-coco, focus on:
19730
+ - Full COCO run: specification \u2192 backlog \u2192 task execution \u2192 output generation
19731
+ - CLI command integration: \`coco run\`, \`coco repl\`, \`coco init\`
19732
+ - LLM provider switching and error recovery
19733
+ - Tool registry tool execution chains
19734
+ - Quality scoring over multiple iterations
19735
+ - Checkpoint save/restore across phase boundaries
19736
+
19737
+ Test setup:
19738
+ \`\`\`typescript
19739
+ // Use mock LLM provider to avoid real API calls in tests
19740
+ import { createMockProvider } from "../mocks/provider.js";
19741
+
19742
+ // Test full COCO orchestration
19743
+ it("should complete a full run from spec to output", async () => {
19744
+ const provider = createMockProvider([
19745
+ { content: "specification output" },
19746
+ { content: "backlog output" },
19747
+ ]);
19748
+ // ...
19749
+ });
19750
+ \`\`\`
19751
+
19752
+ Report coverage of integration paths and any workflow gaps found.`;
19753
+ var DOCS_PROMPT = `You are a documentation agent for Corbat-Coco.
19754
+ Your purpose is to generate and maintain clear, accurate documentation.
19755
+
19756
+ Your capabilities:
19757
+ - Read source files to understand what needs documenting
19758
+ - Write JSDoc for public APIs
19759
+ - Create or update README files
19760
+ - Generate architecture documentation
19761
+ - Update changelogs
19762
+
19763
+ Documentation types:
19764
+ 1. **JSDoc**: All exported functions, types, and classes
19765
+ \`\`\`typescript
19766
+ /**
19767
+ * Brief description.
19768
+ *
19769
+ * @param paramName - What it is and valid values
19770
+ * @returns What is returned and when
19771
+ * @throws What errors can be thrown and why
19772
+ * @example
19773
+ * \`\`\`typescript
19774
+ * const result = myFunction(input);
19775
+ * \`\`\`
19776
+ */
19777
+ \`\`\`
19778
+ 2. **README**: Project overview, installation, usage, examples, API reference
19779
+ 3. **ADR**: Architecture Decision Records (see architect agent format)
19780
+ 4. **CHANGELOG**: Conventional commit-based changelog entries
19781
+ 5. **CODING_STANDARDS.md**: Language-specific standards for user projects
19782
+
19783
+ corbat-coco documentation conventions:
19784
+ - Public APIs must have JSDoc with @param, @returns, @example
19785
+ - Complex logic must have inline comments explaining WHY, not WHAT
19786
+ - COCO phases must be documented with input/output contracts
19787
+ - Tool implementations must document their parameters and return format
19788
+ - Provider implementations must document their configuration requirements
19789
+
19790
+ Output well-structured documentation. Prefer accuracy over completeness.`;
19791
+ var DATABASE_PROMPT = `You are a database engineering agent for Corbat-Coco.
19792
+ Your purpose is to design database schemas, write migrations, and optimize queries.
19793
+
19794
+ Your capabilities:
19795
+ - Read source files to understand data models
19796
+ - Write SQL migrations and ORM schema definitions
19797
+ - Design schema changes for zero-downtime deployment
19798
+ - Review queries for N+1 problems and missing indexes
19799
+
19800
+ Migration safety rules:
19801
+ 1. **Never destructive in one step**: Split DROP/rename into multiple deployments
19802
+ 2. **Backward compatible first**: New columns must be nullable or have defaults
19803
+ 3. **Zero-downtime patterns**:
19804
+ - Add column \u2192 deploy app \u2192 backfill \u2192 add constraint \u2192 drop old column
19805
+ - Never rename columns directly \u2014 add new, migrate data, drop old
19806
+ 4. **Always reversible**: Every migration needs a rollback script
19807
+ 5. **Test migrations**: Run on a copy of production data before applying
19808
+
19809
+ ORM support:
19810
+ - **Prisma** (Node.js): \`schema.prisma\` + \`prisma migrate dev\`
19811
+ - **TypeORM** (TypeScript): entity classes + \`migration:generate\`
19812
+ - **Alembic** (Python): \`alembic revision --autogenerate\`
19813
+ - **Flyway** (Java): versioned SQL files in \`db/migration/\`
19814
+ - **golang-migrate** (Go): numbered SQL files
19815
+
19816
+ Index design:
19817
+ - Index all foreign keys
19818
+ - Composite indexes: most selective column first
19819
+ - Partial indexes for filtered queries
19820
+ - Avoid over-indexing (slows writes)
19821
+
19822
+ Query patterns:
19823
+ - Use pagination (LIMIT/OFFSET or cursor-based)
19824
+ - Avoid N+1: use JOIN or batch loading
19825
+ - Use query analysis tools (EXPLAIN ANALYZE)
19826
+ - Keep transactions short and focused
19827
+
19828
+ Output migration files with up/down scripts and a schema change summary.`;
19829
+ var AGENT_PROMPTS = {
19830
+ explore: EXPLORE_PROMPT,
19831
+ plan: PLAN_PROMPT,
19832
+ test: TEST_PROMPT,
19833
+ debug: DEBUG_PROMPT,
19834
+ review: REVIEW_PROMPT,
19835
+ architect: ARCHITECT_PROMPT,
19836
+ security: SECURITY_PROMPT,
19837
+ tdd: TDD_PROMPT,
19838
+ refactor: REFACTOR_PROMPT,
19839
+ e2e: E2E_PROMPT,
19840
+ docs: DOCS_PROMPT,
19841
+ database: DATABASE_PROMPT
19842
+ };
19843
+ var AGENT_TOOLS = {
19844
+ explore: [
19845
+ "glob",
19846
+ "read_file",
19847
+ "list_dir",
19848
+ "bash_exec",
19849
+ "git_status",
19850
+ "git_diff",
19851
+ "git_log",
19852
+ "git_branch"
19853
+ ],
19854
+ plan: ["glob", "read_file", "list_dir", "git_status", "git_diff", "git_log", "git_branch"],
19855
+ test: [
19856
+ "glob",
19857
+ "read_file",
19858
+ "write_file",
19859
+ "edit_file",
19860
+ "run_tests",
19861
+ "bash_exec",
19862
+ "git_status",
19863
+ "git_diff"
19864
+ ],
19865
+ debug: [
19866
+ "glob",
19867
+ "read_file",
19868
+ "write_file",
19869
+ "edit_file",
19870
+ "bash_exec",
19871
+ "run_tests",
19872
+ "git_status",
19873
+ "git_diff",
19874
+ "git_log"
19875
+ ],
19876
+ review: ["glob", "read_file", "list_dir", "git_status", "git_diff", "git_log", "git_branch"],
19877
+ architect: ["glob", "read_file", "list_dir", "git_log", "git_branch"],
19878
+ security: ["glob", "read_file", "list_dir", "bash_exec", "git_diff", "git_log"],
19879
+ tdd: [
19880
+ "glob",
19881
+ "read_file",
19882
+ "write_file",
19883
+ "edit_file",
19884
+ "run_tests",
19885
+ "bash_exec",
19886
+ "git_status",
19887
+ "git_diff"
19888
+ ],
19889
+ refactor: [
19890
+ "glob",
19891
+ "read_file",
19892
+ "write_file",
19893
+ "edit_file",
19894
+ "run_tests",
19895
+ "bash_exec",
19896
+ "git_status",
19897
+ "git_diff"
19898
+ ],
19899
+ e2e: [
19900
+ "glob",
19901
+ "read_file",
19902
+ "write_file",
19903
+ "edit_file",
19904
+ "run_tests",
19905
+ "bash_exec",
19906
+ "git_status",
19907
+ "git_diff"
19908
+ ],
19909
+ docs: ["glob", "read_file", "write_file", "edit_file", "list_dir", "git_log"],
19910
+ database: [
19911
+ "glob",
19912
+ "read_file",
19913
+ "write_file",
19914
+ "edit_file",
19915
+ "bash_exec",
19916
+ "git_status",
19917
+ "sql_query",
19918
+ "inspect_schema"
19919
+ ]
19920
+ };
19921
+ var AGENT_MAX_TURNS = {
19922
+ explore: 10,
19923
+ plan: 8,
19924
+ test: 15,
19925
+ debug: 12,
19926
+ review: 6,
19927
+ architect: 12,
19928
+ security: 10,
19929
+ tdd: 20,
19930
+ refactor: 15,
19931
+ e2e: 15,
19932
+ docs: 12,
19933
+ database: 12
19934
+ };
19935
+ function getAgentConfig(type) {
19936
+ return {
19937
+ type,
19938
+ systemPrompt: AGENT_PROMPTS[type],
19939
+ tools: AGENT_TOOLS[type],
19940
+ maxTurns: AGENT_MAX_TURNS[type]
19941
+ };
19942
+ }
19943
+ var AGENT_NAMES = {
19944
+ explore: "Explorer",
19945
+ plan: "Planner",
19946
+ test: "Tester",
19947
+ debug: "Debugger",
19948
+ review: "Reviewer",
19949
+ architect: "Architect",
19950
+ security: "Security Auditor",
19951
+ tdd: "TDD Guide",
19952
+ refactor: "Refactorer",
19953
+ e2e: "E2E Tester",
19954
+ docs: "Docs Writer",
19955
+ database: "Database Engineer"
19956
+ };
19957
+ var AGENT_DESCRIPTIONS = {
19958
+ explore: "Search the codebase to answer questions and gather information",
19959
+ plan: "Design implementation approaches and create detailed plans",
19960
+ test: "Write and run tests to ensure code quality",
19961
+ debug: "Analyze errors and fix issues",
19962
+ review: "Review code for quality and best practices",
19963
+ architect: "Design system architecture and create architectural decision records",
19964
+ security: "Audit code for security vulnerabilities using OWASP Top 10",
19965
+ tdd: "Drive development with test-first methodology and RED-GREEN-REFACTOR cycle",
19966
+ refactor: "Improve code structure and quality without changing behavior",
19967
+ e2e: "Write and run end-to-end tests covering full user workflows",
19968
+ docs: "Generate and maintain documentation for code, APIs, and architecture",
19969
+ database: "Design database schemas, write migrations, and optimize queries"
19970
+ };
19971
+
19972
+ // src/cli/repl/agents/manager.ts
19973
+ var MAX_CONCURRENT_AGENTS = 3;
19974
+ var DEFAULT_TIMEOUT_MS = 5 * 60 * 1e3;
19975
+ var AgentManager = class extends EventEmitter {
19976
+ activeAgents = /* @__PURE__ */ new Map();
19977
+ completedAgents = /* @__PURE__ */ new Map();
19978
+ abortControllers = /* @__PURE__ */ new Map();
19979
+ provider;
19980
+ toolRegistry;
19981
+ logger = getLogger();
19982
+ /**
19983
+ * Create a new AgentManager
19984
+ * @param provider - LLM provider for agent execution
19985
+ * @param toolRegistry - Tool registry for agent tool access
19986
+ */
19987
+ constructor(provider, toolRegistry) {
19988
+ super();
19989
+ this.provider = provider;
19990
+ this.toolRegistry = toolRegistry;
19991
+ }
19992
+ /**
19993
+ * Spawn a new subagent for a specific task
19994
+ *
19995
+ * @description Creates and executes a specialized subagent for the given task.
19996
+ * The agent will run autonomously, making LLM calls and executing tools until
19997
+ * it completes the task or reaches the maximum turn limit.
19998
+ *
19999
+ * @param type - Type of agent to spawn (explore, plan, test, debug, review, architect, security, tdd, refactor, e2e, docs, database)
20000
+ * @param task - Task description for the agent to execute
20001
+ * @param options - Optional spawn configuration including callbacks, abort signal, and timeout
20002
+ * @returns Promise resolving to the agent result with output and usage stats
20003
+ *
20004
+ * @example
20005
+ * ```typescript
20006
+ * const result = await manager.spawn('test', 'Write tests for UserService', {
20007
+ * onStatusChange: (agent) => console.log(`Status: ${agent.status}`),
20008
+ * onOutput: (agent, text) => console.log(text),
20009
+ * timeout: 60000, // 1 minute timeout
20010
+ * });
20011
+ * ```
20012
+ */
20013
+ async spawn(type, task, options = {}) {
20014
+ if (this.activeAgents.size >= MAX_CONCURRENT_AGENTS) {
20015
+ const error = `Cannot spawn agent: maximum concurrent agents (${MAX_CONCURRENT_AGENTS}) reached`;
20016
+ this.logger.warn(error);
20017
+ const failedAgent = this.createAgent(type, task);
20018
+ failedAgent.status = "failed";
20019
+ failedAgent.error = error;
20020
+ failedAgent.completedAt = /* @__PURE__ */ new Date();
20021
+ return {
20022
+ agent: failedAgent,
20023
+ success: false,
20024
+ output: error
20025
+ };
20026
+ }
20027
+ const agent = this.createAgent(type, task);
20028
+ this.activeAgents.set(agent.id, agent);
20029
+ options.onStatusChange?.(agent);
20030
+ const internalAbortController = new AbortController();
20031
+ this.abortControllers.set(agent.id, internalAbortController);
20032
+ if (options.signal) {
20033
+ if (options.signal.aborted) {
20034
+ internalAbortController.abort();
20035
+ } else {
20036
+ options.signal.addEventListener("abort", () => {
20037
+ internalAbortController.abort();
20038
+ });
20039
+ }
20040
+ }
20041
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
20042
+ const timeoutId = setTimeout(() => {
20043
+ if (this.activeAgents.has(agent.id)) {
20044
+ this.logger.warn(`Agent ${agent.id} timed out after ${timeout}ms`);
20045
+ internalAbortController.abort();
20046
+ agent.error = `Agent timed out after ${timeout}ms`;
20047
+ this.emitEvent("timeout", agent);
20048
+ }
20049
+ }, timeout);
20050
+ this.logger.info(`Spawned ${type} agent: ${agent.id}`, { task, timeout });
20051
+ this.emitEvent("spawn", agent);
20052
+ try {
20053
+ const result = await this.executeAgent(agent, {
20054
+ ...options,
20055
+ signal: internalAbortController.signal
20056
+ });
20057
+ clearTimeout(timeoutId);
20058
+ if (result.success) {
20059
+ this.emitEvent("complete", agent, result);
20060
+ } else if (agent.error?.includes("Aborted")) {
20061
+ this.emitEvent("cancel", agent, result);
20062
+ } else {
20063
+ this.emitEvent("fail", agent, result);
20064
+ }
20065
+ return result;
20066
+ } catch (error) {
20067
+ clearTimeout(timeoutId);
20068
+ const errorMessage = error instanceof Error ? error.message : String(error);
20069
+ agent.status = "failed";
20070
+ agent.error = errorMessage;
20071
+ agent.completedAt = /* @__PURE__ */ new Date();
20072
+ this.moveToCompleted(agent.id);
20073
+ this.abortControllers.delete(agent.id);
20074
+ options.onStatusChange?.(agent);
20075
+ this.logger.error(`Agent ${agent.id} failed unexpectedly`, { error: errorMessage });
20076
+ this.emitEvent("fail", agent);
20077
+ return {
20078
+ agent,
20079
+ success: false,
20080
+ output: errorMessage
20081
+ };
20082
+ }
20083
+ }
20084
+ /**
20085
+ * Cancel a running agent
20086
+ *
20087
+ * @description Cancels an active agent by triggering its abort signal.
20088
+ * The agent will stop at the next safe point (beginning of next iteration).
20089
+ *
20090
+ * @param agentId - ID of the agent to cancel
20091
+ * @returns True if the agent was cancelled, false if not found or already completed
20092
+ */
20093
+ cancel(agentId) {
20094
+ const controller = this.abortControllers.get(agentId);
20095
+ if (!controller) {
20096
+ this.logger.warn(`Cannot cancel agent ${agentId}: not found or already completed`);
20097
+ return false;
20098
+ }
20099
+ this.logger.info(`Cancelling agent ${agentId}`);
20100
+ controller.abort();
20101
+ return true;
20102
+ }
20103
+ /**
20104
+ * Get the status of a specific agent
20105
+ *
20106
+ * @description Returns the current status of an agent.
20107
+ *
20108
+ * @param agentId - ID of the agent
20109
+ * @returns The agent's status or undefined if not found
20110
+ */
20111
+ getStatus(agentId) {
20112
+ return this.getAgent(agentId)?.status;
20113
+ }
20114
+ /**
20115
+ * Get the current status of an agent
20116
+ *
20117
+ * @description Retrieves an agent by ID from either active or completed agents.
20118
+ *
20119
+ * @param agentId - Unique agent identifier (UUID)
20120
+ * @returns The agent if found, undefined otherwise
20121
+ */
20122
+ getAgent(agentId) {
20123
+ return this.activeAgents.get(agentId) ?? this.completedAgents.get(agentId);
20124
+ }
20125
+ /**
20126
+ * Get all active agents
20127
+ * @returns Array of currently running agents
20128
+ */
20129
+ getActiveAgents() {
20130
+ return Array.from(this.activeAgents.values());
20131
+ }
20132
+ /**
20133
+ * Get all completed agents
20134
+ * @returns Array of completed agents (succeeded or failed)
20135
+ */
20136
+ getCompletedAgents() {
20137
+ return Array.from(this.completedAgents.values());
20138
+ }
20139
+ /**
20140
+ * Get the number of active agents
20141
+ * @returns Count of running agents
20142
+ */
20143
+ getActiveCount() {
20144
+ return this.activeAgents.size;
20145
+ }
20146
+ /**
20147
+ * Check if more agents can be spawned
20148
+ * @returns True if under the concurrent limit
20149
+ */
20150
+ canSpawn() {
20151
+ return this.activeAgents.size < MAX_CONCURRENT_AGENTS;
20152
+ }
20153
+ /**
20154
+ * Clear completed agents from history
20155
+ */
20156
+ clearCompleted() {
20157
+ this.completedAgents.clear();
20158
+ this.logger.debug("Cleared completed agents history");
20159
+ }
20160
+ /**
20161
+ * Get available agent types with their descriptions
20162
+ *
20163
+ * @description Returns all supported agent types with their names, descriptions,
20164
+ * and configurations. Useful for building UI or help text.
20165
+ *
20166
+ * @returns Array of agent registry entries with type, name, description, and config
20167
+ */
20168
+ getAvailableAgentTypes() {
20169
+ return Object.keys(AGENT_NAMES).map((type) => ({
20170
+ type,
20171
+ name: AGENT_NAMES[type],
20172
+ description: AGENT_DESCRIPTIONS[type],
20173
+ config: getAgentConfig(type)
20174
+ }));
20175
+ }
20176
+ /**
20177
+ * Create a new agent instance
20178
+ */
20179
+ createAgent(type, task) {
20180
+ return {
20181
+ id: randomUUID(),
20182
+ type,
20183
+ status: "idle",
20184
+ task,
20185
+ createdAt: /* @__PURE__ */ new Date()
20186
+ };
20187
+ }
20188
+ /**
20189
+ * Execute an agent's task
20190
+ */
20191
+ async executeAgent(agent, options) {
20192
+ const config = getAgentConfig(agent.type);
20193
+ agent.status = "running";
20194
+ options.onStatusChange?.(agent);
20195
+ const tools = this.getToolsForAgent(config);
20196
+ const messages = [{ role: "user", content: agent.task }];
20197
+ let totalInputTokens = 0;
20198
+ let totalOutputTokens = 0;
20199
+ let finalOutput = "";
20200
+ let iteration = 0;
20201
+ const maxTurns = config.maxTurns ?? 10;
20202
+ while (iteration < maxTurns) {
20203
+ iteration++;
20204
+ if (options.signal?.aborted) {
20205
+ agent.status = "failed";
20206
+ agent.error = "Aborted by user";
20207
+ agent.completedAt = /* @__PURE__ */ new Date();
20208
+ this.moveToCompleted(agent.id);
20209
+ options.onStatusChange?.(agent);
20210
+ return {
20211
+ agent,
20212
+ success: false,
20213
+ output: "Agent execution was aborted",
20214
+ usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
20215
+ };
20216
+ }
20217
+ const response = await this.provider.chatWithTools(messages, {
20218
+ system: config.systemPrompt,
20219
+ tools,
20220
+ maxTokens: 4096
20221
+ });
20222
+ totalInputTokens += response.usage.inputTokens;
20223
+ totalOutputTokens += response.usage.outputTokens;
20224
+ if (response.content) {
20225
+ finalOutput += response.content;
20226
+ options.onOutput?.(agent, response.content);
20227
+ }
20228
+ if (!response.toolCalls || response.toolCalls.length === 0) {
20229
+ messages.push({ role: "assistant", content: response.content });
20230
+ break;
20231
+ }
20232
+ const toolResults = await this.executeToolCalls(response.toolCalls, config);
20233
+ const toolUses = response.toolCalls.map((tc) => ({
20234
+ type: "tool_use",
20235
+ id: tc.id,
20236
+ name: tc.name,
20237
+ input: tc.input,
20238
+ geminiThoughtSignature: tc.geminiThoughtSignature
20239
+ }));
20240
+ const assistantContent = response.content ? [{ type: "text", text: response.content }, ...toolUses] : toolUses;
20241
+ messages.push({ role: "assistant", content: assistantContent });
20242
+ messages.push({ role: "user", content: toolResults });
20243
+ this.logger.debug(`Agent ${agent.id} completed iteration ${iteration}`, {
20244
+ toolCalls: response.toolCalls.length
20245
+ });
20246
+ }
20247
+ agent.status = "completed";
20248
+ agent.result = finalOutput;
20249
+ agent.completedAt = /* @__PURE__ */ new Date();
20250
+ this.moveToCompleted(agent.id);
20251
+ options.onStatusChange?.(agent);
20252
+ this.logger.info(`Agent ${agent.id} completed`, {
20253
+ iterations: iteration,
20254
+ outputLength: finalOutput.length
20255
+ });
20256
+ return {
20257
+ agent,
20258
+ success: true,
20259
+ output: finalOutput,
20260
+ usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
20261
+ };
20262
+ }
20263
+ /**
20264
+ * Get tool definitions filtered for the agent's allowed tools
20265
+ */
20266
+ getToolsForAgent(config) {
20267
+ const allTools = this.toolRegistry.getToolDefinitionsForLLM();
20268
+ const allowedSet = new Set(config.tools);
20269
+ return allTools.filter((tool) => allowedSet.has(tool.name));
20270
+ }
20271
+ /**
20272
+ * Execute tool calls and return results
20273
+ */
20274
+ async executeToolCalls(toolCalls, config) {
20275
+ const results = [];
20276
+ const allowedTools = new Set(config.tools);
20277
+ for (const toolCall of toolCalls) {
20278
+ if (!allowedTools.has(toolCall.name)) {
20279
+ results.push({
20280
+ type: "tool_result",
20281
+ tool_use_id: toolCall.id,
20282
+ content: `Tool '${toolCall.name}' is not available to this agent type`,
20283
+ is_error: true
20284
+ });
20285
+ continue;
20286
+ }
20287
+ try {
20288
+ const result = await this.toolRegistry.execute(toolCall.name, toolCall.input);
20289
+ results.push({
20290
+ type: "tool_result",
20291
+ tool_use_id: toolCall.id,
20292
+ content: result.success ? String(result.data ?? "Success") : `Error: ${result.error}`,
20293
+ is_error: !result.success
20294
+ });
20295
+ } catch (error) {
20296
+ const errorMessage = error instanceof Error ? error.message : String(error);
20297
+ results.push({
20298
+ type: "tool_result",
20299
+ tool_use_id: toolCall.id,
20300
+ content: `Tool execution failed: ${errorMessage}`,
20301
+ is_error: true
20302
+ });
20303
+ }
20304
+ }
20305
+ return results;
20306
+ }
20307
+ /**
20308
+ * Move an agent from active to completed
20309
+ */
20310
+ moveToCompleted(agentId) {
20311
+ const agent = this.activeAgents.get(agentId);
20312
+ if (agent) {
20313
+ this.activeAgents.delete(agentId);
20314
+ this.completedAgents.set(agentId, agent);
20315
+ this.abortControllers.delete(agentId);
20316
+ }
20317
+ }
20318
+ /**
20319
+ * Emit an agent event
20320
+ */
20321
+ emitEvent(type, agent, result) {
20322
+ const event = { type, agent, result };
20323
+ this.emit(type, event);
20324
+ this.emit("agent", event);
20325
+ }
20326
+ };
20327
+
20328
+ // src/agents/provider-bridge.ts
20329
+ var agentProvider = null;
20330
+ var agentToolRegistry = null;
20331
+ var agentManagerInstance = null;
20332
+ function setAgentProvider(provider) {
20333
+ agentProvider = provider;
20334
+ agentManagerInstance = null;
20335
+ }
20336
+ function getAgentProvider() {
20337
+ return agentProvider;
20338
+ }
20339
+ function setAgentToolRegistry(registry) {
20340
+ agentToolRegistry = registry;
20341
+ agentManagerInstance = null;
20342
+ }
20343
+ function getAgentToolRegistry() {
20344
+ return agentToolRegistry;
20345
+ }
20346
+ function getAgentManager() {
20347
+ if (!agentProvider || !agentToolRegistry) {
20348
+ return null;
20349
+ }
20350
+ if (!agentManagerInstance) {
20351
+ agentManagerInstance = new AgentManager(agentProvider, agentToolRegistry);
20352
+ }
20353
+ return agentManagerInstance;
20354
+ }
20355
+
20356
+ // src/runtime/agent-runtime.ts
20357
+ init_env();
19349
20358
  init_errors();
19350
20359
  init_allowed_paths();
19351
20360
  function levenshtein(a, b) {
@@ -20290,7 +21299,7 @@ function escapeRegex(str) {
20290
21299
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20291
21300
  }
20292
21301
  init_errors();
20293
- var DEFAULT_TIMEOUT_MS = 12e4;
21302
+ var DEFAULT_TIMEOUT_MS2 = 12e4;
20294
21303
  var MAX_OUTPUT_SIZE = 1024 * 1024;
20295
21304
  var DANGEROUS_PATTERNS_FULL = [
20296
21305
  { pattern: /\brm\s+-rf\s+\/(?!\w)/, rule: "rm -rf on root filesystem" },
@@ -20412,7 +21421,7 @@ Examples:
20412
21421
  }
20413
21422
  }
20414
21423
  const startTime = performance.now();
20415
- const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS;
21424
+ const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS2;
20416
21425
  const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
20417
21426
  const heartbeat = new CommandHeartbeat2({
20418
21427
  onUpdate: (stats) => {
@@ -21110,54 +22119,6 @@ var simpleAutoCommitTool = defineTool({
21110
22119
  }
21111
22120
  });
21112
22121
  var gitSimpleTools = [checkProtectedBranchTool, simpleAutoCommitTool];
21113
-
21114
- // src/cli/repl/agents/manager.ts
21115
- init_logger();
21116
- var AGENT_NAMES = {
21117
- explore: "Explorer",
21118
- plan: "Planner",
21119
- test: "Tester",
21120
- debug: "Debugger",
21121
- review: "Reviewer",
21122
- architect: "Architect",
21123
- security: "Security Auditor",
21124
- tdd: "TDD Guide",
21125
- refactor: "Refactorer",
21126
- e2e: "E2E Tester",
21127
- docs: "Docs Writer",
21128
- database: "Database Engineer"
21129
- };
21130
- var AGENT_DESCRIPTIONS = {
21131
- explore: "Search the codebase to answer questions and gather information",
21132
- plan: "Design implementation approaches and create detailed plans",
21133
- test: "Write and run tests to ensure code quality",
21134
- debug: "Analyze errors and fix issues",
21135
- review: "Review code for quality and best practices",
21136
- architect: "Design system architecture and create architectural decision records",
21137
- security: "Audit code for security vulnerabilities using OWASP Top 10",
21138
- tdd: "Drive development with test-first methodology and RED-GREEN-REFACTOR cycle",
21139
- refactor: "Improve code structure and quality without changing behavior",
21140
- e2e: "Write and run end-to-end tests covering full user workflows",
21141
- docs: "Generate and maintain documentation for code, APIs, and architecture",
21142
- database: "Design database schemas, write migrations, and optimize queries"
21143
- };
21144
-
21145
- // src/agents/provider-bridge.ts
21146
- var agentProvider = null;
21147
- var agentToolRegistry = null;
21148
- function getAgentProvider() {
21149
- return agentProvider;
21150
- }
21151
- function getAgentToolRegistry() {
21152
- return agentToolRegistry;
21153
- }
21154
- function getAgentManager() {
21155
- {
21156
- return null;
21157
- }
21158
- }
21159
-
21160
- // src/tools/simple-agent.ts
21161
22122
  var AGENT_TYPES = [
21162
22123
  "explore",
21163
22124
  "plan",
@@ -21270,7 +22231,7 @@ var checkAgentCapabilityTool = defineTool({
21270
22231
  async execute() {
21271
22232
  const provider = getAgentProvider();
21272
22233
  const toolRegistry = getAgentToolRegistry();
21273
- const isReady = provider !== null;
22234
+ const isReady = provider !== null && toolRegistry !== null;
21274
22235
  const agentTypes = Object.entries(AGENT_DESCRIPTIONS).map(([type, description]) => ({
21275
22236
  type,
21276
22237
  name: AGENT_NAMES[type],
@@ -21284,12 +22245,12 @@ var checkAgentCapabilityTool = defineTool({
21284
22245
  ready: isReady,
21285
22246
  availableTypes: agentTypes,
21286
22247
  features: {
21287
- taskDelegation: "requires provider initialization",
21288
- parallelSpawn: "requires provider initialization",
21289
- multiTurnToolUse: "requires provider initialization",
21290
- specializedAgents: "requires provider initialization"
22248
+ taskDelegation: isReady ? "ready" : "requires provider initialization",
22249
+ parallelSpawn: isReady ? "ready" : "requires provider initialization",
22250
+ multiTurnToolUse: isReady ? "ready" : "requires provider initialization",
22251
+ specializedAgents: isReady ? "ready" : "requires provider initialization"
21291
22252
  },
21292
- status: "Provider not initialized. Call setAgentProvider() during startup."
22253
+ status: isReady ? "Multi-agent system is ready with 12 specialized agent types." : "Provider not initialized. Call setAgentProvider() during startup."
21293
22254
  }),
21294
22255
  stderr: "",
21295
22256
  exitCode: 0,
@@ -30646,6 +31607,235 @@ function getMCPServerManager() {
30646
31607
 
30647
31608
  // src/mcp/tools.ts
30648
31609
  init_errors2();
31610
+ var DEFAULT_OPTIONS = {
31611
+ namePrefix: "mcp",
31612
+ category: "deploy",
31613
+ requestTimeout: 6e4
31614
+ };
31615
+ function buildMcpToolDescription(serverName, tool) {
31616
+ const base = tool.description || `Tool '${tool.name}' exposed by MCP server '${serverName}'`;
31617
+ const lowerServer = serverName.toLowerCase();
31618
+ if (lowerServer.includes("atlassian") || lowerServer.includes("jira") || lowerServer.includes("confluence")) {
31619
+ return `${base}. Use this MCP tool for Atlassian/Jira/Confluence data. Prefer it over direct web_fetch or http_fetch for Atlassian content.`;
31620
+ }
31621
+ return `${base}. Exposed by MCP server '${serverName}'. Prefer this MCP tool over generic web/http fetch when accessing data from that connected service.`;
31622
+ }
31623
+ function jsonSchemaToZod(schema) {
31624
+ if (schema.enum && Array.isArray(schema.enum)) {
31625
+ const values = schema.enum;
31626
+ if (values.length > 0 && values.every((v) => typeof v === "string")) {
31627
+ return z.enum(values);
31628
+ }
31629
+ const literals = values.map((v) => z.literal(v));
31630
+ if (literals.length < 2) {
31631
+ return literals[0] ?? z.any();
31632
+ }
31633
+ return z.union(literals);
31634
+ }
31635
+ if (schema.const !== void 0) {
31636
+ return z.literal(schema.const);
31637
+ }
31638
+ if (schema.oneOf && Array.isArray(schema.oneOf)) {
31639
+ const schemas = schema.oneOf.map(jsonSchemaToZod);
31640
+ if (schemas.length >= 2) {
31641
+ return z.union(schemas);
31642
+ }
31643
+ return schemas[0] ?? z.unknown();
31644
+ }
31645
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
31646
+ const schemas = schema.anyOf.map(jsonSchemaToZod);
31647
+ if (schemas.length >= 2) {
31648
+ return z.union(schemas);
31649
+ }
31650
+ return schemas[0] ?? z.unknown();
31651
+ }
31652
+ if (schema.allOf && Array.isArray(schema.allOf)) {
31653
+ const schemas = schema.allOf.map(jsonSchemaToZod);
31654
+ return schemas.reduce((acc, s) => z.intersection(acc, s));
31655
+ }
31656
+ const type = schema.type;
31657
+ const makeNullable = (s) => {
31658
+ if (schema.nullable === true) return s.nullable();
31659
+ return s;
31660
+ };
31661
+ switch (type) {
31662
+ case "string": {
31663
+ let s = z.string();
31664
+ if (schema.format) {
31665
+ switch (schema.format) {
31666
+ case "uri":
31667
+ case "url":
31668
+ s = z.string().url();
31669
+ break;
31670
+ case "email":
31671
+ s = z.string().email();
31672
+ break;
31673
+ case "date-time":
31674
+ case "datetime":
31675
+ s = z.string().datetime();
31676
+ break;
31677
+ }
31678
+ }
31679
+ if (typeof schema.minLength === "number") s = s.min(schema.minLength);
31680
+ if (typeof schema.maxLength === "number") s = s.max(schema.maxLength);
31681
+ return makeNullable(s);
31682
+ }
31683
+ case "number": {
31684
+ let n = z.number();
31685
+ if (typeof schema.minimum === "number") n = n.min(schema.minimum);
31686
+ if (typeof schema.maximum === "number") n = n.max(schema.maximum);
31687
+ if (typeof schema.exclusiveMinimum === "number") n = n.gt(schema.exclusiveMinimum);
31688
+ if (typeof schema.exclusiveMaximum === "number") n = n.lt(schema.exclusiveMaximum);
31689
+ return makeNullable(n);
31690
+ }
31691
+ case "integer": {
31692
+ let n = z.number().int();
31693
+ if (typeof schema.minimum === "number") n = n.min(schema.minimum);
31694
+ if (typeof schema.maximum === "number") n = n.max(schema.maximum);
31695
+ return makeNullable(n);
31696
+ }
31697
+ case "boolean":
31698
+ return makeNullable(z.boolean());
31699
+ case "null":
31700
+ return z.null();
31701
+ case "array":
31702
+ if (schema.items) {
31703
+ const itemSchema = jsonSchemaToZod(schema.items);
31704
+ let arr = z.array(itemSchema);
31705
+ if (typeof schema.minItems === "number") arr = arr.min(schema.minItems);
31706
+ if (typeof schema.maxItems === "number") arr = arr.max(schema.maxItems);
31707
+ return makeNullable(arr);
31708
+ }
31709
+ return makeNullable(z.array(z.unknown()));
31710
+ case "object": {
31711
+ const properties = schema.properties;
31712
+ const required = schema.required;
31713
+ if (!properties) {
31714
+ return makeNullable(z.record(z.string(), z.unknown()));
31715
+ }
31716
+ const shape = {};
31717
+ for (const [key, propSchema] of Object.entries(properties)) {
31718
+ let fieldSchema = jsonSchemaToZod(propSchema);
31719
+ if (!required?.includes(key)) {
31720
+ fieldSchema = fieldSchema.optional();
31721
+ }
31722
+ if (propSchema.description && typeof propSchema.description === "string") {
31723
+ fieldSchema = fieldSchema.describe(propSchema.description);
31724
+ }
31725
+ shape[key] = fieldSchema;
31726
+ }
31727
+ return makeNullable(z.object(shape));
31728
+ }
31729
+ default:
31730
+ if (Array.isArray(schema.type)) {
31731
+ const types = schema.type;
31732
+ if (types.includes("null")) {
31733
+ const nonNullType = types.find((t) => t !== "null");
31734
+ if (nonNullType) {
31735
+ return jsonSchemaToZod({ ...schema, type: nonNullType }).nullable();
31736
+ }
31737
+ }
31738
+ }
31739
+ return z.unknown();
31740
+ }
31741
+ }
31742
+ function createToolParametersSchema(tool) {
31743
+ const schema = tool.inputSchema;
31744
+ if (!schema || schema.type !== "object") {
31745
+ return z.object({});
31746
+ }
31747
+ return jsonSchemaToZod(schema);
31748
+ }
31749
+ function formatToolResult(result) {
31750
+ if (result.isError) {
31751
+ throw new Error(result.content.map((c) => c.text || "").join("\n"));
31752
+ }
31753
+ return result.content.map((item) => {
31754
+ switch (item.type) {
31755
+ case "text":
31756
+ return item.text || "";
31757
+ case "image":
31758
+ return `[Image: ${item.mimeType || "unknown"}]`;
31759
+ case "resource":
31760
+ return `[Resource: ${item.resource?.uri || "unknown"}]`;
31761
+ default:
31762
+ return "";
31763
+ }
31764
+ }).filter(Boolean).join("\n");
31765
+ }
31766
+ function createToolName(serverName, toolName, prefix) {
31767
+ return `${prefix}_${serverName}_${toolName}`.replace(/[^a-zA-Z0-9_]/g, "_");
31768
+ }
31769
+ function wrapMCPTool(tool, serverName, client, options = {}) {
31770
+ const opts = { ...DEFAULT_OPTIONS, ...options };
31771
+ const wrappedName = createToolName(serverName, tool.name, opts.namePrefix);
31772
+ const parametersSchema = createToolParametersSchema(tool);
31773
+ const cocoTool = {
31774
+ name: wrappedName,
31775
+ description: buildMcpToolDescription(serverName, tool),
31776
+ category: opts.category,
31777
+ parameters: parametersSchema,
31778
+ execute: async (params) => {
31779
+ const timeout = opts.requestTimeout;
31780
+ try {
31781
+ const result = await Promise.race([
31782
+ client.callTool({
31783
+ name: tool.name,
31784
+ arguments: params
31785
+ }),
31786
+ new Promise((_, reject) => {
31787
+ setTimeout(() => {
31788
+ reject(new MCPTimeoutError(`Tool '${tool.name}' timed out after ${timeout}ms`));
31789
+ }, timeout);
31790
+ })
31791
+ ]);
31792
+ return formatToolResult(result);
31793
+ } catch (error) {
31794
+ if (error instanceof MCPError) {
31795
+ throw error;
31796
+ }
31797
+ throw new MCPError(
31798
+ -32603,
31799
+ `Tool execution failed: ${error instanceof Error ? error.message : "Unknown error"}`
31800
+ );
31801
+ }
31802
+ }
31803
+ };
31804
+ const wrapped = {
31805
+ originalTool: tool,
31806
+ serverName,
31807
+ wrappedName
31808
+ };
31809
+ return { tool: cocoTool, wrapped };
31810
+ }
31811
+ function wrapMCPTools(tools, serverName, client, options = {}) {
31812
+ const cocoTools = [];
31813
+ const wrappedTools = [];
31814
+ for (const tool of tools) {
31815
+ const { tool: cocoTool, wrapped } = wrapMCPTool(tool, serverName, client, options);
31816
+ cocoTools.push(cocoTool);
31817
+ wrappedTools.push(wrapped);
31818
+ }
31819
+ return { tools: cocoTools, wrapped: wrappedTools };
31820
+ }
31821
+ async function createToolsFromMCPServer(serverName, client, options = {}) {
31822
+ if (!client.isConnected()) {
31823
+ await client.initialize({
31824
+ protocolVersion: "2024-11-05",
31825
+ capabilities: {},
31826
+ clientInfo: { name: "coco-mcp-client", version: "0.2.0" }
31827
+ });
31828
+ }
31829
+ const { tools } = await client.listTools();
31830
+ return wrapMCPTools(tools, serverName, client, options);
31831
+ }
31832
+ async function registerMCPTools(registry, serverName, client, options = {}) {
31833
+ const { tools, wrapped } = await createToolsFromMCPServer(serverName, client, options);
31834
+ for (const tool of tools) {
31835
+ registry.register(tool);
31836
+ }
31837
+ return wrapped;
31838
+ }
30649
31839
 
30650
31840
  // src/tools/mcp.ts
30651
31841
  async function loadConfiguredServers(projectPath) {
@@ -30742,6 +31932,10 @@ built-in MCP OAuth browser login flow. Do not ask the user for raw tokens when t
30742
31932
  await manager.stopServer(target.name);
30743
31933
  }
30744
31934
  const connection = await manager.startServer(target);
31935
+ const toolRegistry = getAgentToolRegistry();
31936
+ if (toolRegistry) {
31937
+ await registerMCPTools(toolRegistry, connection.name, connection.client);
31938
+ }
30745
31939
  let tools;
30746
31940
  if (includeTools) {
30747
31941
  try {
@@ -30911,11 +32105,1194 @@ function createFullToolRegistry() {
30911
32105
  return registry;
30912
32106
  }
30913
32107
 
32108
+ // src/runtime/agent-modes.ts
32109
+ var AGENT_MODES = {
32110
+ ask: {
32111
+ id: "ask",
32112
+ label: "Ask",
32113
+ description: "Answer questions and explain code without modifying files.",
32114
+ readOnly: true,
32115
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
32116
+ requiresVerification: false
32117
+ },
32118
+ plan: {
32119
+ id: "plan",
32120
+ label: "Plan",
32121
+ description: "Explore and produce an implementation plan with read-only tools.",
32122
+ readOnly: true,
32123
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
32124
+ requiresVerification: false
32125
+ },
32126
+ build: {
32127
+ id: "build",
32128
+ label: "Build",
32129
+ description: "Implement code changes and verify them.",
32130
+ readOnly: false,
32131
+ preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
32132
+ requiresVerification: true
32133
+ },
32134
+ debug: {
32135
+ id: "debug",
32136
+ label: "Debug",
32137
+ description: "Reproduce failures, trace root cause, patch, and verify.",
32138
+ readOnly: false,
32139
+ preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
32140
+ requiresVerification: true
32141
+ },
32142
+ review: {
32143
+ id: "review",
32144
+ label: "Review",
32145
+ description: "Inspect code quality, security, behavior changes, and test gaps.",
32146
+ readOnly: true,
32147
+ preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
32148
+ requiresVerification: false
32149
+ },
32150
+ architect: {
32151
+ id: "architect",
32152
+ label: "Architect",
32153
+ description: "Design architecture and split work for architect/editor execution.",
32154
+ readOnly: true,
32155
+ preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
32156
+ requiresVerification: false
32157
+ }
32158
+ };
32159
+ function getAgentMode(mode) {
32160
+ return AGENT_MODES[mode];
32161
+ }
32162
+ function listAgentModes() {
32163
+ return Object.values(AGENT_MODES);
32164
+ }
32165
+ function isAgentMode(value) {
32166
+ return value in AGENT_MODES;
32167
+ }
32168
+
32169
+ // src/runtime/default-turn-runner.ts
32170
+ var DefaultRuntimeTurnRunner = class {
32171
+ async run(input, context) {
32172
+ const messages = [
32173
+ ...context.session.messages,
32174
+ {
32175
+ role: "user",
32176
+ content: input.content
32177
+ }
32178
+ ];
32179
+ const response = await context.provider.chat(messages, {
32180
+ model: input.options?.model,
32181
+ maxTokens: input.options?.maxTokens,
32182
+ temperature: input.options?.temperature,
32183
+ stopSequences: input.options?.stopSequences,
32184
+ system: context.session.instructions ?? input.options?.system,
32185
+ timeout: input.options?.timeout,
32186
+ signal: input.options?.signal,
32187
+ thinking: input.options?.thinking
32188
+ });
32189
+ return {
32190
+ sessionId: context.session.id,
32191
+ content: response.content,
32192
+ usage: response.usage,
32193
+ model: response.model,
32194
+ mode: context.session.mode
32195
+ };
32196
+ }
32197
+ };
32198
+ function createDefaultRuntimeTurnRunner() {
32199
+ return new DefaultRuntimeTurnRunner();
32200
+ }
32201
+ var InMemoryEventLog = class {
32202
+ events = [];
32203
+ record(type, data = {}) {
32204
+ const event = {
32205
+ id: randomUUID(),
32206
+ type,
32207
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
32208
+ data
32209
+ };
32210
+ this.events.push(event);
32211
+ return event;
32212
+ }
32213
+ list() {
32214
+ return [...this.events];
32215
+ }
32216
+ count() {
32217
+ return this.events.length;
32218
+ }
32219
+ clear() {
32220
+ this.events = [];
32221
+ }
32222
+ };
32223
+ var FileEventLog = class {
32224
+ constructor(filePath) {
32225
+ this.filePath = filePath;
32226
+ try {
32227
+ mkdirSync(dirname(filePath), { recursive: true });
32228
+ } catch {
32229
+ this.writable = false;
32230
+ }
32231
+ }
32232
+ filePath;
32233
+ memory = new InMemoryEventLog();
32234
+ writable = true;
32235
+ record(type, data = {}) {
32236
+ const event = this.memory.record(type, data);
32237
+ if (this.writable) {
32238
+ try {
32239
+ appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
32240
+ } catch {
32241
+ this.writable = false;
32242
+ }
32243
+ }
32244
+ return event;
32245
+ }
32246
+ list() {
32247
+ if (!this.writable) return this.memory.list();
32248
+ try {
32249
+ const raw = readFileSync(this.filePath, "utf-8");
32250
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
32251
+ try {
32252
+ return [JSON.parse(line)];
32253
+ } catch {
32254
+ return [];
32255
+ }
32256
+ });
32257
+ } catch {
32258
+ return this.memory.list();
32259
+ }
32260
+ }
32261
+ count() {
32262
+ return this.list().length;
32263
+ }
32264
+ clear() {
32265
+ this.memory.clear();
32266
+ if (this.writable) {
32267
+ try {
32268
+ writeFileSync(this.filePath, "", "utf-8");
32269
+ } catch {
32270
+ this.writable = false;
32271
+ }
32272
+ }
32273
+ }
32274
+ };
32275
+ function createEventLog() {
32276
+ return new InMemoryEventLog();
32277
+ }
32278
+ function createFileEventLog(filePath) {
32279
+ return new FileEventLog(filePath);
32280
+ }
32281
+
32282
+ // src/runtime/permission-policy.ts
32283
+ var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
32284
+ var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
32285
+ var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
32286
+ "glob",
32287
+ "read_file",
32288
+ "list_dir",
32289
+ "tree",
32290
+ "grep",
32291
+ "find_in_file",
32292
+ "semantic_search",
32293
+ "codebase_map",
32294
+ "repo_context",
32295
+ "lsp_status",
32296
+ "lsp_document_symbols",
32297
+ "lsp_workspace_symbols",
32298
+ "lsp_definition",
32299
+ "lsp_references",
32300
+ "git_status",
32301
+ "git_log",
32302
+ "git_diff",
32303
+ "git_show",
32304
+ "git_branch",
32305
+ "recall_memory",
32306
+ "list_memories",
32307
+ "list_checkpoints",
32308
+ "spawnSimpleAgent",
32309
+ "checkAgentCapability"
32310
+ ]);
32311
+ var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
32312
+ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
32313
+ "bash_exec",
32314
+ "write_file",
32315
+ "edit_file",
32316
+ "delete_file",
32317
+ "restore_checkpoint",
32318
+ "git_commit",
32319
+ "git_push"
32320
+ ]);
32321
+ function riskForTool(tool) {
32322
+ if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
32323
+ if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
32324
+ if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
32325
+ if (tool.category === "web") return "network";
32326
+ if (WRITE_CATEGORIES.has(tool.category)) return "write";
32327
+ if (tool.category === "quality") return "write";
32328
+ return "read-only";
32329
+ }
32330
+ var DefaultPermissionPolicy = class {
32331
+ canExecuteTool(mode, tool) {
32332
+ const definition = getAgentMode(mode);
32333
+ const risk = riskForTool(tool);
32334
+ const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
32335
+ if (definition.readOnly && !readOnlyTool) {
32336
+ return {
32337
+ allowed: false,
32338
+ reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
32339
+ risk
32340
+ };
32341
+ }
32342
+ if (risk === "destructive") {
32343
+ return {
32344
+ allowed: true,
32345
+ requiresConfirmation: true,
32346
+ reason: `${tool.name} can change repository state and should be confirmed.`,
32347
+ risk
32348
+ };
32349
+ }
32350
+ return { allowed: true, risk };
32351
+ }
32352
+ canExecuteToolInput(mode, tool, input) {
32353
+ if (tool.name !== "run_linter") {
32354
+ return this.canExecuteTool(mode, tool);
32355
+ }
32356
+ const definition = getAgentMode(mode);
32357
+ const fixEnabled = input["fix"] === true;
32358
+ const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
32359
+ if (definition.readOnly && fixEnabled) {
32360
+ return {
32361
+ allowed: false,
32362
+ reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
32363
+ risk: "write"
32364
+ };
32365
+ }
32366
+ return decision;
32367
+ }
32368
+ };
32369
+ function createPermissionPolicy() {
32370
+ return new DefaultPermissionPolicy();
32371
+ }
32372
+
32373
+ // src/runtime/provider-registry.ts
32374
+ init_catalog();
32375
+ var ProviderRegistry = class {
32376
+ listProviders() {
32377
+ return Object.values(PROVIDER_CATALOG);
32378
+ }
32379
+ getProvider(provider) {
32380
+ return getProviderCatalogEntry(provider);
32381
+ }
32382
+ listModels(provider) {
32383
+ return this.getProvider(provider).models;
32384
+ }
32385
+ getModel(provider, model2) {
32386
+ return getCatalogModel(provider, model2);
32387
+ }
32388
+ getDefaultModel(provider) {
32389
+ return getCatalogDefaultModel(provider);
32390
+ }
32391
+ getRecommendedModel(provider) {
32392
+ return getCatalogRecommendedModel(provider);
32393
+ }
32394
+ getCapability(provider, model2) {
32395
+ return getProviderRuntimeCapability(provider, model2);
32396
+ }
32397
+ async createProvider(provider, config = {}) {
32398
+ return createProvider(provider, config);
32399
+ }
32400
+ async probe(provider, model2, checkAvailability) {
32401
+ return probeProviderRuntimeCapability(provider, model2, checkAvailability);
32402
+ }
32403
+ };
32404
+ function createProviderRegistry() {
32405
+ return new ProviderRegistry();
32406
+ }
32407
+ function createSessionId() {
32408
+ return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
32409
+ }
32410
+ function cloneSession(session) {
32411
+ return structuredClone(session);
32412
+ }
32413
+ var InMemoryRuntimeSessionStore = class {
32414
+ sessions = /* @__PURE__ */ new Map();
32415
+ create(options = {}) {
32416
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32417
+ const session = {
32418
+ id: options.id ?? createSessionId(),
32419
+ createdAt: now,
32420
+ updatedAt: now,
32421
+ mode: options.mode ?? "ask",
32422
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
32423
+ instructions: options.instructions,
32424
+ metadata: { ...options.metadata }
32425
+ };
32426
+ this.sessions.set(session.id, cloneSession(session));
32427
+ return cloneSession(session);
32428
+ }
32429
+ get(id) {
32430
+ const session = this.sessions.get(id);
32431
+ return session ? cloneSession(session) : void 0;
32432
+ }
32433
+ update(session) {
32434
+ const updated = {
32435
+ ...session,
32436
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
32437
+ messages: session.messages.map((message) => ({ ...message })),
32438
+ metadata: { ...session.metadata }
32439
+ };
32440
+ this.sessions.set(updated.id, cloneSession(updated));
32441
+ return cloneSession(updated);
32442
+ }
32443
+ list() {
32444
+ return [...this.sessions.values()].map(cloneSession);
32445
+ }
32446
+ delete(id) {
32447
+ return this.sessions.delete(id);
32448
+ }
32449
+ };
32450
+ var FileRuntimeSessionStore = class {
32451
+ constructor(filePath) {
32452
+ this.filePath = filePath;
32453
+ mkdirSync(dirname(filePath), { recursive: true });
32454
+ this.sessions = this.readSessionsFromDisk();
32455
+ }
32456
+ filePath;
32457
+ sessions = /* @__PURE__ */ new Map();
32458
+ create(options = {}) {
32459
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32460
+ const session = {
32461
+ id: options.id ?? createSessionId(),
32462
+ createdAt: now,
32463
+ updatedAt: now,
32464
+ mode: options.mode ?? "ask",
32465
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
32466
+ instructions: options.instructions,
32467
+ metadata: { ...options.metadata }
32468
+ };
32469
+ const sessions = this.readSessionsFromDisk();
32470
+ sessions.set(session.id, cloneSession(session));
32471
+ this.sessions = sessions;
32472
+ this.persist(sessions);
32473
+ return cloneSession(session);
32474
+ }
32475
+ get(id) {
32476
+ this.sessions = this.readSessionsFromDisk();
32477
+ const session = this.sessions.get(id);
32478
+ return session ? cloneSession(session) : void 0;
32479
+ }
32480
+ update(session) {
32481
+ const updated = {
32482
+ ...session,
32483
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
32484
+ messages: session.messages.map((message) => ({ ...message })),
32485
+ metadata: { ...session.metadata }
32486
+ };
32487
+ const sessions = this.readSessionsFromDisk();
32488
+ sessions.set(updated.id, cloneSession(updated));
32489
+ this.sessions = sessions;
32490
+ this.persist(sessions);
32491
+ return cloneSession(updated);
32492
+ }
32493
+ list() {
32494
+ this.sessions = this.readSessionsFromDisk();
32495
+ return [...this.sessions.values()].map(cloneSession);
32496
+ }
32497
+ delete(id) {
32498
+ const sessions = this.readSessionsFromDisk();
32499
+ const deleted = sessions.delete(id);
32500
+ this.sessions = sessions;
32501
+ if (deleted) this.persist(sessions);
32502
+ return deleted;
32503
+ }
32504
+ readSessionsFromDisk() {
32505
+ let raw;
32506
+ try {
32507
+ raw = readFileSync(this.filePath, "utf-8");
32508
+ } catch (error) {
32509
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
32510
+ return /* @__PURE__ */ new Map();
32511
+ }
32512
+ throw error;
32513
+ }
32514
+ if (!raw.trim()) return /* @__PURE__ */ new Map();
32515
+ const parsed = JSON.parse(raw);
32516
+ if (parsed.version !== 1 || !Array.isArray(parsed.sessions)) {
32517
+ throw new Error(`Unsupported runtime session store format: ${this.filePath}`);
32518
+ }
32519
+ return new Map(parsed.sessions.map((session) => [session.id, cloneSession(session)]));
32520
+ }
32521
+ persist(sessions) {
32522
+ const payload = {
32523
+ version: 1,
32524
+ sessions: [...sessions.values()].map(cloneSession)
32525
+ };
32526
+ const tempPath = `${this.filePath}.${randomUUID()}.tmp`;
32527
+ writeFileSync(tempPath, JSON.stringify(payload, null, 2) + "\n", "utf-8");
32528
+ renameSync(tempPath, this.filePath);
32529
+ }
32530
+ };
32531
+ function createRuntimeSessionStore() {
32532
+ return new InMemoryRuntimeSessionStore();
32533
+ }
32534
+ function createFileRuntimeSessionStore(filePath) {
32535
+ return new FileRuntimeSessionStore(filePath);
32536
+ }
32537
+
32538
+ // src/runtime/workflow-registry.ts
32539
+ function cloneWorkflow(workflow) {
32540
+ return {
32541
+ ...workflow,
32542
+ checks: [...workflow.checks],
32543
+ steps: workflow.steps.map((step) => ({
32544
+ ...step,
32545
+ requiredTools: [...step.requiredTools]
32546
+ }))
32547
+ };
32548
+ }
32549
+ var WorkflowCatalog = class {
32550
+ workflows = /* @__PURE__ */ new Map();
32551
+ constructor(workflows = DEFAULT_WORKFLOWS) {
32552
+ for (const workflow of workflows) {
32553
+ this.register(workflow);
32554
+ }
32555
+ }
32556
+ register(workflow) {
32557
+ this.workflows.set(workflow.id, cloneWorkflow(workflow));
32558
+ }
32559
+ get(id) {
32560
+ const workflow = this.workflows.get(id);
32561
+ return workflow ? cloneWorkflow(workflow) : void 0;
32562
+ }
32563
+ list() {
32564
+ return [...this.workflows.values()].map(cloneWorkflow).sort((a, b) => a.id.localeCompare(b.id));
32565
+ }
32566
+ createPlan(workflowId, input, eventLog) {
32567
+ const workflow = this.get(workflowId);
32568
+ if (!workflow) {
32569
+ throw new Error(`Unknown workflow: ${workflowId}`);
32570
+ }
32571
+ const plan = {
32572
+ id: `${workflowId}-${Date.now().toString(36)}`,
32573
+ workflowId,
32574
+ input,
32575
+ status: "planned",
32576
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
32577
+ };
32578
+ eventLog?.record("workflow.planned", {
32579
+ workflowId,
32580
+ planId: plan.id,
32581
+ replayable: workflow.replayable,
32582
+ checks: workflow.checks
32583
+ });
32584
+ return plan;
32585
+ }
32586
+ };
32587
+ var DEFAULT_WORKFLOWS = [
32588
+ {
32589
+ id: "architect-editor-verifier",
32590
+ name: "Architect / Editor / Verifier",
32591
+ description: "Plan read-only, apply approved changes, then verify and summarize risks.",
32592
+ inputSchema: "task: string; approvedPlan?: string",
32593
+ outputKind: "patch",
32594
+ replayable: true,
32595
+ checks: ["pnpm check", "diff summary", "review risks"],
32596
+ steps: [
32597
+ {
32598
+ id: "architect",
32599
+ description: "Inspect context and produce a read-only implementation plan.",
32600
+ requiredTools: ["repo_context", "read_file", "git_diff"],
32601
+ risk: "read-only"
32602
+ },
32603
+ {
32604
+ id: "editor",
32605
+ description: "Apply the approved plan without reinterpreting the objective.",
32606
+ requiredTools: ["read_file", "edit_file", "write_file"],
32607
+ risk: "write"
32608
+ },
32609
+ {
32610
+ id: "verifier",
32611
+ description: "Run checks, review diff, and report residual risk.",
32612
+ requiredTools: ["bash_exec", "git_diff", "review_code"],
32613
+ risk: "destructive"
32614
+ }
32615
+ ]
32616
+ },
32617
+ {
32618
+ id: "provider-diagnosis",
32619
+ name: "Provider Diagnosis",
32620
+ description: "Probe provider/model capabilities, endpoint strategy, credentials, and fallbacks.",
32621
+ inputSchema: "provider?: string; model?: string; live?: boolean",
32622
+ outputKind: "json",
32623
+ replayable: true,
32624
+ checks: ["provider capability matrix", "optional live probe"],
32625
+ steps: [
32626
+ {
32627
+ id: "capability",
32628
+ description: "Resolve catalog metadata and runtime endpoint strategy.",
32629
+ requiredTools: [],
32630
+ risk: "read-only"
32631
+ },
32632
+ {
32633
+ id: "fallbacks",
32634
+ description: "Suggest fallback provider/model choices when unsupported.",
32635
+ requiredTools: [],
32636
+ risk: "read-only"
32637
+ }
32638
+ ]
32639
+ },
32640
+ {
32641
+ id: "review-pr",
32642
+ name: "Review PR",
32643
+ description: "Review a branch or PR read-only and emit severity-ranked findings.",
32644
+ inputSchema: "target: string",
32645
+ outputKind: "markdown",
32646
+ replayable: true,
32647
+ checks: ["git diff", "tests gap review", "security review"],
32648
+ steps: [
32649
+ {
32650
+ id: "collect-diff",
32651
+ description: "Collect PR diff and related context.",
32652
+ requiredTools: ["git_diff", "repo_context"],
32653
+ risk: "read-only"
32654
+ },
32655
+ {
32656
+ id: "findings",
32657
+ description: "Produce prioritized findings with file and line references.",
32658
+ requiredTools: ["read_file", "review_code"],
32659
+ risk: "read-only"
32660
+ }
32661
+ ]
32662
+ },
32663
+ {
32664
+ id: "best-of-n",
32665
+ name: "Best Of N",
32666
+ description: "Run multiple isolated attempts, score them, and select a winning patch.",
32667
+ inputSchema: "task: string; attempts: number",
32668
+ outputKind: "patch",
32669
+ replayable: true,
32670
+ checks: ["worktree isolation", "checks pass", "diff risk score"],
32671
+ steps: [
32672
+ {
32673
+ id: "fanout",
32674
+ description: "Create isolated attempts in temporary worktrees.",
32675
+ requiredTools: ["git_status", "bash_exec"],
32676
+ risk: "destructive"
32677
+ },
32678
+ {
32679
+ id: "score",
32680
+ description: "Run checks and compare quality, cost, latency, and diff risk.",
32681
+ requiredTools: ["bash_exec", "git_diff"],
32682
+ risk: "destructive"
32683
+ },
32684
+ {
32685
+ id: "apply-winner",
32686
+ description: "Apply the winning patch only if conservative checks pass.",
32687
+ requiredTools: ["git_diff", "edit_file"],
32688
+ risk: "write"
32689
+ }
32690
+ ]
32691
+ },
32692
+ {
32693
+ id: "release",
32694
+ name: "Release",
32695
+ description: "Follow the project release skill: changelog, version bump, PR, merge, tag, publish verify.",
32696
+ inputSchema: "bump?: patch|minor|major",
32697
+ outputKind: "release",
32698
+ replayable: true,
32699
+ checks: ["pnpm check", "PR checks", "release.yml", "npm view"],
32700
+ steps: [
32701
+ {
32702
+ id: "preflight",
32703
+ description: "Verify branch, clean tree, GitHub auth, and remote state.",
32704
+ requiredTools: ["git_status", "bash_exec"],
32705
+ risk: "destructive"
32706
+ },
32707
+ {
32708
+ id: "version",
32709
+ description: "Update changelog and package versions using the release skill.",
32710
+ requiredTools: ["read_file", "edit_file", "bash_exec"],
32711
+ risk: "destructive"
32712
+ },
32713
+ {
32714
+ id: "publish",
32715
+ description: "Merge release PR, tag main, and verify release workflow outputs.",
32716
+ requiredTools: ["bash_exec"],
32717
+ risk: "destructive"
32718
+ }
32719
+ ]
32720
+ }
32721
+ ];
32722
+ var WorkflowRegistry = WorkflowCatalog;
32723
+ function createWorkflowCatalog(workflows) {
32724
+ return new WorkflowCatalog(workflows);
32725
+ }
32726
+ function createWorkflowRegistry(workflows) {
32727
+ return createWorkflowCatalog(workflows);
32728
+ }
32729
+
32730
+ // src/runtime/workflow-engine.ts
32731
+ var WorkflowEngine = class {
32732
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
32733
+ this.catalog = catalog;
32734
+ this.eventLog = eventLog;
32735
+ }
32736
+ catalog;
32737
+ eventLog;
32738
+ handlers = /* @__PURE__ */ new Map();
32739
+ registerHandler(workflowId, handler) {
32740
+ if (!this.catalog.get(workflowId)) {
32741
+ throw new Error(`Unknown workflow: ${workflowId}`);
32742
+ }
32743
+ this.handlers.set(workflowId, handler);
32744
+ }
32745
+ createPlan(workflowId, input) {
32746
+ return this.catalog.createPlan(workflowId, input, this.eventLog);
32747
+ }
32748
+ async run(request) {
32749
+ const workflow = this.catalog.get(request.workflowId);
32750
+ if (!workflow) {
32751
+ throw new Error(`Unknown workflow: ${request.workflowId}`);
32752
+ }
32753
+ const handler = this.handlers.get(request.workflowId);
32754
+ if (!handler) {
32755
+ throw new Error(`No handler registered for workflow: ${request.workflowId}`);
32756
+ }
32757
+ const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
32758
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
32759
+ const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
32760
+ this.eventLog.record("workflow.started", {
32761
+ workflowId: request.workflowId,
32762
+ planId: plan.id,
32763
+ runId
32764
+ });
32765
+ try {
32766
+ const output = await handler(request.input, {
32767
+ workflow,
32768
+ plan,
32769
+ eventLog: this.eventLog
32770
+ });
32771
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
32772
+ const result = {
32773
+ id: runId,
32774
+ workflowId: request.workflowId,
32775
+ status: "completed",
32776
+ output,
32777
+ startedAt,
32778
+ completedAt
32779
+ };
32780
+ this.eventLog.record("workflow.completed", {
32781
+ workflowId: request.workflowId,
32782
+ planId: plan.id,
32783
+ runId
32784
+ });
32785
+ return result;
32786
+ } catch (error) {
32787
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
32788
+ const message = error instanceof Error ? error.message : String(error);
32789
+ this.eventLog.record("workflow.failed", {
32790
+ workflowId: request.workflowId,
32791
+ planId: plan.id,
32792
+ runId,
32793
+ error: message
32794
+ });
32795
+ return {
32796
+ id: runId,
32797
+ workflowId: request.workflowId,
32798
+ status: "failed",
32799
+ output: null,
32800
+ startedAt,
32801
+ completedAt,
32802
+ error: message
32803
+ };
32804
+ }
32805
+ }
32806
+ };
32807
+ function createWorkflowEngine(catalog, eventLog) {
32808
+ return new WorkflowEngine(catalog, eventLog);
32809
+ }
32810
+
32811
+ // src/runtime/agent-runtime.ts
32812
+ var AgentRuntime = class {
32813
+ constructor(options) {
32814
+ this.options = options;
32815
+ this.providerRegistry = createProviderRegistry();
32816
+ this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
32817
+ this.sessionStore = options.sessionStore;
32818
+ this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
32819
+ this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
32820
+ this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
32821
+ this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
32822
+ this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
32823
+ this.providerType = options.providerType;
32824
+ this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
32825
+ }
32826
+ options;
32827
+ providerRegistry;
32828
+ toolRegistry;
32829
+ sessionStore;
32830
+ runtimeSessionStore;
32831
+ workflowEngine;
32832
+ permissionPolicy;
32833
+ eventLog;
32834
+ turnRunner;
32835
+ providerType;
32836
+ model;
32837
+ provider;
32838
+ async initialize() {
32839
+ const providerInjected = Boolean(this.options.provider);
32840
+ const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
32841
+ ...this.options.providerConfig,
32842
+ model: this.getModel()
32843
+ });
32844
+ this.provider = provider;
32845
+ this.publishToGlobalBridge(provider);
32846
+ this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
32847
+ provider: this.providerType,
32848
+ model: this.getModel(),
32849
+ createdByRuntime: !providerInjected
32850
+ });
32851
+ this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
32852
+ }
32853
+ getModel() {
32854
+ return this.model;
32855
+ }
32856
+ updateProvider(providerType, model2, provider) {
32857
+ this.providerType = providerType;
32858
+ this.model = model2 ?? getDefaultModel(providerType);
32859
+ this.provider = provider;
32860
+ this.publishToGlobalBridge(provider);
32861
+ this.eventLog.record("provider.updated", {
32862
+ provider: this.providerType,
32863
+ model: this.model
32864
+ });
32865
+ }
32866
+ publishToGlobalBridge(provider) {
32867
+ if (this.options.publishToGlobalBridge !== true) return;
32868
+ setAgentProvider(provider);
32869
+ setAgentToolRegistry(this.toolRegistry);
32870
+ }
32871
+ snapshot() {
32872
+ const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
32873
+ const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
32874
+ return {
32875
+ provider: {
32876
+ type: this.providerType,
32877
+ model: this.getModel(),
32878
+ capability
32879
+ },
32880
+ tools: {
32881
+ count: toolNames.length,
32882
+ names: toolNames
32883
+ },
32884
+ modes: listAgentModes()
32885
+ };
32886
+ }
32887
+ createSession(options = {}) {
32888
+ const session = this.runtimeSessionStore.create(options);
32889
+ this.eventLog.record("session.created", {
32890
+ sessionId: session.id,
32891
+ mode: session.mode,
32892
+ metadataKeys: Object.keys(session.metadata).sort()
32893
+ });
32894
+ return session;
32895
+ }
32896
+ getSession(sessionId) {
32897
+ return this.runtimeSessionStore.get(sessionId);
32898
+ }
32899
+ listSessions() {
32900
+ return this.runtimeSessionStore.list();
32901
+ }
32902
+ async runTurn(input) {
32903
+ const provider = this.provider;
32904
+ if (!provider) {
32905
+ throw new Error("Runtime provider is not initialized.");
32906
+ }
32907
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
32908
+ if (!session) {
32909
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
32910
+ }
32911
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
32912
+ this.eventLog.record("turn.started", {
32913
+ sessionId: effectiveSession.id,
32914
+ provider: this.providerType,
32915
+ model: this.getModel(),
32916
+ mode: effectiveSession.mode,
32917
+ runtimeApi: true
32918
+ });
32919
+ try {
32920
+ const result = await this.turnRunner.run(input, {
32921
+ runtime: this,
32922
+ session: effectiveSession,
32923
+ provider,
32924
+ toolRegistry: this.toolRegistry,
32925
+ permissionPolicy: this.permissionPolicy,
32926
+ eventLog: this.eventLog
32927
+ });
32928
+ const updatedSession = this.runtimeSessionStore.update({
32929
+ ...effectiveSession,
32930
+ messages: [
32931
+ ...effectiveSession.messages,
32932
+ { role: "user", content: input.content },
32933
+ { role: "assistant", content: result.content }
32934
+ ]
32935
+ });
32936
+ this.eventLog.record("session.updated", {
32937
+ sessionId: updatedSession.id,
32938
+ messages: updatedSession.messages.length
32939
+ });
32940
+ this.eventLog.record("turn.completed", {
32941
+ sessionId: updatedSession.id,
32942
+ inputTokens: result.usage.inputTokens,
32943
+ outputTokens: result.usage.outputTokens,
32944
+ model: result.model,
32945
+ runtimeApi: true
32946
+ });
32947
+ return { ...result, sessionId: updatedSession.id, mode: updatedSession.mode };
32948
+ } catch (error) {
32949
+ this.eventLog.record("turn.failed", {
32950
+ sessionId: effectiveSession.id,
32951
+ error: error instanceof Error ? error.message : String(error),
32952
+ runtimeApi: true
32953
+ });
32954
+ throw error;
32955
+ }
32956
+ }
32957
+ async *streamTurn(input) {
32958
+ const provider = this.provider;
32959
+ if (!provider) {
32960
+ throw new Error("Runtime provider is not initialized.");
32961
+ }
32962
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
32963
+ if (!session) {
32964
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
32965
+ }
32966
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
32967
+ const messages = [
32968
+ ...effectiveSession.messages,
32969
+ {
32970
+ role: "user",
32971
+ content: input.content
32972
+ }
32973
+ ];
32974
+ this.eventLog.record("turn.started", {
32975
+ sessionId: effectiveSession.id,
32976
+ provider: this.providerType,
32977
+ model: this.getModel(),
32978
+ mode: effectiveSession.mode,
32979
+ streaming: true,
32980
+ runtimeApi: true
32981
+ });
32982
+ let content = "";
32983
+ let completed = false;
32984
+ let failed = false;
32985
+ try {
32986
+ for await (const chunk of provider.stream(messages, {
32987
+ model: input.options?.model,
32988
+ maxTokens: input.options?.maxTokens,
32989
+ temperature: input.options?.temperature,
32990
+ stopSequences: input.options?.stopSequences,
32991
+ system: effectiveSession.instructions ?? input.options?.system,
32992
+ timeout: input.options?.timeout,
32993
+ signal: input.options?.signal,
32994
+ thinking: input.options?.thinking
32995
+ })) {
32996
+ if (chunk.type === "text" && chunk.text) {
32997
+ content += chunk.text;
32998
+ yield {
32999
+ type: "text",
33000
+ sessionId: effectiveSession.id,
33001
+ text: chunk.text
33002
+ };
33003
+ }
33004
+ }
33005
+ const updatedSession = this.runtimeSessionStore.update({
33006
+ ...effectiveSession,
33007
+ messages: [
33008
+ ...effectiveSession.messages,
33009
+ { role: "user", content: input.content },
33010
+ { role: "assistant", content }
33011
+ ]
33012
+ });
33013
+ const result = {
33014
+ sessionId: updatedSession.id,
33015
+ content,
33016
+ usage: {
33017
+ inputTokens: provider.countTokens(input.content),
33018
+ outputTokens: provider.countTokens(content),
33019
+ estimated: true
33020
+ },
33021
+ model: input.options?.model ?? this.getModel(),
33022
+ mode: updatedSession.mode
33023
+ };
33024
+ this.eventLog.record("session.updated", {
33025
+ sessionId: updatedSession.id,
33026
+ messages: updatedSession.messages.length
33027
+ });
33028
+ this.eventLog.record("turn.completed", {
33029
+ sessionId: updatedSession.id,
33030
+ inputTokens: result.usage.inputTokens,
33031
+ outputTokens: result.usage.outputTokens,
33032
+ model: result.model,
33033
+ streaming: true,
33034
+ runtimeApi: true
33035
+ });
33036
+ completed = true;
33037
+ yield { type: "done", sessionId: updatedSession.id, result };
33038
+ } catch (error) {
33039
+ failed = true;
33040
+ const message = error instanceof Error ? error.message : String(error);
33041
+ this.eventLog.record("turn.failed", {
33042
+ sessionId: effectiveSession.id,
33043
+ error: message,
33044
+ streaming: true,
33045
+ runtimeApi: true
33046
+ });
33047
+ yield {
33048
+ type: "error",
33049
+ sessionId: effectiveSession.id,
33050
+ error: message
33051
+ };
33052
+ } finally {
33053
+ if (!completed && !failed) {
33054
+ this.eventLog.record("turn.cancelled", {
33055
+ sessionId: effectiveSession.id,
33056
+ outputTokens: provider.countTokens(content),
33057
+ streaming: true,
33058
+ runtimeApi: true
33059
+ });
33060
+ }
33061
+ }
33062
+ }
33063
+ async executeTool(input) {
33064
+ const startedAt = performance.now();
33065
+ const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
33066
+ if (input.sessionId && !session) {
33067
+ const decision2 = {
33068
+ allowed: false,
33069
+ reason: `Runtime session not found: ${input.sessionId}`,
33070
+ risk: "read-only"
33071
+ };
33072
+ this.eventLog.record("tool.blocked", {
33073
+ sessionId: input.sessionId,
33074
+ mode: input.mode ?? "ask",
33075
+ tool: input.toolName,
33076
+ reason: decision2.reason,
33077
+ runtimeApi: true
33078
+ });
33079
+ return {
33080
+ toolName: input.toolName,
33081
+ success: false,
33082
+ error: decision2.reason,
33083
+ duration: performance.now() - startedAt,
33084
+ decision: decision2
33085
+ };
33086
+ }
33087
+ const mode = input.mode ?? session?.mode ?? "ask";
33088
+ const tool = this.toolRegistry.get(input.toolName);
33089
+ if (!tool) {
33090
+ const decision2 = {
33091
+ allowed: false,
33092
+ reason: "Tool not registered.",
33093
+ risk: "read-only"
33094
+ };
33095
+ this.eventLog.record("tool.blocked", {
33096
+ sessionId: input.sessionId,
33097
+ mode,
33098
+ tool: input.toolName,
33099
+ reason: decision2.reason,
33100
+ runtimeApi: true
33101
+ });
33102
+ return {
33103
+ toolName: input.toolName,
33104
+ success: false,
33105
+ error: decision2.reason,
33106
+ duration: performance.now() - startedAt,
33107
+ decision: decision2
33108
+ };
33109
+ }
33110
+ const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
33111
+ if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
33112
+ const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
33113
+ this.eventLog.record("tool.blocked", {
33114
+ sessionId: input.sessionId,
33115
+ mode,
33116
+ tool: input.toolName,
33117
+ reason,
33118
+ risk: decision.risk,
33119
+ requiresConfirmation: decision.requiresConfirmation,
33120
+ runtimeApi: true
33121
+ });
33122
+ return {
33123
+ toolName: input.toolName,
33124
+ success: false,
33125
+ error: reason,
33126
+ duration: performance.now() - startedAt,
33127
+ decision
33128
+ };
33129
+ }
33130
+ this.eventLog.record("tool.started", {
33131
+ sessionId: input.sessionId,
33132
+ mode,
33133
+ tool: input.toolName,
33134
+ risk: decision.risk,
33135
+ runtimeApi: true,
33136
+ metadataKeys: Object.keys(input.metadata ?? {}).sort()
33137
+ });
33138
+ const result = await this.toolRegistry.execute(input.toolName, input.input);
33139
+ this.eventLog.record("tool.completed", {
33140
+ sessionId: input.sessionId,
33141
+ mode,
33142
+ tool: input.toolName,
33143
+ success: result.success,
33144
+ duration: result.duration,
33145
+ runtimeApi: true
33146
+ });
33147
+ return {
33148
+ toolName: input.toolName,
33149
+ success: result.success,
33150
+ output: result.data,
33151
+ error: result.error,
33152
+ duration: result.duration,
33153
+ decision
33154
+ };
33155
+ }
33156
+ assertToolAllowed(mode, toolName, input) {
33157
+ const tool = this.toolRegistry.get(toolName);
33158
+ if (!tool) {
33159
+ this.eventLog.record("tool.blocked", {
33160
+ mode,
33161
+ tool: toolName,
33162
+ reason: "Tool not registered."
33163
+ });
33164
+ return false;
33165
+ }
33166
+ const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
33167
+ this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
33168
+ mode,
33169
+ tool: toolName,
33170
+ ...decision
33171
+ });
33172
+ return decision.allowed;
33173
+ }
33174
+ };
33175
+ async function createAgentRuntime(options) {
33176
+ const runtime = new AgentRuntime(options);
33177
+ await runtime.initialize();
33178
+ return runtime;
33179
+ }
33180
+ var HttpRequestError = class extends Error {
33181
+ constructor(message, status) {
33182
+ super(message);
33183
+ this.status = status;
33184
+ }
33185
+ status;
33186
+ };
33187
+ async function readJsonBody(request, maxBodyBytes) {
33188
+ const chunks = [];
33189
+ let size = 0;
33190
+ for await (const chunk of request) {
33191
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
33192
+ size += buffer.length;
33193
+ if (size > maxBodyBytes) {
33194
+ throw new HttpRequestError(`Request body exceeds ${maxBodyBytes} bytes.`, 413);
33195
+ }
33196
+ chunks.push(buffer);
33197
+ }
33198
+ const raw = Buffer.concat(chunks).toString("utf-8").trim();
33199
+ try {
33200
+ return raw ? JSON.parse(raw) : {};
33201
+ } catch {
33202
+ throw new HttpRequestError("Invalid JSON request body.", 400);
33203
+ }
33204
+ }
33205
+ function sendJson(response, status, body) {
33206
+ response.statusCode = status;
33207
+ response.setHeader("content-type", "application/json; charset=utf-8");
33208
+ response.end(JSON.stringify(body, null, 2));
33209
+ }
33210
+ function notFound(response) {
33211
+ sendJson(response, 404, { error: "Not found" });
33212
+ }
33213
+ function assertValidMode(mode) {
33214
+ if (mode === void 0) return void 0;
33215
+ if (typeof mode === "string" && isAgentMode(mode)) return mode;
33216
+ throw new HttpRequestError("Invalid runtime mode.", 400);
33217
+ }
33218
+ function createRuntimeHttpServer(runtime, options = {}) {
33219
+ const maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;
33220
+ return createServer(async (request, response) => {
33221
+ try {
33222
+ const url = new URL(request.url ?? "/", "http://localhost");
33223
+ const parts = url.pathname.split("/").filter(Boolean);
33224
+ if (request.method === "POST" && url.pathname === "/sessions") {
33225
+ const body = await readJsonBody(request, maxBodyBytes);
33226
+ const session = runtime.createSession({
33227
+ mode: assertValidMode(body.mode),
33228
+ instructions: body.instructions,
33229
+ metadata: body.metadata
33230
+ });
33231
+ sendJson(response, 201, session);
33232
+ return;
33233
+ }
33234
+ if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts.length === 2) {
33235
+ const session = runtime.getSession(parts[1]);
33236
+ if (!session) {
33237
+ notFound(response);
33238
+ return;
33239
+ }
33240
+ sendJson(response, 200, session);
33241
+ return;
33242
+ }
33243
+ if (request.method === "POST" && parts[0] === "sessions" && parts[1] && parts[2] === "messages") {
33244
+ const body = await readJsonBody(request, maxBodyBytes);
33245
+ if (!body.content || typeof body.content !== "string") {
33246
+ sendJson(response, 400, { error: "content is required" });
33247
+ return;
33248
+ }
33249
+ if (!runtime.getSession(parts[1])) {
33250
+ notFound(response);
33251
+ return;
33252
+ }
33253
+ const result = await runtime.runTurn({
33254
+ ...body,
33255
+ mode: assertValidMode(body.mode),
33256
+ sessionId: parts[1]
33257
+ });
33258
+ sendJson(response, 200, result);
33259
+ return;
33260
+ }
33261
+ if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts[2] === "events") {
33262
+ const events = runtime.eventLog.list().filter((event) => event.data["sessionId"] === parts[1]);
33263
+ sendJson(response, 200, { events });
33264
+ return;
33265
+ }
33266
+ if (request.method === "GET" && url.pathname === "/state") {
33267
+ sendJson(response, 200, runtime.snapshot());
33268
+ return;
33269
+ }
33270
+ notFound(response);
33271
+ } catch (error) {
33272
+ const status = error instanceof HttpRequestError ? error.status : 500;
33273
+ sendJson(response, status, {
33274
+ error: error instanceof Error ? error.message : String(error)
33275
+ });
33276
+ }
33277
+ });
33278
+ }
33279
+
33280
+ // src/runtime/extension-manifests.ts
33281
+ function createMcpToolPolicy(server, tool, risk, allowedModes = ["ask", "plan", "build", "debug", "review", "architect"]) {
33282
+ return {
33283
+ server,
33284
+ tool,
33285
+ risk,
33286
+ requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
33287
+ allowedModes
33288
+ };
33289
+ }
33290
+
30914
33291
  // src/index.ts
30915
33292
  init_errors();
30916
33293
  init_logger();
30917
33294
  init_proxy();
30918
33295
 
30919
- export { ADRGenerator, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DiscoveryEngine, DockerGenerator, DocsGenerator, OrchestrateExecutor, OutputExecutor, PhaseError, SessionManager, SpecificationGenerator, TaskError, TaskIterator, ToolRegistry, VERSION, configExists, createADRGenerator, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCompleteExecutor, createConvergeExecutor, createDefaultConfig, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createFullToolRegistry, createLogger, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createProvider, createSessionManager, createSpecificationGenerator, createTaskIterator, createToolRegistry, installProxyDispatcher, loadConfig, registerAllTools, saveConfig };
33296
+ export { ADRGenerator, AGENT_MODES, AgentRuntime, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DefaultRuntimeTurnRunner, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, FileRuntimeSessionStore, InMemoryEventLog, InMemoryRuntimeSessionStore, OrchestrateExecutor, OutputExecutor, PhaseError, ProviderRegistry, SessionManager, SpecificationGenerator, TaskError, TaskIterator, ToolRegistry, VERSION, WorkflowCatalog, WorkflowEngine, WorkflowRegistry, configExists, createADRGenerator, createAgentRuntime, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCompleteExecutor, createConvergeExecutor, createDefaultConfig, createDefaultRuntimeTurnRunner, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createEventLog, createFileEventLog, createFileRuntimeSessionStore, createFullToolRegistry, createLogger, createMcpToolPolicy, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createProvider, createProviderRegistry, createRuntimeHttpServer, createRuntimeSessionStore, createSessionManager, createSpecificationGenerator, createTaskIterator, createToolRegistry, createWorkflowCatalog, createWorkflowEngine, createWorkflowRegistry, getAgentMode, installProxyDispatcher, isAgentMode, listAgentModes, loadConfig, registerAllTools, saveConfig };
30920
33297
  //# sourceMappingURL=index.js.map
30921
33298
  //# sourceMappingURL=index.js.map