@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/README.md +7 -0
- package/dist/cli/index.js +1124 -109
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +451 -1
- package/dist/index.js +2436 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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 ??
|
|
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
|