@intentius/chant-lexicon-fountain 0.56.0 → 0.58.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 +20 -4
- package/dist/acp/command-line.d.ts +61 -0
- package/dist/acp/command-line.d.ts.map +1 -0
- package/dist/acp/host.d.ts +63 -0
- package/dist/acp/host.d.ts.map +1 -0
- package/dist/acp/index.d.ts +16 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/jsonrpc.d.ts +87 -0
- package/dist/acp/jsonrpc.d.ts.map +1 -0
- package/dist/acp/output.d.ts +28 -0
- package/dist/acp/output.d.ts.map +1 -0
- package/dist/acp/protocol.d.ts +160 -0
- package/dist/acp/protocol.d.ts.map +1 -0
- package/dist/acp/serve.d.ts +15 -0
- package/dist/acp/serve.d.ts.map +1 -0
- package/dist/acp/server.d.ts +76 -0
- package/dist/acp/server.d.ts.map +1 -0
- package/dist/acp/turn.d.ts +72 -0
- package/dist/acp/turn.d.ts.map +1 -0
- package/dist/allowlist-refs.d.ts +88 -0
- package/dist/allowlist-refs.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/generate-lexicon.d.ts +11 -0
- package/dist/codegen/generate-lexicon.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/composites/steward.d.ts +94 -0
- package/dist/composites/steward.d.ts.map +1 -0
- package/dist/config.d.ts +106 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/coverage.d.ts +11 -3
- package/dist/coverage.d.ts.map +1 -1
- package/dist/deep-observe-hooks.d.ts +20 -2
- package/dist/deep-observe-hooks.d.ts.map +1 -1
- package/dist/deep-observe.d.ts +38 -17
- package/dist/deep-observe.d.ts.map +1 -1
- package/dist/describe-resources.d.ts +16 -9
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/disruption.d.ts +49 -0
- package/dist/disruption.d.ts.map +1 -0
- package/dist/export-resources.d.ts +22 -9
- package/dist/export-resources.d.ts.map +1 -1
- package/dist/generated/index.d.ts +3 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/init-templates.d.ts +9 -1
- package/dist/init-templates.d.ts.map +1 -1
- package/dist/integrity.json +12 -7
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-lineage.d.ts +10 -0
- package/dist/lint/audit-lineage.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn016-runtime-model-valid.d.ts.map +1 -1
- package/dist/lint/post-synth/ftn020-schedule-cron-syntax.d.ts +26 -0
- package/dist/lint/post-synth/ftn020-schedule-cron-syntax.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn021-typed-references-resolve.d.ts +3 -0
- package/dist/lint/post-synth/ftn021-typed-references-resolve.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn022-webhook-url-public-https.d.ts +5 -0
- package/dist/lint/post-synth/ftn022-webhook-url-public-https.d.ts.map +1 -0
- package/dist/lint/post-synth/ftn023-acp-runtime-command.d.ts +16 -0
- package/dist/lint/post-synth/ftn023-acp-runtime-command.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/rules/ftn001-no-secret-literals.d.ts.map +1 -1
- package/dist/live-identity.d.ts +120 -0
- package/dist/live-identity.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/lexicon-index.d.ts +4 -0
- package/dist/lsp/lexicon-index.d.ts.map +1 -0
- package/dist/manifest.json +2 -2
- package/dist/meta.json +113 -1
- package/dist/okf/index.md +8 -1
- package/dist/okf/rules/FTN001.md +2 -2
- package/dist/okf/rules/FTN020.md +15 -0
- package/dist/okf/rules/FTN021.md +17 -0
- package/dist/okf/rules/FTN022.md +15 -0
- package/dist/okf/rules/FTN023.md +15 -0
- package/dist/okf/types/Agent.md +9 -2
- package/dist/okf/types/Environment.md +2 -2
- package/dist/okf/types/Schedule.md +23 -0
- package/dist/okf/types/Teammate.md +20 -0
- package/dist/okf/types/Vault.md +1 -1
- package/dist/okf/types/Webhook.md +19 -0
- package/dist/op/activities/fountain-apply.d.ts +78 -8
- package/dist/op/activities/fountain-apply.d.ts.map +1 -1
- package/dist/op/activities/fountain-run.d.ts +10 -2
- package/dist/op/activities/fountain-run.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +2 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/run-prompt.d.ts +14 -0
- package/dist/op/run-prompt.d.ts.map +1 -0
- package/dist/op/runtime.d.ts +237 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rules/ftn001-no-secret-literals.ts +74 -19
- package/dist/rules/ftn016-runtime-model-valid.ts +22 -1
- package/dist/rules/ftn020-schedule-cron-syntax.ts +57 -0
- package/dist/rules/ftn021-typed-references-resolve.ts +87 -0
- package/dist/rules/ftn022-webhook-url-public-https.ts +89 -0
- package/dist/rules/ftn023-acp-runtime-command.ts +57 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/skills/chant-fountain-ops.md +164 -0
- package/dist/skills/chant-fountain.md +26 -2
- package/dist/spec/fetch.d.ts +6 -4
- package/dist/spec/fetch.d.ts.map +1 -1
- package/dist/spec/parse.d.ts +26 -6
- package/dist/spec/parse.d.ts.map +1 -1
- package/dist/types/index.d.ts +81 -2
- package/dist/validate.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/acp/acp.test.ts +723 -0
- package/src/acp/command-line.ts +168 -0
- package/src/acp/host.ts +104 -0
- package/src/acp/index.ts +52 -0
- package/src/acp/jsonrpc.ts +239 -0
- package/src/acp/output.ts +59 -0
- package/src/acp/protocol.ts +151 -0
- package/src/acp/serve.ts +43 -0
- package/src/acp/server.ts +337 -0
- package/src/acp/turn.ts +311 -0
- package/src/allowlist-refs.ts +138 -0
- package/src/codegen/docs.ts +17 -4
- package/src/codegen/generate-lexicon.ts +13 -0
- package/src/codegen/naming.ts +3 -0
- package/src/composites/composites.test.ts +183 -1
- package/src/composites/steward.ts +245 -0
- package/src/config.test.ts +126 -0
- package/src/config.ts +113 -0
- package/src/coverage.test.ts +8 -1
- package/src/coverage.ts +65 -16
- package/src/deep-observe-hooks.ts +46 -2
- package/src/deep-observe.test.ts +435 -11
- package/src/deep-observe.ts +241 -93
- package/src/describe-resources.test.ts +180 -0
- package/src/describe-resources.ts +125 -70
- package/src/disruption.test.ts +163 -0
- package/src/disruption.ts +141 -0
- package/src/export-resources.ts +172 -22
- package/src/generated/index.d.ts +81 -2
- package/src/generated/index.ts +6 -3
- package/src/generated/lexicon-fountain.json +113 -1
- package/src/import/parser.ts +3 -0
- package/src/import/roundtrip.test.ts +258 -23
- package/src/index.ts +24 -0
- package/src/init-templates.test.ts +182 -0
- package/src/init-templates.ts +158 -1
- package/src/lint/audit-catalog.ts +38 -1
- package/src/lint/audit-lineage.ts +15 -0
- package/src/lint/post-synth/ftn016-runtime-model-valid.ts +22 -1
- package/src/lint/post-synth/ftn020-schedule-cron-syntax.ts +57 -0
- package/src/lint/post-synth/ftn021-typed-references-resolve.ts +87 -0
- package/src/lint/post-synth/ftn022-webhook-url-public-https.ts +89 -0
- package/src/lint/post-synth/ftn023-acp-runtime-command.ts +57 -0
- package/src/lint/post-synth/index.ts +8 -0
- package/src/lint/post-synth/post-synth.test.ts +149 -0
- package/src/lint/rules/ftn001-no-secret-literals.ts +74 -19
- package/src/lint/rules/rules.test.ts +35 -0
- package/src/live-identity.ts +288 -0
- package/src/lsp/completions.test.ts +24 -5
- package/src/lsp/completions.ts +3 -13
- package/src/lsp/hover.test.ts +12 -1
- package/src/lsp/hover.ts +22 -14
- package/src/lsp/lexicon-index.ts +45 -0
- package/src/op/activities/fountain-apply.test.ts +594 -4
- package/src/op/activities/fountain-apply.ts +579 -52
- package/src/op/activities/fountain-run.ts +16 -4
- package/src/op/activities/index.ts +2 -0
- package/src/op/run-prompt.ts +16 -0
- package/src/op/runtime.test.ts +943 -0
- package/src/op/runtime.ts +1230 -0
- package/src/plugin.test.ts +14 -5
- package/src/plugin.ts +49 -2
- package/src/serializer.test.ts +107 -0
- package/src/serializer.ts +20 -1
- package/src/skills/chant-fountain-ops.md +164 -0
- package/src/skills/chant-fountain.md +26 -2
- package/src/spec/fetch.ts +6 -4
- package/src/spec/fountain-openapi.snapshot.json +14979 -1
- package/src/spec/parse.ts +188 -11
- package/src/validate.ts +9 -1
package/README.md
CHANGED
|
@@ -5,15 +5,17 @@ fountain lexicon plugin for [chant](https://github.com/intentius/chant).
|
|
|
5
5
|
[fountain](https://github.com/BinaryBourbon/fountain) runs coding agents in
|
|
6
6
|
sandboxed VMs. This lexicon declares its workload layer as typed chant
|
|
7
7
|
resources: `Environment` (sandbox baseline), `Vault` (env-var overrides),
|
|
8
|
-
`Agent` (a runnable agent config)
|
|
9
|
-
|
|
8
|
+
`Agent` (a runnable agent config), `Teammate` (an agent seated on the team,
|
|
9
|
+
with a thread of its own), `Schedule` (a cron prompt into that thread), and
|
|
10
|
+
`Webhook` (where the estate's events leave it). Conversations are runs, not
|
|
11
|
+
resources — start them with the `fountainRun` op.
|
|
10
12
|
|
|
11
13
|
`chant build` serializes to fountain's own manifest YAML (`fountain apply -f`
|
|
12
14
|
accepts it verbatim) — the same YAML `fountainApply` sends to fountain's bulk
|
|
13
15
|
`POST /api/apply` endpoint in one request.
|
|
14
16
|
|
|
15
17
|
```ts
|
|
16
|
-
import { Environment, Agent } from "@intentius/chant-lexicon-fountain";
|
|
18
|
+
import { Environment, Agent, Teammate, Schedule } from "@intentius/chant-lexicon-fountain";
|
|
17
19
|
|
|
18
20
|
export const env = new Environment({
|
|
19
21
|
name: "team-env",
|
|
@@ -28,8 +30,22 @@ export const helper = new Agent({
|
|
|
28
30
|
runtime: "claude",
|
|
29
31
|
environment: env, // typed ref — dangling name = build error
|
|
30
32
|
});
|
|
33
|
+
|
|
34
|
+
export const helperSeat = new Teammate({ name: "helper", agent: helper });
|
|
35
|
+
|
|
36
|
+
export const nightly = new Schedule({
|
|
37
|
+
name: "nightly-converge",
|
|
38
|
+
teammate: helperSeat,
|
|
39
|
+
cron: "0 3 * * *", // five fields, UTC (FTN020)
|
|
40
|
+
prompt: "chant run converge",
|
|
41
|
+
});
|
|
31
42
|
```
|
|
32
43
|
|
|
44
|
+
`runtime: "acp"` and `runtime_command` are on the generated `Agent` type as
|
|
45
|
+
chant extensions. Upstream does not have them until
|
|
46
|
+
[BinaryBourbon/fountain#1634](https://github.com/BinaryBourbon/fountain/pull/1634)
|
|
47
|
+
lands, and an instance without that PR rejects the pair at apply.
|
|
48
|
+
|
|
33
49
|
For agents handling anything sensitive, `ConciergeStack` bundles the
|
|
34
50
|
locked-down defaults (deny-all egress, no vault overrides, ownership marker
|
|
35
51
|
on both resources) so loosening any of them is a visible, reviewable
|
|
@@ -61,7 +77,7 @@ left unmodeled.
|
|
|
61
77
|
- `src/plugin.ts` — LexiconPlugin with all lifecycle methods
|
|
62
78
|
- `src/serializer.ts` — manifest YAML output
|
|
63
79
|
- `src/codegen/`, `src/spec/` — generation pipeline and spec fetch/parse
|
|
64
|
-
- `src/lint/rules/`, `src/lint/post-synth/` — FTN001 (AST) and FTN010
|
|
80
|
+
- `src/lint/rules/`, `src/lint/post-synth/` — FTN001 (AST) and FTN010 to FTN023
|
|
65
81
|
- `src/op/activities/` — `fountainApply` (reconciler) and `fountainRun`
|
|
66
82
|
- `src/composites/` — `ConciergeStack`
|
|
67
83
|
- `src/skills/` — agent skills for authoring, secrets, and locked sandboxes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A prompt is a chant command line (#2125).
|
|
3
|
+
*
|
|
4
|
+
* That is the whole convention, and the reason a fountain thread reads as an
|
|
5
|
+
* environment's shell history: each turn is `chant run prod-apply --env prod`
|
|
6
|
+
* or `chant lifecycle diff --live`, so scrolling the thread is scrolling what
|
|
7
|
+
* was done to the environment.
|
|
8
|
+
*
|
|
9
|
+
* It is a *command line*, not a shell line. This module splits on whitespace
|
|
10
|
+
* with quote awareness and stops there: no expansion, no substitution, no
|
|
11
|
+
* pipes, no `&&`, no globbing, no `$VAR`. A prompt that does not parse to a
|
|
12
|
+
* chant verb is refused before anything runs, which is what keeps an agent
|
|
13
|
+
* that can be prompted by anyone from being an agent that can run anything.
|
|
14
|
+
* The verb list is core's own registry, so the set of things this accepts is
|
|
15
|
+
* exactly the set `chant --help` prints.
|
|
16
|
+
*/
|
|
17
|
+
import type { ParsedArgs, CommandDef } from "@intentius/chant/cli/registry";
|
|
18
|
+
/**
|
|
19
|
+
* Split a command line into argv the way a shell would *quote* it, and in no
|
|
20
|
+
* other way.
|
|
21
|
+
*
|
|
22
|
+
* Single and double quotes group, a backslash escapes the next character
|
|
23
|
+
* inside double quotes and outside them, and nothing else is special. An
|
|
24
|
+
* unterminated quote is an error rather than a silent join, because the
|
|
25
|
+
* silent reading changes which arguments a verb receives.
|
|
26
|
+
*/
|
|
27
|
+
export declare function tokenize(text: string): string[];
|
|
28
|
+
/** A prompt that resolved to something chant can run. */
|
|
29
|
+
export type ChantCommand = {
|
|
30
|
+
/** `chant run <op>` — the path that goes through the op runtime provider. */
|
|
31
|
+
kind: "op-run";
|
|
32
|
+
op: string;
|
|
33
|
+
args: ParsedArgs;
|
|
34
|
+
argv: string[];
|
|
35
|
+
} | {
|
|
36
|
+
/** Any other chant verb — run through its own registry handler. */
|
|
37
|
+
kind: "verb";
|
|
38
|
+
name: string;
|
|
39
|
+
def: CommandDef;
|
|
40
|
+
compound: boolean;
|
|
41
|
+
args: ParsedArgs;
|
|
42
|
+
argv: string[];
|
|
43
|
+
};
|
|
44
|
+
/** Either a command, or the reason the prompt is not one. */
|
|
45
|
+
export type CommandLineParse = {
|
|
46
|
+
ok: true;
|
|
47
|
+
command: ChantCommand;
|
|
48
|
+
} | {
|
|
49
|
+
ok: false;
|
|
50
|
+
message: string;
|
|
51
|
+
hint: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Parse one prompt into a runnable chant command, or refuse it.
|
|
55
|
+
*
|
|
56
|
+
* Core's registry and argv parser are imported here rather than at module
|
|
57
|
+
* load: nothing about declaring the fountain lexicon should pull in every CLI
|
|
58
|
+
* handler, and only a live `chant acp` turn ever reaches this.
|
|
59
|
+
*/
|
|
60
|
+
export declare function parseChantCommandLine(text: string): Promise<CommandLineParse>;
|
|
61
|
+
//# sourceMappingURL=command-line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-line.d.ts","sourceRoot":"","sources":["../../src/acp/command-line.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE5E;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAsC/C;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GACpB;IACE,6EAA6E;IAC7E,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,GACD;IACE,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEN,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4DnF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a turn needs from chant, stated once (#2125).
|
|
3
|
+
*
|
|
4
|
+
* The ACP server owns the protocol — sessions, updates, stop reasons — and
|
|
5
|
+
* nothing else. Everything it does *to a project* goes through this seam:
|
|
6
|
+
* finding an Op, starting it on a runtime provider, running any other chant
|
|
7
|
+
* verb, and recording a gate resolution. The conformance test drives the
|
|
8
|
+
* protocol through a stub host, so the tool-call ordering, the cancel path and
|
|
9
|
+
* the gated reply are tested without a checkout, a git branch or a real Op.
|
|
10
|
+
*
|
|
11
|
+
* The real implementation is `createChantHost`, and it is deliberately thin:
|
|
12
|
+
* `createLocalOpRuntime` from core is the provider (#2121), `discoverOps` is
|
|
13
|
+
* the lookup, and a verb runs through core's own registry handler rather than
|
|
14
|
+
* a reimplementation of it. Nothing here shells out — a prompt is parsed and
|
|
15
|
+
* dispatched in this process, so there is no line for a shell to interpret.
|
|
16
|
+
*/
|
|
17
|
+
import type { OpConfig } from "@intentius/chant/op/types";
|
|
18
|
+
import type { OpRunHandle, OpRunStartOptions } from "@intentius/chant/op/runtime";
|
|
19
|
+
import type { ChantCommand } from "./command-line.js";
|
|
20
|
+
/**
|
|
21
|
+
* What one `*.op.ts` scan found.
|
|
22
|
+
*
|
|
23
|
+
* `errors` is carried rather than dropped because the failure mode it names is
|
|
24
|
+
* indistinguishable from the innocent one: an Op file that will not import
|
|
25
|
+
* reports as "no such Op", and a person reading that in a thread has been told
|
|
26
|
+
* the wrong thing. `chant run` prints these as warnings; so does a turn.
|
|
27
|
+
*/
|
|
28
|
+
export interface OpLookup {
|
|
29
|
+
/** The Op the prompt named, when the scan found it. */
|
|
30
|
+
config?: OpConfig;
|
|
31
|
+
/** Every Op name the scan did find, for the "not declared" reply's hint. */
|
|
32
|
+
names: string[];
|
|
33
|
+
/** Files the scan could not read as an Op. */
|
|
34
|
+
errors: string[];
|
|
35
|
+
}
|
|
36
|
+
/** The project-facing half of a turn. */
|
|
37
|
+
export interface ChantHost {
|
|
38
|
+
/** Where chant runs — the session's `cwd`. */
|
|
39
|
+
readonly cwd: string;
|
|
40
|
+
/** Scan the project for Ops and pick out the one this name declares. */
|
|
41
|
+
findOp(name: string): Promise<OpLookup>;
|
|
42
|
+
/** Start an Op on the resolved runtime provider. */
|
|
43
|
+
startOp(op: OpConfig, opts: OpRunStartOptions): Promise<OpRunHandle>;
|
|
44
|
+
/** Run a non-`run` chant verb. Returns its exit code; output goes to the process writers. */
|
|
45
|
+
runVerb(command: Extract<ChantCommand, {
|
|
46
|
+
kind: "verb";
|
|
47
|
+
}>, signal: AbortSignal): Promise<number>;
|
|
48
|
+
/** Record a gate resolution, the way `chant approve` does (durable-request resume). */
|
|
49
|
+
resolveGate(op: string, gate: string, resolvedBy: string): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/** How the real host identifies itself on a gate resolution it writes. */
|
|
52
|
+
export declare const ACP_APPROVER = "chant-acp";
|
|
53
|
+
/**
|
|
54
|
+
* The real host, bound to one session's working directory.
|
|
55
|
+
*
|
|
56
|
+
* Core's machinery reads the project from `process.cwd()`, so a turn changes
|
|
57
|
+
* into `cwd` for its duration (see ./turn.ts) rather than threading a path
|
|
58
|
+
* through every call — which is also why turns are serialized. Every import
|
|
59
|
+
* below is dynamic: declaring the fountain lexicon must not pull core's CLI
|
|
60
|
+
* handlers into a `chant build`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createChantHost(cwd: string): ChantHost;
|
|
63
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/acp/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,oDAAoD;IACpD,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrE,6FAA6F;IAC7F,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChG,uFAAuF;IACvF,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E;AAED,0EAA0E;AAC1E,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAuCtD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant acp` — the CLI mount for the ACP server (#2125).
|
|
3
|
+
*
|
|
4
|
+
* A command group with a `defaultVerb`, so the bare `chant acp` an editor or a
|
|
5
|
+
* fountain Agent spawns (`runtime_command: "chant acp"`) reaches `serve`
|
|
6
|
+
* without the client having to know chant's verb grammar. `chant acp serve`
|
|
7
|
+
* is the same thing spelled out.
|
|
8
|
+
*
|
|
9
|
+
* The server itself is behind a dynamic import: mounting the group happens
|
|
10
|
+
* every time a plugin loads, and nothing about `chant build` should pay for a
|
|
11
|
+
* JSON-RPC peer it will never open.
|
|
12
|
+
*/
|
|
13
|
+
import type { CommandGroup } from "@intentius/chant/cli/command-group";
|
|
14
|
+
/** The verb group `chant acp` mounts. */
|
|
15
|
+
export declare function acpCommandGroup(): CommandGroup;
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,oCAAoC,CAAC;AAK5F,yCAAyC;AACzC,wBAAgB,eAAe,IAAI,YAAY,CAa9C"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Newline-delimited JSON-RPC 2.0, both directions (#2125).
|
|
3
|
+
*
|
|
4
|
+
* ACP frames one JSON value per line. That is the whole transport, which is
|
|
5
|
+
* why this is ~150 lines of local code instead of a dependency: an agent that
|
|
6
|
+
* speaks the protocol needs a line reader, a writer that serializes its two
|
|
7
|
+
* writers, and a table of outbound requests waiting on answers.
|
|
8
|
+
*
|
|
9
|
+
* The peer is stream-agnostic on purpose. `chant acp` hands it the process's
|
|
10
|
+
* stdin and stdout; the conformance test hands it a pair of in-memory pipes
|
|
11
|
+
* and drives the client side in the same process, so the test exercises the
|
|
12
|
+
* real framing rather than a mock of it.
|
|
13
|
+
*/
|
|
14
|
+
import type { Readable, Writable } from "node:stream";
|
|
15
|
+
/** The four JSON-RPC message kinds, told apart by which fields are present. */
|
|
16
|
+
export interface JsonRpcMessage {
|
|
17
|
+
jsonrpc?: string;
|
|
18
|
+
id?: string | number | null;
|
|
19
|
+
method?: string;
|
|
20
|
+
params?: unknown;
|
|
21
|
+
result?: unknown;
|
|
22
|
+
error?: {
|
|
23
|
+
code: number;
|
|
24
|
+
message: string;
|
|
25
|
+
data?: unknown;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** An error a handler wants reported with a specific JSON-RPC code. */
|
|
29
|
+
export declare class JsonRpcError extends Error {
|
|
30
|
+
readonly code: number;
|
|
31
|
+
readonly data?: unknown | undefined;
|
|
32
|
+
constructor(code: number, message: string, data?: unknown | undefined);
|
|
33
|
+
}
|
|
34
|
+
/** What the peer dispatches incoming traffic to. */
|
|
35
|
+
export interface JsonRpcHandler {
|
|
36
|
+
/** Answer a request. The returned value is encoded as `result`. */
|
|
37
|
+
request(method: string, params: unknown): Promise<unknown>;
|
|
38
|
+
/** Handle a notification. JSON-RPC forbids a reply, so a rejection is dropped. */
|
|
39
|
+
notify(method: string, params: unknown): void;
|
|
40
|
+
}
|
|
41
|
+
/** A line-delimited byte channel, so the peer never names a stream type. */
|
|
42
|
+
export interface LineTransport {
|
|
43
|
+
send(line: string): void;
|
|
44
|
+
onLine(cb: (line: string) => void): void;
|
|
45
|
+
onClose(cb: () => void): void;
|
|
46
|
+
close(): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A transport over a pair of Node streams — stdin and stdout, for `chant acp`.
|
|
50
|
+
*
|
|
51
|
+
* The writer is bound here, at construction, and that is load-bearing rather
|
|
52
|
+
* than tidy. A turn replaces `process.stdout.write` to stream a command's
|
|
53
|
+
* output (../acp/output.ts); if this looked the method up per call it would
|
|
54
|
+
* find the interceptor, every protocol line the turn emits would come back as
|
|
55
|
+
* another message chunk to emit, and the first notification sent inside a turn
|
|
56
|
+
* would recurse until V8 refused to grow the string. Binding once means the
|
|
57
|
+
* protocol always reaches the real stdout.
|
|
58
|
+
*/
|
|
59
|
+
export declare function streamTransport(input: Readable, output: Writable): LineTransport;
|
|
60
|
+
/** An in-memory transport pair — one end for each side of a connection. */
|
|
61
|
+
export declare function memoryTransportPair(): [LineTransport, LineTransport];
|
|
62
|
+
/**
|
|
63
|
+
* One connection, serving a handler and able to originate requests of its own.
|
|
64
|
+
*
|
|
65
|
+
* The agent has two writers — request responses, and the `session/update`
|
|
66
|
+
* notifications a turn emits while a response is still pending. `send` is the
|
|
67
|
+
* single funnel for both, so two interleaved writes can never produce one
|
|
68
|
+
* unparseable line.
|
|
69
|
+
*/
|
|
70
|
+
export declare class JsonRpcPeer {
|
|
71
|
+
private readonly transport;
|
|
72
|
+
private readonly handler;
|
|
73
|
+
private nextId;
|
|
74
|
+
private readonly pending;
|
|
75
|
+
private closed;
|
|
76
|
+
constructor(transport: LineTransport, handler: JsonRpcHandler);
|
|
77
|
+
/** Send a notification. Fire and forget, by definition. */
|
|
78
|
+
notify(method: string, params: unknown): void;
|
|
79
|
+
/** Send a request and resolve with its `result`, or reject with its `error`. */
|
|
80
|
+
request(method: string, params: unknown): Promise<unknown>;
|
|
81
|
+
/** Stop serving and fail every outbound request still waiting. */
|
|
82
|
+
close(): void;
|
|
83
|
+
private shutdown;
|
|
84
|
+
private write;
|
|
85
|
+
private receive;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=jsonrpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonrpc.d.ts","sourceRoot":"","sources":["../../src/acp/jsonrpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D;AAED,uEAAuE;AACvE,qBAAa,YAAa,SAAQ,KAAK;IAEnC,QAAQ,CAAC,IAAI,EAAE,MAAM;IAErB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO;gBAFd,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACN,IAAI,CAAC,EAAE,OAAO,YAAA;CAK1B;AAED,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,kFAAkF;IAClF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/C;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,aAAa,CAkChF;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CA8BpE;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW;IASpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAT1B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGpB;IACJ,OAAO,CAAC,MAAM,CAAS;gBAGJ,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,cAAc;IAM1C,2DAA2D;IAC3D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAI7C,gFAAgF;IAChF,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ1D,kEAAkE;IAClE,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,KAAK;YAKC,OAAO;CA8CtB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capturing what a chant command prints, so a turn can stream it (#2125).
|
|
3
|
+
*
|
|
4
|
+
* chant's own handlers and its activities print through `console.log` /
|
|
5
|
+
* `console.error`, which means the process's stdout and stderr are where a
|
|
6
|
+
* step's output actually appears — there is no per-step output channel on the
|
|
7
|
+
* executor to subscribe to instead. So a turn borrows both writers for its
|
|
8
|
+
* duration and forwards every chunk as an `agent_message_chunk`.
|
|
9
|
+
*
|
|
10
|
+
* Two consequences worth stating rather than discovering:
|
|
11
|
+
*
|
|
12
|
+
* - The `chant acp` process writes the protocol on stdout, so a turn MUST
|
|
13
|
+
* hold this capture over everything it runs. A stray `console.log` reaching
|
|
14
|
+
* the real stdout mid-turn is an unparseable line to the client.
|
|
15
|
+
* - The capture is process-wide, so turns are serialized (see
|
|
16
|
+
* ./server.ts). One stdio connection running one command at a time is the
|
|
17
|
+
* honest shape anyway.
|
|
18
|
+
*
|
|
19
|
+
* Redaction is deliberately absent. A step's output is the environment's
|
|
20
|
+
* output, and fountain redacts a thread's secrets on the way in — the
|
|
21
|
+
* documented division of labour in ../skills/chant-fountain.md. This server
|
|
22
|
+
* never reads or prints the environment it inherits.
|
|
23
|
+
*/
|
|
24
|
+
/** Where a captured chunk came from. */
|
|
25
|
+
export type OutputStream = "stdout" | "stderr";
|
|
26
|
+
/** Run `fn` with both process writers forwarded to `onChunk`, and restore them after. */
|
|
27
|
+
export declare function withCapturedOutput<T>(onChunk: (text: string, stream: OutputStream) => void, fn: () => Promise<T>): Promise<T>;
|
|
28
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/acp/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,wCAAwC;AACxC,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/C,yFAAyF;AACzF,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,KAAK,IAAI,EACrD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CA2BZ"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Agent Client Protocol wire shapes `chant acp` speaks (#2125).
|
|
3
|
+
*
|
|
4
|
+
* ACP (<https://agentclientprotocol.com>) is JSON-RPC 2.0 between a *client*
|
|
5
|
+
* — an editor, or fountain — and an *agent*. chant is the agent half here: it
|
|
6
|
+
* is spawned, it answers `initialize`, it opens sessions, and every prompt it
|
|
7
|
+
* receives is one chant command line.
|
|
8
|
+
*
|
|
9
|
+
* These are hand-written rather than pulled from a package on purpose. The
|
|
10
|
+
* subset an agent has to speak is small enough to state in one file, and a
|
|
11
|
+
* dependency for it would be a dependency in every project that declares the
|
|
12
|
+
* fountain lexicon. Field names match what fountain's own ACP client sends
|
|
13
|
+
* and expects (fountain ADR 0014, `cli/internal/acp`), which is the same
|
|
14
|
+
* vocabulary the specification defines — a client of ours that is not
|
|
15
|
+
* fountain sees nothing fountain-specific.
|
|
16
|
+
*/
|
|
17
|
+
/** The ACP major version this agent speaks. */
|
|
18
|
+
export declare const ACP_PROTOCOL_VERSION = 1;
|
|
19
|
+
/** JSON-RPC 2.0 error codes, plus the one ACP adds. */
|
|
20
|
+
export declare const JSONRPC_PARSE_ERROR = -32700;
|
|
21
|
+
export declare const JSONRPC_INVALID_REQUEST = -32600;
|
|
22
|
+
export declare const JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
23
|
+
export declare const JSONRPC_INVALID_PARAMS = -32602;
|
|
24
|
+
export declare const JSONRPC_INTERNAL_ERROR = -32603;
|
|
25
|
+
/**
|
|
26
|
+
* How a turn ended.
|
|
27
|
+
*
|
|
28
|
+
* `end_turn`, `cancelled` and `refusal` are the specification's.
|
|
29
|
+
*
|
|
30
|
+
* `waiting` is not: it is what `--durable-requests` returns for a run that
|
|
31
|
+
* stopped at a gate whose `session/request_permission` will be answered after
|
|
32
|
+
* this turn is over (BinaryBourbon/fountain#1635). Until that ships, no client
|
|
33
|
+
* can answer such a request within the turn, and reporting `end_turn` for a
|
|
34
|
+
* run that has not finished would be a lie a client renders as success. The
|
|
35
|
+
* flag is off by default for exactly this reason — see ../acp/server.ts.
|
|
36
|
+
*/
|
|
37
|
+
export type StopReason = "end_turn" | "cancelled" | "refusal" | "waiting";
|
|
38
|
+
/** A tool call's lifecycle, as a client renders it. */
|
|
39
|
+
export type ToolCallStatus = "pending" | "in_progress" | "completed" | "failed";
|
|
40
|
+
/** One text block in a prompt or an update. */
|
|
41
|
+
export interface TextContent {
|
|
42
|
+
type: "text";
|
|
43
|
+
text: string;
|
|
44
|
+
}
|
|
45
|
+
/** `initialize` params. */
|
|
46
|
+
export interface InitializeParams {
|
|
47
|
+
protocolVersion?: number;
|
|
48
|
+
clientCapabilities?: unknown;
|
|
49
|
+
}
|
|
50
|
+
/** `initialize` result. */
|
|
51
|
+
export interface InitializeResult {
|
|
52
|
+
protocolVersion: number;
|
|
53
|
+
agentInfo: {
|
|
54
|
+
name: string;
|
|
55
|
+
title: string;
|
|
56
|
+
version: string;
|
|
57
|
+
};
|
|
58
|
+
agentCapabilities: {
|
|
59
|
+
loadSession: boolean;
|
|
60
|
+
promptCapabilities: {
|
|
61
|
+
image: boolean;
|
|
62
|
+
audio: boolean;
|
|
63
|
+
embeddedContext: boolean;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
authMethods: unknown[];
|
|
67
|
+
}
|
|
68
|
+
/** `session/new` params. `mcpServers` is accepted and ignored — see the server's module doc. */
|
|
69
|
+
export interface NewSessionParams {
|
|
70
|
+
cwd?: string;
|
|
71
|
+
mcpServers?: unknown[];
|
|
72
|
+
_meta?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
/** `session/new` result. */
|
|
75
|
+
export interface NewSessionResult {
|
|
76
|
+
sessionId: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The out-of-band bag a client attaches to `session/prompt` to resume a
|
|
80
|
+
* durable permission request (#2125). ACP's `_meta` is the extension point
|
|
81
|
+
* fountain already uses for its own `channelId`, so a resume needs no method
|
|
82
|
+
* of its own and a client that does not do durable requests never sends it.
|
|
83
|
+
*/
|
|
84
|
+
export interface ChantPromptMeta {
|
|
85
|
+
/** Answers a `session/request_permission` this agent sent in an earlier turn. */
|
|
86
|
+
permission?: {
|
|
87
|
+
requestId: string;
|
|
88
|
+
optionId: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** `session/prompt` params. */
|
|
92
|
+
export interface PromptParams {
|
|
93
|
+
sessionId: string;
|
|
94
|
+
prompt: Array<TextContent | {
|
|
95
|
+
type: string;
|
|
96
|
+
[k: string]: unknown;
|
|
97
|
+
}>;
|
|
98
|
+
_meta?: {
|
|
99
|
+
chant?: ChantPromptMeta;
|
|
100
|
+
[k: string]: unknown;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** `session/prompt` result. */
|
|
104
|
+
export interface PromptResult {
|
|
105
|
+
stopReason: StopReason;
|
|
106
|
+
}
|
|
107
|
+
/** `session/cancel` params. A notification: the pending prompt is what answers. */
|
|
108
|
+
export interface CancelParams {
|
|
109
|
+
sessionId: string;
|
|
110
|
+
}
|
|
111
|
+
/** The `session/update` variants this agent emits. */
|
|
112
|
+
export type SessionUpdate = {
|
|
113
|
+
sessionUpdate: "agent_message_chunk";
|
|
114
|
+
content: TextContent;
|
|
115
|
+
} | {
|
|
116
|
+
sessionUpdate: "tool_call";
|
|
117
|
+
toolCallId: string;
|
|
118
|
+
title: string;
|
|
119
|
+
kind: "execute";
|
|
120
|
+
status: ToolCallStatus;
|
|
121
|
+
rawInput?: Record<string, unknown>;
|
|
122
|
+
} | {
|
|
123
|
+
sessionUpdate: "tool_call_update";
|
|
124
|
+
toolCallId: string;
|
|
125
|
+
status: ToolCallStatus;
|
|
126
|
+
content?: TextContent[];
|
|
127
|
+
rawOutput?: Record<string, unknown>;
|
|
128
|
+
};
|
|
129
|
+
/** `session/update` notification params. */
|
|
130
|
+
export interface SessionNotification {
|
|
131
|
+
sessionId: string;
|
|
132
|
+
update: SessionUpdate;
|
|
133
|
+
}
|
|
134
|
+
/** One choice offered on a `session/request_permission`. */
|
|
135
|
+
export interface PermissionOption {
|
|
136
|
+
optionId: string;
|
|
137
|
+
name: string;
|
|
138
|
+
kind: "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
139
|
+
}
|
|
140
|
+
/** `session/request_permission` params. */
|
|
141
|
+
export interface RequestPermissionParams {
|
|
142
|
+
sessionId: string;
|
|
143
|
+
toolCall: {
|
|
144
|
+
toolCallId: string;
|
|
145
|
+
title: string;
|
|
146
|
+
kind: "execute";
|
|
147
|
+
};
|
|
148
|
+
options: PermissionOption[];
|
|
149
|
+
_meta?: Record<string, unknown>;
|
|
150
|
+
}
|
|
151
|
+
/** `session/request_permission` result. */
|
|
152
|
+
export interface RequestPermissionResult {
|
|
153
|
+
outcome: {
|
|
154
|
+
outcome: "selected";
|
|
155
|
+
optionId: string;
|
|
156
|
+
} | {
|
|
157
|
+
outcome: "cancelled";
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/acp/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1E,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEhF,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2BAA2B;AAC3B,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2BAA2B;AAC3B,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,iBAAiB,EAAE;QACjB,WAAW,EAAE,OAAO,CAAC;QACrB,kBAAkB,EAAE;YAAE,KAAK,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,OAAO,CAAC;YAAC,eAAe,EAAE,OAAO,CAAA;SAAE,CAAC;KAClF,CAAC;IACF,WAAW,EAAE,OAAO,EAAE,CAAC;CACxB;AAED,gGAAgG;AAChG,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,4BAA4B;AAC5B,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,UAAU,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC,WAAW,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IACpE,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,eAAe,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC3D;AAED,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sDAAsD;AACtD,MAAM,MAAM,aAAa,GACrB;IAAE,aAAa,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAC9D;IACE,aAAa,EAAE,WAAW,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GACD;IACE,aAAa,EAAE,kBAAkB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEN,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,aAAa,GAAG,eAAe,CAAC;CACvE;AAED,2CAA2C;AAC3C,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IACjE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,2CAA2C;AAC3C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC;CAC/E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant acp` on the process's own stdio (#2125).
|
|
3
|
+
*
|
|
4
|
+
* Split from ./index.ts so mounting the command group costs nothing: this
|
|
5
|
+
* module is imported only once a client has actually spawned the agent.
|
|
6
|
+
*
|
|
7
|
+
* stdout is the protocol. Nothing else may write to it for the life of the
|
|
8
|
+
* process — every turn holds the output capture (./output.ts) precisely so a
|
|
9
|
+
* command's `console.log` cannot land between two JSON-RPC lines.
|
|
10
|
+
*/
|
|
11
|
+
/** Serve until the client closes stdin, which is how it says the connection is over. */
|
|
12
|
+
export declare function serveAcpOverStdio(opts?: {
|
|
13
|
+
durableRequests?: boolean;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/acp/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,wFAAwF;AACxF,wBAAsB,iBAAiB,CAAC,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAa/F"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant acp` — chant as an Agent Client Protocol agent (#2125, epic #2115).
|
|
3
|
+
*
|
|
4
|
+
* An editor or fountain spawns this process, speaks JSON-RPC 2.0 over stdio,
|
|
5
|
+
* and gets `session/update` notifications back. Every prompt is one chant
|
|
6
|
+
* command line, so a fountain thread of turns reads as an environment's shell
|
|
7
|
+
* history, and a run's steps arrive as tool calls a client already knows how
|
|
8
|
+
* to render.
|
|
9
|
+
*
|
|
10
|
+
* It is fountain-agnostic by construction. Nothing here imports the fountain
|
|
11
|
+
* API, a fountain type, or a fountain URL; it lives in this lexicon because
|
|
12
|
+
* fountain is its first host (epic #2115's steward runs `runtime: "acp"`,
|
|
13
|
+
* `runtime_command: "chant acp"`), and any ACP client can drive it unchanged.
|
|
14
|
+
*
|
|
15
|
+
* Three deliberate limits:
|
|
16
|
+
*
|
|
17
|
+
* - **Turns are serialized.** A turn borrows the process writers to stream a
|
|
18
|
+
* command's output (./output.ts) and changes into the session's `cwd`
|
|
19
|
+
* (./turn.ts). Both are process-wide, so two turns at once would interleave.
|
|
20
|
+
* One stdio connection running one command at a time is the honest shape.
|
|
21
|
+
* - **`mcpServers` from `session/new` is ignored.** chant's tools are its own
|
|
22
|
+
* verbs; there is nothing here for an MCP server to extend.
|
|
23
|
+
* - **The server never reads or prints the environment it inherits.** A step's
|
|
24
|
+
* output is streamed verbatim, secrets included, because redaction belongs
|
|
25
|
+
* to the thread that stores it — fountain redacts on the way in (see
|
|
26
|
+
* ../skills/chant-fountain.md).
|
|
27
|
+
*/
|
|
28
|
+
import { JsonRpcPeer, type JsonRpcHandler, type LineTransport } from "./jsonrpc.js";
|
|
29
|
+
import { type ChantHost } from "./host.js";
|
|
30
|
+
/** How `chant acp` is configured, and where a test substitutes its own project. */
|
|
31
|
+
export interface AcpServerOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Behind BinaryBourbon/fountain#1635: carry a gate to the client as a
|
|
34
|
+
* `session/request_permission` and end the turn `waiting`, instead of
|
|
35
|
+
* replying with the approve line and ending it. Default off, because no
|
|
36
|
+
* client can answer a request that outlives a turn until #1635 ships.
|
|
37
|
+
*/
|
|
38
|
+
durableRequests?: boolean;
|
|
39
|
+
/** Version reported as `agentInfo`. */
|
|
40
|
+
version?: string;
|
|
41
|
+
/** Builds the project-facing half of a session. Substituted by the conformance test. */
|
|
42
|
+
createHost?: (cwd: string) => ChantHost;
|
|
43
|
+
/** Mints permission request ids. Injected so a test can pin them. */
|
|
44
|
+
newRequestId?: () => string;
|
|
45
|
+
}
|
|
46
|
+
export declare class AcpServer implements JsonRpcHandler {
|
|
47
|
+
private peer;
|
|
48
|
+
private readonly sessions;
|
|
49
|
+
private readonly durableRequests;
|
|
50
|
+
private readonly version;
|
|
51
|
+
private readonly createHost;
|
|
52
|
+
private readonly newRequestId;
|
|
53
|
+
/** Serializes turns — see the module doc. */
|
|
54
|
+
private queue;
|
|
55
|
+
constructor(opts?: AcpServerOptions);
|
|
56
|
+
/** Serve one connection until it closes. */
|
|
57
|
+
connect(transport: LineTransport): JsonRpcPeer;
|
|
58
|
+
request(method: string, params: unknown): Promise<unknown>;
|
|
59
|
+
notify(method: string, params: unknown): void;
|
|
60
|
+
private enqueue;
|
|
61
|
+
private initialize;
|
|
62
|
+
private newSession;
|
|
63
|
+
private prompt;
|
|
64
|
+
/**
|
|
65
|
+
* Answer a `session/request_permission` this agent sent in an earlier turn.
|
|
66
|
+
*
|
|
67
|
+
* Allowing writes the gate resolution the way `chant approve` does — the
|
|
68
|
+
* fact is chant's, not the protocol's — and re-runs the command line that
|
|
69
|
+
* hit the gate, which now walks through it.
|
|
70
|
+
*/
|
|
71
|
+
private resume;
|
|
72
|
+
private runCommandLine;
|
|
73
|
+
/** The client-facing half of a turn, bound to one session. */
|
|
74
|
+
private sinkFor;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/acp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAEL,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AAoBnB,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGvE,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IACxC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAgBD,qBAAa,SAAU,YAAW,cAAc;IAC9C,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,6CAA6C;IAC7C,OAAO,CAAC,KAAK,CAAuC;gBAExC,IAAI,GAAE,gBAAqB;IAOvC,4CAA4C;IAC5C,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,WAAW;IAKxC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAahE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAU7C,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,UAAU;YAYJ,MAAM;IAcpB;;;;;;OAMG;YACW,MAAM;YAuCN,cAAc;IAiC5B,8DAA8D;IAC9D,OAAO,CAAC,OAAO;CA0DhB"}
|