@qodeca/xezar 0.13.1 → 0.14.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 +45 -15
- package/dist/agent-config/account-identity.d.ts +2 -8
- package/dist/agent-config/account-identity.js +54 -10
- package/dist/agent-config/account-identity.js.map +1 -1
- package/dist/agent-config/catalog.d.ts +49 -7
- package/dist/agent-config/catalog.js +107 -0
- package/dist/agent-config/catalog.js.map +1 -1
- package/dist/agent-config/model-settings/pi.d.ts +12 -6
- package/dist/agent-config/model-settings/pi.js +12 -6
- package/dist/agent-config/model-settings/pi.js.map +1 -1
- package/dist/agent-config/seed.js +10 -0
- package/dist/agent-config/seed.js.map +1 -1
- package/dist/contract/github.d.ts +15 -0
- package/dist/contract/index.d.ts +9 -0
- package/dist/contract/index.js +1527 -895
- package/dist/contract/mcp-api-reference.d.ts +174 -0
- package/dist/contract/mcp-audit.d.ts +103 -0
- package/dist/contract/mcp-discovery.d.ts +257 -0
- package/dist/contract/mcp-event-catalog.d.ts +121 -0
- package/dist/contract/mcp-event-catalog.test.d.ts +1 -0
- package/dist/contract/mcp-idempotency.d.ts +200 -0
- package/dist/contract/mcp-journal.d.ts +268 -0
- package/dist/contract/mcp-leader.d.ts +88 -0
- package/dist/contract/mcp-ownership.d.ts +78 -0
- package/dist/contract/mcp-versioning.d.ts +139 -0
- package/dist/contract/runs.d.ts +81 -0
- package/dist/core/agent-profiles.d.ts +15 -4
- package/dist/core/agent-profiles.js +22 -8
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/opencode-server-runner.js +71 -11
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/secret-redaction.d.ts +7 -1
- package/dist/core/secret-redaction.js +44 -10
- package/dist/core/secret-redaction.js.map +1 -1
- package/dist/index.js +138 -27
- package/dist/index.js.map +1 -1
- package/dist/machine-identity.d.ts +66 -0
- package/dist/machine-identity.js +96 -0
- package/dist/machine-identity.js.map +1 -0
- package/dist/mcp/adapters/claude-code.d.ts +41 -0
- package/dist/mcp/adapters/claude-code.js +40 -0
- package/dist/mcp/adapters/claude-code.js.map +1 -0
- package/dist/mcp/adapters/codex.d.ts +140 -0
- package/dist/mcp/adapters/codex.js +323 -0
- package/dist/mcp/adapters/codex.js.map +1 -0
- package/dist/mcp/adapters/opencode.d.ts +148 -0
- package/dist/mcp/adapters/opencode.js +528 -0
- package/dist/mcp/adapters/opencode.js.map +1 -0
- package/dist/mcp/adapters/pi-link.d.ts +102 -0
- package/dist/mcp/adapters/pi-link.js +235 -0
- package/dist/mcp/adapters/pi-link.js.map +1 -0
- package/dist/mcp/adapters/pi.d.ts +188 -0
- package/dist/mcp/adapters/pi.js +418 -0
- package/dist/mcp/adapters/pi.js.map +1 -0
- package/dist/mcp/api-reference.d.ts +26 -0
- package/dist/mcp/api-reference.js +133 -0
- package/dist/mcp/api-reference.js.map +1 -0
- package/dist/mcp/audit-trail.d.ts +162 -0
- package/dist/mcp/audit-trail.js +306 -0
- package/dist/mcp/audit-trail.js.map +1 -0
- package/dist/mcp/bridge.d.ts +81 -0
- package/dist/mcp/bridge.js +407 -0
- package/dist/mcp/bridge.js.map +1 -0
- package/dist/mcp/connection-file.d.ts +49 -0
- package/dist/mcp/connection-file.js +63 -0
- package/dist/mcp/connection-file.js.map +1 -0
- package/dist/mcp/echo-guard.d.ts +94 -0
- package/dist/mcp/echo-guard.js +160 -0
- package/dist/mcp/echo-guard.js.map +1 -0
- package/dist/mcp/event-catalog.d.ts +120 -0
- package/dist/mcp/event-catalog.js +306 -0
- package/dist/mcp/event-catalog.js.map +1 -0
- package/dist/mcp/event-controller.d.ts +230 -0
- package/dist/mcp/event-controller.js +596 -0
- package/dist/mcp/event-controller.js.map +1 -0
- package/dist/mcp/event-journal.d.ts +57 -0
- package/dist/mcp/event-journal.js +423 -0
- package/dist/mcp/event-journal.js.map +1 -0
- package/dist/mcp/index.d.ts +63 -0
- package/dist/mcp/index.js +386 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/ipc.d.ts +202 -0
- package/dist/mcp/ipc.js +206 -0
- package/dist/mcp/ipc.js.map +1 -0
- package/dist/mcp/leader-delivery.d.ts +119 -0
- package/dist/mcp/leader-delivery.js +450 -0
- package/dist/mcp/leader-delivery.js.map +1 -0
- package/dist/mcp/operation-receipts.d.ts +210 -0
- package/dist/mcp/operation-receipts.js +723 -0
- package/dist/mcp/operation-receipts.js.map +1 -0
- package/dist/mcp/project-catalogs.d.ts +23 -0
- package/dist/mcp/project-catalogs.js +25 -0
- package/dist/mcp/project-catalogs.js.map +1 -0
- package/dist/mcp/project-leaders.d.ts +26 -0
- package/dist/mcp/project-leaders.js +17 -0
- package/dist/mcp/project-leaders.js.map +1 -0
- package/dist/mcp/protocol.d.ts +50 -0
- package/dist/mcp/protocol.js +47 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/reconnect.d.ts +297 -0
- package/dist/mcp/reconnect.js +465 -0
- package/dist/mcp/reconnect.js.map +1 -0
- package/dist/mcp/resource-ownership.d.ts +228 -0
- package/dist/mcp/resource-ownership.js +390 -0
- package/dist/mcp/resource-ownership.js.map +1 -0
- package/dist/mcp/service-adapter.d.ts +16488 -0
- package/dist/mcp/service-adapter.js +148 -0
- package/dist/mcp/service-adapter.js.map +1 -0
- package/dist/mcp/service.d.ts +83 -0
- package/dist/mcp/service.js +233 -0
- package/dist/mcp/service.js.map +1 -0
- package/dist/mcp/session-binding.d.ts +105 -0
- package/dist/mcp/session-binding.js +163 -0
- package/dist/mcp/session-binding.js.map +1 -0
- package/dist/mcp/stale-write.d.ts +145 -0
- package/dist/mcp/stale-write.js +219 -0
- package/dist/mcp/stale-write.js.map +1 -0
- package/dist/mcp/tool.d.ts +48 -0
- package/dist/mcp/tool.js +24 -0
- package/dist/mcp/tool.js.map +1 -0
- package/dist/mcp/tools/discovery.d.ts +40 -0
- package/dist/mcp/tools/discovery.js +232 -0
- package/dist/mcp/tools/discovery.js.map +1 -0
- package/dist/mcp/tools/execution-control.d.ts +171 -0
- package/dist/mcp/tools/execution-control.js +513 -0
- package/dist/mcp/tools/execution-control.js.map +1 -0
- package/dist/mcp/tools/handoff-git.d.ts +26 -0
- package/dist/mcp/tools/handoff-git.js +544 -0
- package/dist/mcp/tools/handoff-git.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +2 -0
- package/dist/mcp/tools/index.js +23 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/leader-events.d.ts +46 -0
- package/dist/mcp/tools/leader-events.js +126 -0
- package/dist/mcp/tools/leader-events.js.map +1 -0
- package/dist/mcp/tools/local-handoff.d.ts +102 -0
- package/dist/mcp/tools/local-handoff.js +306 -0
- package/dist/mcp/tools/local-handoff.js.map +1 -0
- package/dist/mcp/tools/project-config.d.ts +340 -0
- package/dist/mcp/tools/project-config.js +1075 -0
- package/dist/mcp/tools/project-config.js.map +1 -0
- package/dist/mcp/tools/results-evidence.d.ts +112 -0
- package/dist/mcp/tools/results-evidence.js +1045 -0
- package/dist/mcp/tools/results-evidence.js.map +1 -0
- package/dist/mcp/tools/task-create.d.ts +70 -0
- package/dist/mcp/tools/task-create.js +473 -0
- package/dist/mcp/tools/task-create.js.map +1 -0
- package/dist/mcp/tools/task-reads.d.ts +102 -0
- package/dist/mcp/tools/task-reads.js +689 -0
- package/dist/mcp/tools/task-reads.js.map +1 -0
- package/dist/mcp/tools/work-organisation.d.ts +2 -0
- package/dist/mcp/tools/work-organisation.js +502 -0
- package/dist/mcp/tools/work-organisation.js.map +1 -0
- package/dist/paths.d.ts +17 -7
- package/dist/paths.js +18 -8
- package/dist/paths.js.map +1 -1
- package/dist/runs/project-writer.js +76 -11
- package/dist/runs/project-writer.js.map +1 -1
- package/dist/runs/retention.d.ts +24 -1
- package/dist/runs/retention.js +62 -1
- package/dist/runs/retention.js.map +1 -1
- package/dist/server/forge/github.js +44 -0
- package/dist/server/forge/github.js.map +1 -1
- package/dist/server/forge/types.d.ts +16 -0
- package/dist/server/project-context.d.ts +81 -8
- package/dist/server/project-context.js +143 -35
- package/dist/server/project-context.js.map +1 -1
- package/dist/server/server.d.ts +1050 -53
- package/dist/server/server.js +326 -120
- package/dist/server/server.js.map +1 -1
- package/dist/server/validators.d.ts +26 -6
- package/dist/server/validators.js +17 -0
- package/dist/server/validators.js.map +1 -1
- package/dist/skills-remote.js +64 -6
- package/dist/skills-remote.js.map +1 -1
- package/dist/workflows/run.d.ts +277 -12
- package/dist/workflows/run.js +554 -59
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/agent-profiles.d.ts +30 -3
- package/dist/workspace/agent-profiles.js +39 -4
- package/dist/workspace/agent-profiles.js.map +1 -1
- package/dist/workspace/config.js +25 -4
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/project-owner.d.ts +210 -0
- package/dist/workspace/project-owner.js +518 -0
- package/dist/workspace/project-owner.js.map +1 -0
- package/package.json +5 -3
- package/scripts/pi-leader-extension.ts +420 -0
- package/scripts/sync-readme.mjs +83 -2
- package/web/dist/assets/{alert-dialog-BVsVcbFy.js → alert-dialog-D6rP6d39.js} +1 -1
- package/web/dist/assets/arrow-down-DMOfFIzW.js +1 -0
- package/web/dist/assets/arrow-left-C4Ec2BUg.js +1 -0
- package/web/dist/assets/{centered-state-Djgly6Ni.js → centered-state-B0ZqrPaa.js} +12 -12
- package/web/dist/assets/chevron-right-mHJ-crvn.js +1 -0
- package/web/dist/assets/{collapsible-DZ4D-DHG.js → collapsible-DchEHgUM.js} +1 -1
- package/web/dist/assets/{commit-list-B-z1JL9G.js → commit-list-BpMim1Rv.js} +1 -1
- package/web/dist/assets/{compare-variants-D62m4j3B.js → compare-variants-D5ItQbAq.js} +1 -1
- package/web/dist/assets/{diff-BKew9rQX.js → diff-HqqZ_WDR.js} +2 -2
- package/web/dist/assets/{diff-stat-D0mc5V6Z.js → diff-stat-NsU-3ecr.js} +1 -1
- package/web/dist/assets/{diff-view-xpIcuLIC.js → diff-view-B7c11Xux.js} +1 -1
- package/web/dist/assets/{dropdown-menu-CEQziH7X.js → dropdown-menu-CtTpnyod.js} +1 -1
- package/web/dist/assets/{editable-title-BCX3T2BY.js → editable-title-BXtuGQry.js} +1 -1
- package/web/dist/assets/{ellipsis-vertical-ByVdDc4z.js → ellipsis-vertical-MHtGZSH6.js} +1 -1
- package/web/dist/assets/{file-xBSB5hXO.js → file-DKLw5SOb.js} +1 -1
- package/web/dist/assets/{folder-CldgbZ5A.js → folder-Drw6-ufH.js} +1 -1
- package/web/dist/assets/{git-toolbar-DJANqg7Y.js → git-toolbar-BQH8bORV.js} +1 -1
- package/web/dist/assets/github-ynnpKFCJ.js +1 -0
- package/web/dist/assets/{image-preview-Cv5mZr0n.js → image-preview-DLhMN_R9.js} +1 -1
- package/web/dist/assets/index-BEsrNdXt.js +29 -0
- package/web/dist/assets/index-Da8DOBau.css +2 -0
- package/web/dist/assets/{markdown-CgEEE2ND.js → markdown-q365eN6Y.js} +1 -1
- package/web/dist/assets/{new-task-form-1r2bgsdD.js → new-task-form-CW-hNIWQ.js} +1 -1
- package/web/dist/assets/{pill-q-x22_ej.js → pill-B_TFulXa.js} +1 -1
- package/web/dist/assets/{project-router-VDN4jQM8.js → project-router-CLPc-ImZ.js} +1 -1
- package/web/dist/assets/{prompt-templates-BmZtCe-L.js → prompt-templates-CLc4RxyO.js} +1 -1
- package/web/dist/assets/{repo-git-btG0sdbO.js → repo-git-Is7R6-Tj.js} +1 -1
- package/web/dist/assets/{run-diff-vguEMJzh.js → run-diff-DHMvDlVo.js} +2 -2
- package/web/dist/assets/run-header-DvZJbQ8I.js +1 -0
- package/web/dist/assets/{search-x-QmhaAbg5.js → search-x-Ce2MMetu.js} +1 -1
- package/web/dist/assets/{skill-empty-hint-BrzUwByZ.js → skill-empty-hint-C_xCSvzB.js} +1 -1
- package/web/dist/assets/skills-CivqD4si.js +1 -0
- package/web/dist/assets/{sparkles-CP8QDOgX.js → sparkles-BCqPoj5g.js} +1 -1
- package/web/dist/assets/{square-terminal-CGypshSD.js → square-terminal-ikj5g-oK.js} +1 -1
- package/web/dist/assets/{tab-link-D4lFzzI1.js → tab-link-VsEjFV1Y.js} +1 -1
- package/web/dist/assets/{task-changes-BtZId14z.js → task-changes-CH-E81-_.js} +1 -1
- package/web/dist/assets/{task-commits-BoeyJXrv.js → task-commits-DqfkMFxp.js} +1 -1
- package/web/dist/assets/{task-files-DIy2oUnj.js → task-files-D_nkHZ_a.js} +2 -2
- package/web/dist/assets/task-thread-bxQompxJ.js +9 -0
- package/web/dist/assets/{textarea-CyBCyKIk.js → textarea-xajuW1L_.js} +1 -1
- package/web/dist/assets/{thread-loading-Cuq2jchC.js → thread-loading-C3JQZbIE.js} +1 -1
- package/web/dist/assets/{trash-2-B6Dp3ZNs.js → trash-2-hJrBhpUD.js} +1 -1
- package/web/dist/assets/{triangle-alert-xBya8FUp.js → triangle-alert-D1u82y1a.js} +1 -1
- package/web/dist/assets/{upload-D6MXEB9p.js → upload-Bn6FBZ59.js} +1 -1
- package/web/dist/assets/{use-desktop-CPBwzQ7M.js → use-desktop-DOIMfHfY.js} +1 -1
- package/web/dist/assets/{use-submit-shortcut-JTpNzU-u.js → use-submit-shortcut-Dj4DHTdE.js} +1 -1
- package/web/dist/assets/utils-YwBpOoRN.js +64 -0
- package/web/dist/assets/{workflows-DG115scU.js → workflows-CTaAKz2m.js} +3 -3
- package/web/dist/assets/{zoomable-image-GTYwLtkS.js → zoomable-image-C1-6P3tg.js} +1 -1
- package/web/dist/index.html +23 -23
- package/web/dist/assets/arrow-down-CYgAlZtW.js +0 -1
- package/web/dist/assets/arrow-left-BOqE0a3k.js +0 -1
- package/web/dist/assets/chevron-right-Cc9BWnbN.js +0 -1
- package/web/dist/assets/github-D6vK0jFn.js +0 -1
- package/web/dist/assets/index-CkmR6h7s.css +0 -2
- package/web/dist/assets/index-DVDqF4bM.js +0 -9
- package/web/dist/assets/refresh-cw-DcNCj2nu.js +0 -1
- package/web/dist/assets/run-header-DM7MiKj9.js +0 -1
- package/web/dist/assets/skills-DMfxQtrD.js +0 -1
- package/web/dist/assets/task-thread-CbMPmrWq.js +0 -9
- package/web/dist/assets/utils--z9hRtl3.js +0 -64
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type HealthResponse, type McpDiscovery, type McpDiscoveryLimits, type ProviderStatusResponse } from '../../contract/index.js';
|
|
3
|
+
import { type McpToolContext } from '../tool.ts';
|
|
4
|
+
/**
|
|
5
|
+
* `discover_project` (#90, F-03, U-M06): which project this session is bound to, what it can do
|
|
6
|
+
* and within which limits, and — for everything it cannot do — why.
|
|
7
|
+
*
|
|
8
|
+
* Two halves on purpose. `collectDiscoveryFacts` gathers what `GET /health` and `GET /config`
|
|
9
|
+
* report, through the same helpers those routes call, for the BOUND project only: it never reads
|
|
10
|
+
* the project list at all. `buildDiscovery` is the filter — pure, and the part the isolation
|
|
11
|
+
* guarantees rest on. It accepts the health shape (a full `HealthResponse` included, `projects`
|
|
12
|
+
* and `bootProject` and all), copies out only what `mcpDiscoverySchema` names, and writes every
|
|
13
|
+
* reason itself instead of forwarding a CLI's text: raw `gh` or agent output can name an account
|
|
14
|
+
* or an organisation (F-12, F-15). The strict schema parse at the end turns any key that slips in
|
|
15
|
+
* later into a tool failure instead of a leak.
|
|
16
|
+
*/
|
|
17
|
+
export interface DiscoveryFacts {
|
|
18
|
+
project: McpToolContext['project'];
|
|
19
|
+
xezarVersion: string;
|
|
20
|
+
/** Structurally a subset of `HealthResponse`, so a whole health payload is accepted — and filtered. */
|
|
21
|
+
health: Pick<HealthResponse, 'repo' | 'checks' | 'forge' | 'capabilities' | 'defaultRunner'>;
|
|
22
|
+
config: {
|
|
23
|
+
baseBranch: string | null;
|
|
24
|
+
modelsLocked: boolean;
|
|
25
|
+
};
|
|
26
|
+
providers: ProviderStatusResponse;
|
|
27
|
+
limits: McpDiscoveryLimits;
|
|
28
|
+
}
|
|
29
|
+
export declare function buildDiscovery(facts: DiscoveryFacts): McpDiscovery;
|
|
30
|
+
/**
|
|
31
|
+
* `--bind-host` of THIS process. The MCP socket lives inside `xezar serve`, and a non-loopback
|
|
32
|
+
* bind is half of what makes the cockpit hosted; `McpToolContext` does not carry it yet (#89
|
|
33
|
+
* widens that context), and reporting `localHandoff: true` on a hosted box would promise actions
|
|
34
|
+
* the routes refuse.
|
|
35
|
+
*/
|
|
36
|
+
export declare function bindHostFromArgv(argv?: readonly string[]): string | undefined;
|
|
37
|
+
export declare function collectDiscoveryFacts(ctx: McpToolContext, env?: NodeJS.ProcessEnv): Promise<DiscoveryFacts>;
|
|
38
|
+
/** The authoritative text block (D-05): a one-line orientation, then the whole result. */
|
|
39
|
+
export declare function discoveryText(discovery: McpDiscovery): string;
|
|
40
|
+
export declare const discoverProjectTool: import("../tool.ts").McpTool<z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { mcpDiscoverySchema, } from '../../contract/index.js';
|
|
4
|
+
import { loadConfig } from '../../config.js';
|
|
5
|
+
import { agentModelsLocked } from '../../core/agent-model-policy.js';
|
|
6
|
+
import { ProviderAuthService } from '../../core/provider-auth.js';
|
|
7
|
+
import { applyProviderEnablement } from '../../core/provider-availability.js';
|
|
8
|
+
import { detectEnvironment } from '../../core/backend-detect.js';
|
|
9
|
+
import { resolveCapabilities } from '../../server/capabilities.js';
|
|
10
|
+
import { resolveForge } from '../../server/forge/index.js';
|
|
11
|
+
import { getRepoInfo } from '../../server/git.js';
|
|
12
|
+
import { loadWorkspaceConfig } from '../../workspace/config.js';
|
|
13
|
+
import { defineTool, textResult } from '../tool.js';
|
|
14
|
+
const RUNNERS = ['claude', 'codex', 'opencode', 'pi'];
|
|
15
|
+
const LABEL = { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', pi: 'pi' };
|
|
16
|
+
const PROVIDERS_SETTINGS = 'Settings → Agents → Providers';
|
|
17
|
+
const HOSTED_REASON = 'This xezar runs in hosted mode (XEZ_REMOTE=1 or a non-loopback bind), so actions on the host machine are refused.';
|
|
18
|
+
export function buildDiscovery(facts) {
|
|
19
|
+
const { health, config } = facts;
|
|
20
|
+
const caps = health.capabilities;
|
|
21
|
+
const agents = RUNNERS.map((runner) => agentEntry(runner, facts));
|
|
22
|
+
const git = health.repo !== null;
|
|
23
|
+
const githubReason = githubUnavailableReason(facts);
|
|
24
|
+
const actions = [
|
|
25
|
+
action('create_task', 'Start a task', createTaskReason(agents)),
|
|
26
|
+
action('parallel_variants', 'Run a task as parallel variants', git ? null : 'Parallel variants need a git repository — each variant runs in its own worktree.'),
|
|
27
|
+
action('worktree_choice', 'Choose worktree or in-place for a task', git ? null : 'This project is not a git repository, so tasks run in place, one at a time.'),
|
|
28
|
+
config.modelsLocked
|
|
29
|
+
? readOnly('model_selection', 'Choose a task model', "Models are locked: each coding agent uses the model from its own native settings. Only a person can change that (XEZ_AGENT_MODELS_LOCKED or modelsLocked in xezar's config).")
|
|
30
|
+
: action('model_selection', 'Choose a task model', null),
|
|
31
|
+
action('github', 'GitHub issues, pull requests and draft PRs', githubReason),
|
|
32
|
+
action('automations', 'GitHub automations', !caps.automations
|
|
33
|
+
? 'GitHub automations are off on this xezar. A person can start it with XEZ_AUTOMATIONS=1 to turn them on.'
|
|
34
|
+
: githubReason && `GitHub automations need GitHub: ${githubReason}`),
|
|
35
|
+
action('inbox', 'Follow-up inbox', caps.followups
|
|
36
|
+
? null
|
|
37
|
+
: 'The follow-up inbox is off for this workspace. A person can turn it on in the cockpit settings (or with XEZ_FOLLOWUPS=1).'),
|
|
38
|
+
action('open_in_app', 'Open the project or a task in a desktop app', caps.localHandoff ? null : HOSTED_REASON),
|
|
39
|
+
action('agent_config_write', "Edit the coding agents' config files", caps.localHandoff ? null : `${HOSTED_REASON} Agent config files can define hooks and commands, so they are never written remotely.`),
|
|
40
|
+
readOnly('workspace_limits', 'Change workspace-wide limits', "Workspace limits are shared with every project. The leader can read them; only a person can change them in the cockpit's global settings."),
|
|
41
|
+
];
|
|
42
|
+
return mcpDiscoverySchema.parse({
|
|
43
|
+
project: {
|
|
44
|
+
id: facts.project.id,
|
|
45
|
+
name: facts.project.name,
|
|
46
|
+
// The rule `/health` already follows (#431): a hosted cockpit reports a basename only.
|
|
47
|
+
root: caps.localHandoff ? facts.project.root : basename(facts.project.root),
|
|
48
|
+
},
|
|
49
|
+
xezarVersion: facts.xezarVersion,
|
|
50
|
+
repository: git ? { git: true, branch: health.repo.branch } : { git: false },
|
|
51
|
+
settings: { defaultRunner: health.defaultRunner, baseBranch: config.baseBranch, modelsLocked: config.modelsLocked },
|
|
52
|
+
capabilities: { localHandoff: caps.localHandoff, followups: caps.followups, automations: caps.automations },
|
|
53
|
+
agents,
|
|
54
|
+
tools: ['gh', 'git'].map((name) => toolCheck(name, facts)),
|
|
55
|
+
limits: facts.limits,
|
|
56
|
+
actions,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function action(id, label, reason) {
|
|
60
|
+
return reason ? { id, label, status: 'unavailable', reason } : { id, label, status: 'available' };
|
|
61
|
+
}
|
|
62
|
+
function readOnly(id, label, reason) {
|
|
63
|
+
return { id, label, status: 'read-only', reason };
|
|
64
|
+
}
|
|
65
|
+
function agentEntry(runner, facts) {
|
|
66
|
+
const check = facts.health.checks.find((c) => c.name === runner);
|
|
67
|
+
const row = facts.providers.providers.find((p) => p.provider === runner);
|
|
68
|
+
const signIn = row?.status ?? 'unknown';
|
|
69
|
+
const installed = check ? check.available : signIn !== 'not-installed';
|
|
70
|
+
const enabled = row?.enabled !== false;
|
|
71
|
+
// The cockpit's own rule (`usableRunners`): enabled AND signed in.
|
|
72
|
+
const usable = enabled && signIn === 'connected';
|
|
73
|
+
const version = installed ? versionLine(check?.version) : undefined;
|
|
74
|
+
return {
|
|
75
|
+
runner,
|
|
76
|
+
installed,
|
|
77
|
+
...(version ? { version } : {}),
|
|
78
|
+
enabled,
|
|
79
|
+
signIn,
|
|
80
|
+
usable,
|
|
81
|
+
...(usable ? {} : { reason: agentReason(runner, enabled, installed ? signIn : 'not-installed') }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function agentReason(runner, enabled, signIn) {
|
|
85
|
+
const label = LABEL[runner];
|
|
86
|
+
if (!enabled)
|
|
87
|
+
return `${label} is disabled in ${PROVIDERS_SETTINGS}.`;
|
|
88
|
+
switch (signIn) {
|
|
89
|
+
case 'not-installed':
|
|
90
|
+
return `${label} is not installed on this machine.`;
|
|
91
|
+
case 'disconnected':
|
|
92
|
+
return `${label} is installed but not signed in. A person can sign in from ${PROVIDERS_SETTINGS}.`;
|
|
93
|
+
default:
|
|
94
|
+
return `${label}'s sign-in could not be verified yet. Call this tool again shortly.`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** A version is one short line of a CLI's `--version`; anything longer is not a version. */
|
|
98
|
+
function versionLine(version) {
|
|
99
|
+
const line = version?.split('\n')[0]?.trim();
|
|
100
|
+
return line ? line.slice(0, 80) : undefined;
|
|
101
|
+
}
|
|
102
|
+
function createTaskReason(agents) {
|
|
103
|
+
if (agents.some((a) => a.usable))
|
|
104
|
+
return null;
|
|
105
|
+
return `No coding agent is ready to run a task. ${agents.map((a) => a.reason).join(' ')}`;
|
|
106
|
+
}
|
|
107
|
+
function toolCheck(name, facts) {
|
|
108
|
+
const available = facts.health.checks.find((c) => c.name === name)?.available === true;
|
|
109
|
+
if (available)
|
|
110
|
+
return { name, available };
|
|
111
|
+
return {
|
|
112
|
+
name,
|
|
113
|
+
available,
|
|
114
|
+
reason: name === 'gh'
|
|
115
|
+
? 'The GitHub CLI (gh) is not installed or not signed in. GitHub features need it; a person can run `gh auth login`.'
|
|
116
|
+
: 'git is not installed on this machine.',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Why the GitHub area is closed, or null when it is open. `gh`'s own error text is CLASSIFIED,
|
|
121
|
+
* never forwarded: it can quote the repository owner, an organisation or an account.
|
|
122
|
+
*/
|
|
123
|
+
function githubUnavailableReason(facts) {
|
|
124
|
+
const { repo, forge } = facts.health;
|
|
125
|
+
if (!repo)
|
|
126
|
+
return 'This project is not a git repository, so it has no GitHub remote.';
|
|
127
|
+
if (!forge)
|
|
128
|
+
return "This repository has no GitHub remote; xezar's GitHub features need a github.com remote.";
|
|
129
|
+
if (forge.available === true)
|
|
130
|
+
return null;
|
|
131
|
+
if (forge.available === undefined) {
|
|
132
|
+
return 'GitHub availability has not been checked yet. Call this tool again in a few seconds.';
|
|
133
|
+
}
|
|
134
|
+
const raw = forge.reason ?? '';
|
|
135
|
+
if (/ENOENT|gh CLI not found/i.test(raw)) {
|
|
136
|
+
return 'The GitHub CLI (gh) is not installed on this machine. A person can install it and run `gh auth login`.';
|
|
137
|
+
}
|
|
138
|
+
if (/auth login|not logged|authenticat|credential|\b401\b/i.test(raw)) {
|
|
139
|
+
return 'The GitHub CLI (gh) is not signed in. A person can run `gh auth login`.';
|
|
140
|
+
}
|
|
141
|
+
return 'The GitHub CLI (gh) could not open this repository on GitHub. Check `gh auth status`, access to the repository and the network.';
|
|
142
|
+
}
|
|
143
|
+
// ---- gathering: the same facts `/health` and `/config` read, for the bound project only ------
|
|
144
|
+
let providerAuth;
|
|
145
|
+
/**
|
|
146
|
+
* `--bind-host` of THIS process. The MCP socket lives inside `xezar serve`, and a non-loopback
|
|
147
|
+
* bind is half of what makes the cockpit hosted; `McpToolContext` does not carry it yet (#89
|
|
148
|
+
* widens that context), and reporting `localHandoff: true` on a hosted box would promise actions
|
|
149
|
+
* the routes refuse.
|
|
150
|
+
*/
|
|
151
|
+
export function bindHostFromArgv(argv = process.argv) {
|
|
152
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
153
|
+
const arg = argv[i];
|
|
154
|
+
if (arg === '--bind-host')
|
|
155
|
+
return argv[i + 1];
|
|
156
|
+
if (arg.startsWith('--bind-host='))
|
|
157
|
+
return arg.slice('--bind-host='.length);
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
export async function collectDiscoveryFacts(ctx, env = process.env) {
|
|
162
|
+
const root = ctx.project.root;
|
|
163
|
+
const [checks, repo, config, workspace] = await Promise.all([
|
|
164
|
+
detectEnvironment(),
|
|
165
|
+
getRepoInfo(root),
|
|
166
|
+
loadConfig(root),
|
|
167
|
+
loadWorkspaceConfig(),
|
|
168
|
+
]);
|
|
169
|
+
const forge = resolveForge(repo);
|
|
170
|
+
// Awaited, unlike `/health`: a tool call can afford the one `gh` probe, and a settled answer
|
|
171
|
+
// beats "not checked yet". The driver caches it for 60 s either way.
|
|
172
|
+
const availability = forge ? await forge.detect().catch(() => ({ available: false })) : null;
|
|
173
|
+
providerAuth ??= new ProviderAuthService();
|
|
174
|
+
const providers = applyProviderEnablement(await providerAuth.status(), workspace.disabledProviders);
|
|
175
|
+
const own = workspace.projects.find((p) => p.id === ctx.project.id);
|
|
176
|
+
const resources = workspace.resources;
|
|
177
|
+
const projectMaxParallel = own?.maxParallel ?? null;
|
|
178
|
+
const projectMemoryLimitMb = typeof config.memoryLimitMb === 'number' && config.memoryLimitMb > 0 ? config.memoryLimitMb : null;
|
|
179
|
+
return {
|
|
180
|
+
project: ctx.project,
|
|
181
|
+
xezarVersion: ctx.xezarVersion,
|
|
182
|
+
health: {
|
|
183
|
+
repo,
|
|
184
|
+
checks,
|
|
185
|
+
defaultRunner: config.defaultRunner,
|
|
186
|
+
forge: forge ? { kind: forge.kind, ...availability } : null,
|
|
187
|
+
capabilities: resolveCapabilities(env, bindHostFromArgv(), workspace.followups),
|
|
188
|
+
},
|
|
189
|
+
config: { baseBranch: config.baseBranch ?? null, modelsLocked: agentModelsLocked(root, env) },
|
|
190
|
+
providers,
|
|
191
|
+
limits: {
|
|
192
|
+
maxParallel: {
|
|
193
|
+
effective: projectMaxParallel ?? resources.maxParallel,
|
|
194
|
+
project: projectMaxParallel,
|
|
195
|
+
workspace: resources.maxParallel,
|
|
196
|
+
},
|
|
197
|
+
memoryLimitMb: {
|
|
198
|
+
effective: projectMemoryLimitMb ?? resources.memoryLimitMb,
|
|
199
|
+
project: projectMemoryLimitMb,
|
|
200
|
+
workspace: resources.memoryLimitMb,
|
|
201
|
+
},
|
|
202
|
+
maxMonitoringSessions: resources.maxMonitoringSessions,
|
|
203
|
+
monitoringWakeIntervalMinutes: resources.monitoringWakeIntervalMinutes,
|
|
204
|
+
autoResumeOnUsageLimit: resources.autoResumeOnUsageLimit,
|
|
205
|
+
idleTimeoutMinutes: resources.idleTimeoutMinutes,
|
|
206
|
+
worktreeRetention: config.worktreeRetention,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/** The authoritative text block (D-05): a one-line orientation, then the whole result. */
|
|
211
|
+
export function discoveryText(discovery) {
|
|
212
|
+
const closed = discovery.actions.filter((a) => a.status !== 'available');
|
|
213
|
+
const lines = [
|
|
214
|
+
`Bound to xezar project "${discovery.project.name}" (id ${discovery.project.id}).`,
|
|
215
|
+
...closed.map((a) => `${a.status === 'read-only' ? 'Read-only' : 'Unavailable'}: ${a.label} — ${a.reason}`),
|
|
216
|
+
'',
|
|
217
|
+
JSON.stringify(discovery, null, 2),
|
|
218
|
+
];
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
export const discoverProjectTool = defineTool({
|
|
222
|
+
name: 'discover_project',
|
|
223
|
+
title: 'Discover the bound project',
|
|
224
|
+
description: 'Read which xezar project this session is bound to, its effective capabilities and limits, and which actions are available. Every action that is unavailable or read-only says why. Call it at the start of a session and again after a person changes settings. It takes no arguments: the project comes from the connection, never from a parameter.',
|
|
225
|
+
inputSchema: z.strictObject({}),
|
|
226
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
227
|
+
async call(_args, ctx) {
|
|
228
|
+
const discovery = buildDiscovery(await collectDiscoveryFacts(ctx));
|
|
229
|
+
return textResult(discoveryText(discovery), discovery);
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/mcp/tools/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type GetRunValue, type ServiceDispatch } from '../service-adapter.ts';
|
|
3
|
+
import { type McpToolContext } from '../tool.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Execution control and session messaging for the bound project's own tasks (#94, F-08, F-09,
|
|
6
|
+
* M-03, M-04; inventory I-032, I-034–I-040).
|
|
7
|
+
*
|
|
8
|
+
* WHAT IT CAN TARGET. A task of the project this connection is bound to, named by its run id —
|
|
9
|
+
* and nothing else. Every action first reads the task through the shared service adapter (#89),
|
|
10
|
+
* whose scope is the connection's project, so another project's task is a 404 before anything
|
|
11
|
+
* is dispatched. There is no argument for a process id, a signal, a command or a path, and this
|
|
12
|
+
* module starts or signals no process itself: every effect is one of the cockpit's own routes,
|
|
13
|
+
* and the RunManager behind that route is the only thing that ever touches an agent process.
|
|
14
|
+
* F-08 is explicit that a generic "kill PID" does not meet the boundary; none exists here.
|
|
15
|
+
*
|
|
16
|
+
* THE SAME STATE MACHINE AS THE COCKPIT. Each action is offered in exactly the states the
|
|
17
|
+
* cockpit offers it (`run-actions.ts` `runActionFlags`, `task-thread.tsx`'s composer routing,
|
|
18
|
+
* `ask-answer.ts` `askDeliveryMode`), and refused — with nothing changed — in every other one.
|
|
19
|
+
* The refusal is checked here AND again by the route, so a state that moved between the read and
|
|
20
|
+
* the write is still refused by the service.
|
|
21
|
+
*
|
|
22
|
+
* NO NEW STATES. Every action lands the task in a state the cockpit already reaches, through the
|
|
23
|
+
* cockpit's own route, so every exit a state already has — a user message, the autonomous
|
|
24
|
+
* nudge, the monitoring wake timer, cancel, finish, the idle close — still applies to it.
|
|
25
|
+
* Nothing here parks a task, holds a session open or schedules anything.
|
|
26
|
+
*
|
|
27
|
+
* WHERE THE SERVICE COMES FROM. `McpToolContext` does not carry the service's in-process entry
|
|
28
|
+
* yet (#86 shipped it without one, #89 left widening it to later work). This tool reads it from
|
|
29
|
+
* an optional `service` field on the context and answers an honest tool error when it is absent;
|
|
30
|
+
* the service passing its app there is the one wiring step this tool cannot take from its own
|
|
31
|
+
* file.
|
|
32
|
+
*
|
|
33
|
+
* STALE WRITES (#250, N-03). Every action changes the task, so every action requires the
|
|
34
|
+
* `expectedVersion` a `task_read` of it handed out, and sends it to the route, which compares it
|
|
35
|
+
* with the task's current version in the same synchronous stretch as the engine call. A task that
|
|
36
|
+
* moved since is refused with nothing applied (`status: "conflict"`, `error: "stale_version"`,
|
|
37
|
+
* `currentVersion`). The version moves with every event a task records, so a RUNNING task's
|
|
38
|
+
* version moves while its agent works: read it right before acting on a running task. The same holds
|
|
39
|
+
* for an answer that meets an idle close: the close changes the task, so the resume after it is
|
|
40
|
+
* refused as stale rather than retried with a fresh version — the leader reads again and answers
|
|
41
|
+
* again (D-06 § 4.4 rule 3).
|
|
42
|
+
*/
|
|
43
|
+
export declare const EXECUTION_CONTROL_ACTIONS: readonly ['cancel', 'finish', 'continue', 'send_message', 'answer_question', 'edit_queued_message', 'remove_queued_message', 'cancel_auto_resume'];
|
|
44
|
+
export type ExecutionControlAction = (typeof EXECUTION_CONTROL_ACTIONS)[number];
|
|
45
|
+
/** The cockpit's own schedule (`ask-answer.ts`): the idle timer closes the backend before the
|
|
46
|
+
* RunManager has released the run, so a resume can arrive a few milliseconds early. Only that
|
|
47
|
+
* exact refusal is retried; every other 409 is an answer. */
|
|
48
|
+
export declare const IDLE_TEARDOWN_RETRY_DELAYS_MS: readonly [50, 100, 200, 400, 800, 1000, 1000, 1000, 1000];
|
|
49
|
+
/** The context this tool reads beyond `McpToolContext`: the running service's in-process entry. */
|
|
50
|
+
export type ExecutionControlContext = McpToolContext & {
|
|
51
|
+
readonly service?: ServiceDispatch;
|
|
52
|
+
};
|
|
53
|
+
export declare const executionControlInputSchema: z.ZodObject<{
|
|
54
|
+
action: z.ZodEnum<{
|
|
55
|
+
answer_question: "answer_question";
|
|
56
|
+
cancel: "cancel";
|
|
57
|
+
cancel_auto_resume: "cancel_auto_resume";
|
|
58
|
+
continue: "continue";
|
|
59
|
+
edit_queued_message: "edit_queued_message";
|
|
60
|
+
finish: "finish";
|
|
61
|
+
remove_queued_message: "remove_queued_message";
|
|
62
|
+
send_message: "send_message";
|
|
63
|
+
}>;
|
|
64
|
+
runId: z.ZodString;
|
|
65
|
+
expectedVersion: z.ZodString;
|
|
66
|
+
operationId: z.ZodString;
|
|
67
|
+
text: z.ZodOptional<z.ZodString>;
|
|
68
|
+
images: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
69
|
+
mediaType: z.ZodString;
|
|
70
|
+
data: z.ZodString;
|
|
71
|
+
}, z.core.$strip>>>;
|
|
72
|
+
finishAs: z.ZodOptional<z.ZodEnum<{
|
|
73
|
+
accept_review: "accept_review";
|
|
74
|
+
close_session: "close_session";
|
|
75
|
+
}>>;
|
|
76
|
+
questionId: z.ZodOptional<z.ZodString>;
|
|
77
|
+
answers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
78
|
+
choices: z.ZodArray<z.ZodString>;
|
|
79
|
+
}, z.core.$strict>>>;
|
|
80
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
export type ExecutionControlInput = z.output<typeof executionControlInputSchema>;
|
|
83
|
+
/** The result, text block and `structuredContent` alike (D-05 § 6.8: the text is authoritative,
|
|
84
|
+
* and the result is a slim projection rather than the task record). */
|
|
85
|
+
export declare const executionControlResultSchema: z.ZodObject<{
|
|
86
|
+
applied: z.ZodOptional<z.ZodLiteral<false>>;
|
|
87
|
+
error: z.ZodOptional<z.ZodLiteral<"stale_version">>;
|
|
88
|
+
resource: z.ZodOptional<z.ZodObject<{
|
|
89
|
+
kind: z.ZodString;
|
|
90
|
+
id: z.ZodString;
|
|
91
|
+
}, z.core.$strip>>;
|
|
92
|
+
currentVersion: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
93
|
+
changedSince: z.ZodOptional<z.ZodLiteral<true>>;
|
|
94
|
+
guidance: z.ZodOptional<z.ZodLiteral<"Not applied: this changed after you read it. Read the current state and decide again; a new decision is a new operation.">>;
|
|
95
|
+
action: z.ZodEnum<{
|
|
96
|
+
answer_question: "answer_question";
|
|
97
|
+
cancel: "cancel";
|
|
98
|
+
cancel_auto_resume: "cancel_auto_resume";
|
|
99
|
+
continue: "continue";
|
|
100
|
+
edit_queued_message: "edit_queued_message";
|
|
101
|
+
finish: "finish";
|
|
102
|
+
remove_queued_message: "remove_queued_message";
|
|
103
|
+
send_message: "send_message";
|
|
104
|
+
}>;
|
|
105
|
+
accepted: z.ZodBoolean;
|
|
106
|
+
status: z.ZodEnum<{
|
|
107
|
+
accepted: "accepted";
|
|
108
|
+
cancelled: "cancelled";
|
|
109
|
+
conflict: "conflict";
|
|
110
|
+
done: "done";
|
|
111
|
+
failed: "failed";
|
|
112
|
+
}>;
|
|
113
|
+
subject: z.ZodObject<{
|
|
114
|
+
type: z.ZodLiteral<"run">;
|
|
115
|
+
id: z.ZodString;
|
|
116
|
+
}, z.core.$strip>;
|
|
117
|
+
runStatus: z.ZodOptional<z.ZodString>;
|
|
118
|
+
delivery: z.ZodOptional<z.ZodEnum<{
|
|
119
|
+
amended: "amended";
|
|
120
|
+
continued: "continued";
|
|
121
|
+
deferred: "deferred";
|
|
122
|
+
live: "live";
|
|
123
|
+
resumed: "resumed";
|
|
124
|
+
}>>;
|
|
125
|
+
questionId: z.ZodOptional<z.ZodString>;
|
|
126
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
127
|
+
hadPendingAutoResume: z.ZodOptional<z.ZodBoolean>;
|
|
128
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
129
|
+
origin: z.ZodLiteral<"mcp">;
|
|
130
|
+
}, z.core.$strip>;
|
|
131
|
+
export type ExecutionControlResult = z.infer<typeof executionControlResultSchema>;
|
|
132
|
+
type Run = GetRunValue;
|
|
133
|
+
/** `ask-answer.ts` `askDeliveryMode`. */
|
|
134
|
+
export declare function askDeliveryMode(run: Pick<Run, 'status' | 'steps'>): 'live' | 'resume' | 'unavailable';
|
|
135
|
+
declare const askQuestionSchema: z.ZodObject<{
|
|
136
|
+
header: z.ZodString;
|
|
137
|
+
options: z.ZodArray<z.ZodObject<{
|
|
138
|
+
label: z.ZodString;
|
|
139
|
+
}, z.core.$loose>>;
|
|
140
|
+
multiSelect: z.ZodOptional<z.ZodBoolean>;
|
|
141
|
+
}, z.core.$loose>;
|
|
142
|
+
type AskQuestion = z.infer<typeof askQuestionSchema>;
|
|
143
|
+
export interface PendingQuestion {
|
|
144
|
+
requestId: string;
|
|
145
|
+
questions: AskQuestion[];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The one question an answer can reach: the newest `ask.requested` with no `user-message` after
|
|
149
|
+
* it — the cockpit's reducer (`thread-state.ts`), which resolves whichever ask is pending with
|
|
150
|
+
* the next user message. An older ask that a newer one superseded is NOT pending, however
|
|
151
|
+
* unanswered it looks: a message sent for it would be read as the answer to the newer one.
|
|
152
|
+
* `events` may be in any order; a malformed ask is skipped, exactly as the reducer skips it.
|
|
153
|
+
*/
|
|
154
|
+
export declare function pendingQuestionIn(events: ReadonlyArray<{
|
|
155
|
+
seq: number;
|
|
156
|
+
type: string;
|
|
157
|
+
} & Record<string, unknown>>): PendingQuestion | null | undefined;
|
|
158
|
+
/** The ask card's answer text (`ask-card.tsx` `formatAnswer`), one line per question. */
|
|
159
|
+
export declare function formatAnswers(questions: readonly AskQuestion[], answers: ReadonlyArray<{
|
|
160
|
+
choices: readonly string[];
|
|
161
|
+
}>): {
|
|
162
|
+
ok: true;
|
|
163
|
+
text: string;
|
|
164
|
+
} | {
|
|
165
|
+
ok: false;
|
|
166
|
+
error: string;
|
|
167
|
+
};
|
|
168
|
+
/** Build the tool over an injectable wait, so the idle-teardown schedule is testable. */
|
|
169
|
+
export declare function createExecutionControlTool(wait?: (ms: number) => Promise<void>): import("../tool.ts").McpTool<z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>;
|
|
170
|
+
export declare const executionControlTool: import("../tool.ts").McpTool<z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>;
|
|
171
|
+
export {};
|