@jevitate/cli 0.1.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/LICENSE +21 -0
- package/dist/ai-cli.d.ts +31 -0
- package/dist/ai-cli.js +238 -0
- package/dist/ai-cli.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +50663 -0
- package/dist/bin.js.map +1 -0
- package/dist/data-dir.d.ts +9 -0
- package/dist/data-dir.js +13 -0
- package/dist/data-dir.js.map +1 -0
- package/dist/envelope.d.ts +11 -0
- package/dist/envelope.js +7 -0
- package/dist/envelope.js.map +1 -0
- package/dist/explore-api.d.ts +187 -0
- package/dist/explore-api.js +302 -0
- package/dist/explore-api.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/init-keys.d.ts +14 -0
- package/dist/init-keys.js +18 -0
- package/dist/init-keys.js.map +1 -0
- package/dist/init-mcp.d.ts +87 -0
- package/dist/init-mcp.js +198 -0
- package/dist/init-mcp.js.map +1 -0
- package/dist/init-skills.d.ts +80 -0
- package/dist/init-skills.js +256 -0
- package/dist/init-skills.js.map +1 -0
- package/dist/journey-api.d.ts +37 -0
- package/dist/journey-api.js +55 -0
- package/dist/journey-api.js.map +1 -0
- package/dist/load-api.d.ts +48 -0
- package/dist/load-api.js +84 -0
- package/dist/load-api.js.map +1 -0
- package/dist/mcp-api.d.ts +116 -0
- package/dist/mcp-api.js +359 -0
- package/dist/mcp-api.js.map +1 -0
- package/dist/mission-api.d.ts +56 -0
- package/dist/mission-api.js +65 -0
- package/dist/mission-api.js.map +1 -0
- package/dist/program.d.ts +77 -0
- package/dist/program.js +1938 -0
- package/dist/program.js.map +1 -0
- package/dist/record-api.d.ts +74 -0
- package/dist/record-api.js +93 -0
- package/dist/record-api.js.map +1 -0
- package/dist/regression-api.d.ts +17 -0
- package/dist/regression-api.js +16 -0
- package/dist/regression-api.js.map +1 -0
- package/dist/self-heal-adapter.d.ts +31 -0
- package/dist/self-heal-adapter.js +70 -0
- package/dist/self-heal-adapter.js.map +1 -0
- package/dist/source-api.d.ts +147 -0
- package/dist/source-api.js +208 -0
- package/dist/source-api.js.map +1 -0
- package/dist/source-run-api.d.ts +57 -0
- package/dist/source-run-api.js +91 -0
- package/dist/source-run-api.js.map +1 -0
- package/dist/ui-api.d.ts +35 -0
- package/dist/ui-api.js +369 -0
- package/dist/ui-api.js.map +1 -0
- package/dist/ux-api.d.ts +75 -0
- package/dist/ux-api.js +231 -0
- package/dist/ux-api.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +37 -0
- package/dist/version.js.map +1 -0
- package/package.json +85 -0
- package/skills/jevitate-explore/SKILL.md +108 -0
- package/skills/jevitate-load-test/SKILL.md +42 -0
- package/skills/jevitate-mission-scope/SKILL.md +107 -0
- package/skills/jevitate-record/SKILL.md +78 -0
- package/skills/jevitate-run-journey/SKILL.md +72 -0
- package/skills/jevitate-sources/SKILL.md +88 -0
- package/skills/jevitate-ux-review/SKILL.md +68 -0
- package/ui/app.js +538 -0
- package/ui/index.html +546 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type RunPolicy } from "@jevitate/domain";
|
|
2
|
+
import { type JourneyRunResult, type SelfHealer } from "@jevitate/runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Distinct from `@jevitate/journey`'s `ParamValidationError` so CLI/API callers
|
|
5
|
+
* can tell "no such journey" apart from "params didn't match the journey's
|
|
6
|
+
* schema" without string-matching error messages.
|
|
7
|
+
*/
|
|
8
|
+
export declare class UnknownJourneyError extends Error {
|
|
9
|
+
}
|
|
10
|
+
export interface RunJourneyProgrammaticallyOptions {
|
|
11
|
+
/** Directory a `FsJourneyStore` reads Journey JSON files from. */
|
|
12
|
+
dir: string;
|
|
13
|
+
id: string;
|
|
14
|
+
params: Record<string, string>;
|
|
15
|
+
/** Defaults to `safeRunPolicy()` (Slice 1: fail-closed secret mode) when omitted. */
|
|
16
|
+
policy?: RunPolicy;
|
|
17
|
+
/**
|
|
18
|
+
* Optional gated self-heal port (Ticket #7). Only relevant when
|
|
19
|
+
* `policy.selfHeal.mode !== "fail-closed"`; wired as the `JourneyRunner`'s
|
|
20
|
+
* 5th constructor arg. When omitted (the default), a divergence quarantines
|
|
21
|
+
* exactly as before — identical to Slice 1's fail-closed behavior. The
|
|
22
|
+
* caller (CLI) is responsible for its credential preflight; this surface
|
|
23
|
+
* never builds AI gateways itself. Writes never auto-heal regardless of
|
|
24
|
+
* this port (enforced by `JourneyRunner`'s write floor).
|
|
25
|
+
*/
|
|
26
|
+
selfHealer?: SelfHealer;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The one programmatic surface for "run this published Journey by id" —
|
|
30
|
+
* used by BOTH the CLI `journey run` action and external callers. Builds
|
|
31
|
+
* the real `FsJourneyStore` + `JourneyRegistry`, resolves the journey
|
|
32
|
+
* (unknown id -> `UnknownJourneyError`), validates params UP FRONT with
|
|
33
|
+
* `deriveParamSchema`/`validateParams` (unknown/missing param ->
|
|
34
|
+
* `ParamValidationError`, from `@jevitate/journey`) BEFORE any browser is
|
|
35
|
+
* launched, then builds the real Actor + `JourneyRunner` and runs.
|
|
36
|
+
*/
|
|
37
|
+
export declare function runJourneyProgrammatically(opts: RunJourneyProgrammaticallyOptions): Promise<JourneyRunResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { FsJourneyStore, JourneyRegistry, deriveParamSchema, validateParams } from "@jevitate/journey";
|
|
5
|
+
import { safeRunPolicy } from "@jevitate/domain";
|
|
6
|
+
import { PlaywrightBrowserPort } from "@jevitate/playwright";
|
|
7
|
+
import { CastActor, BrowseTheWeb } from "@jevitate/screenplay";
|
|
8
|
+
import { RecordingInterpreter } from "@jevitate/interpreter";
|
|
9
|
+
import { JourneyRunner } from "@jevitate/runtime";
|
|
10
|
+
/**
|
|
11
|
+
* Distinct from `@jevitate/journey`'s `ParamValidationError` so CLI/API callers
|
|
12
|
+
* can tell "no such journey" apart from "params didn't match the journey's
|
|
13
|
+
* schema" without string-matching error messages.
|
|
14
|
+
*/
|
|
15
|
+
export class UnknownJourneyError extends Error {
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The one programmatic surface for "run this published Journey by id" —
|
|
19
|
+
* used by BOTH the CLI `journey run` action and external callers. Builds
|
|
20
|
+
* the real `FsJourneyStore` + `JourneyRegistry`, resolves the journey
|
|
21
|
+
* (unknown id -> `UnknownJourneyError`), validates params UP FRONT with
|
|
22
|
+
* `deriveParamSchema`/`validateParams` (unknown/missing param ->
|
|
23
|
+
* `ParamValidationError`, from `@jevitate/journey`) BEFORE any browser is
|
|
24
|
+
* launched, then builds the real Actor + `JourneyRunner` and runs.
|
|
25
|
+
*/
|
|
26
|
+
export async function runJourneyProgrammatically(opts) {
|
|
27
|
+
const store = new FsJourneyStore(opts.dir);
|
|
28
|
+
const registry = new JourneyRegistry(store);
|
|
29
|
+
const journey = await registry.get(opts.id);
|
|
30
|
+
if (!journey) {
|
|
31
|
+
throw new UnknownJourneyError(`unknown journey '${opts.id}'`);
|
|
32
|
+
}
|
|
33
|
+
// Fail fast: validate BEFORE any browser launch, so bad params never pay
|
|
34
|
+
// the cost (or risk) of opening a browser.
|
|
35
|
+
validateParams(deriveParamSchema(journey.recording), opts.params);
|
|
36
|
+
const policy = opts.policy ?? safeRunPolicy();
|
|
37
|
+
const profileDir = await mkdtemp(join(tmpdir(), "doit-journey-run-"));
|
|
38
|
+
const port = new PlaywrightBrowserPort();
|
|
39
|
+
const session = await port.open({
|
|
40
|
+
profileDir,
|
|
41
|
+
headless: true,
|
|
42
|
+
allowedOrigins: [journey.recording.site],
|
|
43
|
+
baseUrl: journey.recording.site,
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
const actor = CastActor.named("cli-runner").whoCan(new BrowseTheWeb(session, [journey.recording.site]));
|
|
47
|
+
const runner = new JourneyRunner(actor, new RecordingInterpreter(), undefined, undefined, opts.selfHealer);
|
|
48
|
+
return await runner.run({ journey, params: opts.params, policy });
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
await session.close();
|
|
52
|
+
await rm(profileDir, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=journey-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journey-api.js","sourceRoot":"","sources":["../src/journey-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAA0C,MAAM,mBAAmB,CAAC;AAE1F;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;CAAG;AAqBjD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,IAAuC;IAEvC,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,mBAAmB,CAAC,oBAAoB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAChE,CAAC;IAED,yEAAyE;IACzE,2CAA2C;IAC3C,cAAc,CAAC,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAElE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;IAE9C,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,qBAAqB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC;QAC9B,UAAU;QACV,QAAQ,EAAE,IAAI;QACd,cAAc,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;QACxC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI;KAChC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,MAAM,CAChD,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CACpD,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,IAAI,oBAAoB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3G,OAAO,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type RunPolicy } from "@jevitate/domain";
|
|
2
|
+
import { type BrowserPort } from "@jevitate/playwright";
|
|
3
|
+
import { type CapacityReport } from "@jevitate/load";
|
|
4
|
+
/** Distinct from `@jevitate/journey`'s ParamValidationError-style "unknown id" cases elsewhere, so CLI callers can branch without string-matching. */
|
|
5
|
+
export declare class UnknownLoadJourneyError extends Error {
|
|
6
|
+
}
|
|
7
|
+
export interface RunJourneyLoadTestOptions {
|
|
8
|
+
dir: string;
|
|
9
|
+
id: string;
|
|
10
|
+
params: Record<string, string>;
|
|
11
|
+
concurrency: number;
|
|
12
|
+
iterationsPerActor: number;
|
|
13
|
+
/**
|
|
14
|
+
* Governs deterministic actor fan-out/scheduling only (see
|
|
15
|
+
* `@jevitate/load`'s `RunLoadTestConfig.seed` doc comment) — the real
|
|
16
|
+
* `JourneyRunner` this function drives per pool member has no pacing
|
|
17
|
+
* hook, so this `seed` does NOT (yet) produce human-speed pacing of the
|
|
18
|
+
* real run the way `modeledCapacityReport`'s `seed` drives
|
|
19
|
+
* `simulateTiming()`. Known gap, deferred to a future slice.
|
|
20
|
+
*/
|
|
21
|
+
seed: number;
|
|
22
|
+
authorizedOrigins: readonly string[];
|
|
23
|
+
/** Defaults to `safeRunPolicy()`, same convention as `journey-api.ts`'s `runJourneyProgrammatically`. */
|
|
24
|
+
policy?: RunPolicy;
|
|
25
|
+
/**
|
|
26
|
+
* Testing seam: overrides the real `PlaywrightBrowserPort` used per pool
|
|
27
|
+
* member with a fake, so the per-actor browser-session lifecycle (see
|
|
28
|
+
* `runnerFactory` below) can be unit-tested with no real browser. Defaults
|
|
29
|
+
* to `() => new PlaywrightBrowserPort()`.
|
|
30
|
+
*/
|
|
31
|
+
browserPortFactory?: () => BrowserPort;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The programmatic surface behind `jevitate load run` — resolves a published
|
|
35
|
+
* Journey (unknown id -> `UnknownLoadJourneyError`), validates params UP
|
|
36
|
+
* FRONT, then hands `@jevitate/load`'s `runLoadTest` a factory that opens ONE
|
|
37
|
+
* real headless Playwright session + `JourneyRunner` per pool member. The
|
|
38
|
+
* authorized-target check happens inside `runLoadTest` itself — this
|
|
39
|
+
* function does not duplicate or bypass it.
|
|
40
|
+
*
|
|
41
|
+
* NOTE on "seeded ⇒ reproducible / human-paced" (corrected post-review):
|
|
42
|
+
* `opts.seed` makes the ACTOR POOL's composition reproducible (via
|
|
43
|
+
* `deriveActorSeeds` inside `runLoadTest`) — it does not yet make the real
|
|
44
|
+
* run human-paced, because `JourneyRunner` (constructed below) has no
|
|
45
|
+
* pacing hook to seed. Only the offline `modeledCapacityReport` path is
|
|
46
|
+
* genuinely human-paced today, via `@jevitate/domain`'s `simulateTiming()`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runJourneyLoadTest(opts: RunJourneyLoadTestOptions): Promise<CapacityReport>;
|
package/dist/load-api.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { FsJourneyStore, JourneyRegistry, deriveParamSchema, validateParams } from "@jevitate/journey";
|
|
5
|
+
import { safeRunPolicy } from "@jevitate/domain";
|
|
6
|
+
import { PlaywrightBrowserPort } from "@jevitate/playwright";
|
|
7
|
+
import { CastActor, BrowseTheWeb } from "@jevitate/screenplay";
|
|
8
|
+
import { RecordingInterpreter } from "@jevitate/interpreter";
|
|
9
|
+
import { JourneyRunner } from "@jevitate/runtime";
|
|
10
|
+
import { runLoadTest } from "@jevitate/load";
|
|
11
|
+
/** Distinct from `@jevitate/journey`'s ParamValidationError-style "unknown id" cases elsewhere, so CLI callers can branch without string-matching. */
|
|
12
|
+
export class UnknownLoadJourneyError extends Error {
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The programmatic surface behind `jevitate load run` — resolves a published
|
|
16
|
+
* Journey (unknown id -> `UnknownLoadJourneyError`), validates params UP
|
|
17
|
+
* FRONT, then hands `@jevitate/load`'s `runLoadTest` a factory that opens ONE
|
|
18
|
+
* real headless Playwright session + `JourneyRunner` per pool member. The
|
|
19
|
+
* authorized-target check happens inside `runLoadTest` itself — this
|
|
20
|
+
* function does not duplicate or bypass it.
|
|
21
|
+
*
|
|
22
|
+
* NOTE on "seeded ⇒ reproducible / human-paced" (corrected post-review):
|
|
23
|
+
* `opts.seed` makes the ACTOR POOL's composition reproducible (via
|
|
24
|
+
* `deriveActorSeeds` inside `runLoadTest`) — it does not yet make the real
|
|
25
|
+
* run human-paced, because `JourneyRunner` (constructed below) has no
|
|
26
|
+
* pacing hook to seed. Only the offline `modeledCapacityReport` path is
|
|
27
|
+
* genuinely human-paced today, via `@jevitate/domain`'s `simulateTiming()`.
|
|
28
|
+
*/
|
|
29
|
+
export async function runJourneyLoadTest(opts) {
|
|
30
|
+
const store = new FsJourneyStore(opts.dir);
|
|
31
|
+
const registry = new JourneyRegistry(store);
|
|
32
|
+
const journey = await registry.get(opts.id);
|
|
33
|
+
if (!journey) {
|
|
34
|
+
throw new UnknownLoadJourneyError(`unknown journey '${opts.id}'`);
|
|
35
|
+
}
|
|
36
|
+
validateParams(deriveParamSchema(journey.recording), opts.params);
|
|
37
|
+
const policy = opts.policy ?? safeRunPolicy();
|
|
38
|
+
const browserPortFactory = opts.browserPortFactory ?? (() => new PlaywrightBrowserPort());
|
|
39
|
+
return runLoadTest({
|
|
40
|
+
targetOrigin: journey.recording.site,
|
|
41
|
+
authorizedOrigins: opts.authorizedOrigins,
|
|
42
|
+
concurrency: opts.concurrency,
|
|
43
|
+
iterationsPerActor: opts.iterationsPerActor,
|
|
44
|
+
seed: opts.seed,
|
|
45
|
+
runnerFactory: async (actorIndex) => {
|
|
46
|
+
const profileDir = await mkdtemp(join(tmpdir(), `doit-load-actor-${actorIndex}-`));
|
|
47
|
+
const port = browserPortFactory();
|
|
48
|
+
const session = await port.open({
|
|
49
|
+
profileDir,
|
|
50
|
+
headless: true,
|
|
51
|
+
allowedOrigins: [journey.recording.site],
|
|
52
|
+
baseUrl: journey.recording.site,
|
|
53
|
+
});
|
|
54
|
+
const actor = CastActor.named(`load-actor-${actorIndex}`).whoCan(new BrowseTheWeb(session, [journey.recording.site]));
|
|
55
|
+
const runner = new JourneyRunner(actor, new RecordingInterpreter());
|
|
56
|
+
// `runLoadTest` calls `run()` exactly `iterationsPerActor` times for
|
|
57
|
+
// this actor — success or failure, never more, never fewer (see
|
|
58
|
+
// measured-load-runner.ts's per-actor loop). Closing the real browser
|
|
59
|
+
// session on EVERY `run()` would defeat pooling (a fresh browser
|
|
60
|
+
// launch per iteration); never closing it leaks a Chromium process +
|
|
61
|
+
// tmp profile dir per actor per invocation, worse as `--concurrency`
|
|
62
|
+
// scales — the whole point of a load harness. So: reuse one session
|
|
63
|
+
// across this actor's iterations, and close it in a `finally` once
|
|
64
|
+
// the LAST iteration finishes OR throws — mirroring `journey-api.ts`'s
|
|
65
|
+
// `try { ... } finally { await session.close(); }`.
|
|
66
|
+
let remainingIterations = opts.iterationsPerActor;
|
|
67
|
+
return {
|
|
68
|
+
run: async () => {
|
|
69
|
+
try {
|
|
70
|
+
return await runner.run({ journey, params: opts.params, policy });
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
remainingIterations--;
|
|
74
|
+
if (remainingIterations <= 0) {
|
|
75
|
+
await session.close();
|
|
76
|
+
await rm(profileDir, { recursive: true, force: true });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=load-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-api.js","sourceRoot":"","sources":["../src/load-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { type AiGenerateTextArgs, type AiGenerateTextResult } from "@jevitate/mcp-facade";
|
|
3
|
+
import { type CredentialStore, type GenerationPort, type SetupRequiredResult } from "@jevitate/ai-core";
|
|
4
|
+
/**
|
|
5
|
+
* The MCP stdio server behind `jevitate mcp`. It exposes ONLY the tools in
|
|
6
|
+
* `@jevitate/mcp-facade`'s `ALLOWED_TOOLS` and structurally CANNOT serve any
|
|
7
|
+
* of `FORBIDDEN_TOOLS` (the raw browser primitives): the served surface is
|
|
8
|
+
* derived from `ALLOWED_TOOLS`, every descriptor is re-checked against the
|
|
9
|
+
* allow/forbid sets at build time (`assertAllowlisted`), and the call
|
|
10
|
+
* dispatcher refuses any name that is forbidden or not in the served map.
|
|
11
|
+
*
|
|
12
|
+
* `buildMcpTools` is the unit-testable seam — a test can enumerate the served
|
|
13
|
+
* tool names (and exercise each handler) WITHOUT opening a stdio transport.
|
|
14
|
+
* `startMcpServer` is the only place a real `StdioServerTransport` is opened.
|
|
15
|
+
*/
|
|
16
|
+
export interface McpToolResult {
|
|
17
|
+
content: Array<{
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}>;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface McpTool {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object";
|
|
28
|
+
properties: Record<string, unknown>;
|
|
29
|
+
required?: string[];
|
|
30
|
+
};
|
|
31
|
+
handler: (args: Record<string, unknown>) => Promise<McpToolResult>;
|
|
32
|
+
}
|
|
33
|
+
export interface McpApiDeps {
|
|
34
|
+
/** Journeys store directory (`~/.jevitate/journeys` in production). */
|
|
35
|
+
journeysDir: string;
|
|
36
|
+
/**
|
|
37
|
+
* Test seam. Defaults to the real promoted-only projection over the
|
|
38
|
+
* journeys store (`@jevitate/mcp-facade`'s `findCapabilities`).
|
|
39
|
+
*/
|
|
40
|
+
findCapabilities?: (query: string) => Promise<unknown>;
|
|
41
|
+
/**
|
|
42
|
+
* Test seam. Defaults to `runJourneyProgrammatically` with a fail-closed
|
|
43
|
+
* `safeRunPolicy()` (invariant #5: PUBLISHED-id-only, never inline steps).
|
|
44
|
+
*/
|
|
45
|
+
runJourney?: (id: string, params: Record<string, string>) => Promise<unknown>;
|
|
46
|
+
/**
|
|
47
|
+
* Promoted mission-target store directory (`~/.jevitate/missions/targets` in
|
|
48
|
+
* production — the SAME store `jevitate mission target` writes). Required for
|
|
49
|
+
* the default `queue_exploration` wiring; the host resolves it.
|
|
50
|
+
*/
|
|
51
|
+
missionTargetsDir?: string;
|
|
52
|
+
/** Mission queue directory (`~/.jevitate/missions/queue` in production). */
|
|
53
|
+
missionQueueDir?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Inbox store directory (`~/.jevitate/inbox` in production) backing all 8
|
|
56
|
+
* `list_incoming`/`get_command`/`get_thread`/`queue_action`/
|
|
57
|
+
* `queue_retrieval`/`approve_action`/`cancel_command`/`get_site_health`
|
|
58
|
+
* tools. The `FsInboxStore` is built lazily inside each handler's closure
|
|
59
|
+
* (mirrors `queueExploration`'s lazy store) so constructing the tool set
|
|
60
|
+
* never touches disk. A missing/unconfigured dir is a config error (a
|
|
61
|
+
* refusal), never a silent success.
|
|
62
|
+
*/
|
|
63
|
+
inboxDir?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Test seam. Defaults to `@jevitate/mcp-facade`'s `queueExploration` over the
|
|
66
|
+
* fs-backed promoted `MissionTargetRegistry` + `FsMissionQueueStore`. Never
|
|
67
|
+
* runs a mission — only enqueues; refuses unknown/unpromoted targets and
|
|
68
|
+
* over-ceiling budgets (all validation delegated to `enqueueMission`).
|
|
69
|
+
*/
|
|
70
|
+
queueExploration?: (args: unknown) => Promise<unknown>;
|
|
71
|
+
/**
|
|
72
|
+
* Credential store for `ai_generate_text`'s preflight gate. Defaults to
|
|
73
|
+
* `envCredentialStore()` (env + gitignored local config). `detect` never
|
|
74
|
+
* returns a value; the key value is read ONLY at the provider call, inside
|
|
75
|
+
* the gateway, and placed only in the Authorization header.
|
|
76
|
+
*/
|
|
77
|
+
credentialStore?: CredentialStore;
|
|
78
|
+
/**
|
|
79
|
+
* Generation gateway for `ai_generate_text`. Provided by the host (the real
|
|
80
|
+
* `OpenRouterGenerationGateway`, which routes every outbound payload through
|
|
81
|
+
* the never-to-model credential guard). When ABSENT and no `aiGenerateText`
|
|
82
|
+
* seam is injected, `ai_generate_text` stays a typed `not_implemented`
|
|
83
|
+
* rather than fabricating an answer.
|
|
84
|
+
*/
|
|
85
|
+
generationGateway?: GenerationPort;
|
|
86
|
+
/**
|
|
87
|
+
* Test seam. Defaults to `@jevitate/mcp-facade`'s `aiGenerateText`
|
|
88
|
+
* (`credentialStore` + `generationGateway`), preflight-gated so a missing key
|
|
89
|
+
* returns a typed `setup_required` result instead of calling the model.
|
|
90
|
+
*/
|
|
91
|
+
aiGenerateText?: (args: AiGenerateTextArgs) => Promise<AiGenerateTextResult | SetupRequiredResult>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Builds the served tool descriptors — EXACTLY one per `ALLOWED_TOOLS` entry.
|
|
95
|
+
* Wired to their real backing services: `find_capabilities` + `run_journey`
|
|
96
|
+
* (journey store), `queue_exploration` (`@jevitate/missions` enqueue over the
|
|
97
|
+
* promoted `MissionTargetRegistry`), and `ai_generate_text` (`@jevitate/ai-core`
|
|
98
|
+
* generation gateway behind a fail-closed credential preflight). The remaining
|
|
99
|
+
* allowlisted tools — the inbox/command-queue surface — are registered (so the
|
|
100
|
+
* served set equals `ALLOWED_TOOLS`) but respond with a typed `not_implemented`
|
|
101
|
+
* error, since no facade-level backing service exists for them in this slice.
|
|
102
|
+
* No handler ever fabricates a success.
|
|
103
|
+
*/
|
|
104
|
+
export declare function buildMcpTools(deps: McpApiDeps): McpTool[];
|
|
105
|
+
/**
|
|
106
|
+
* Constructs the MCP `Server` and registers its `tools/list` and `tools/call`
|
|
107
|
+
* handlers off `buildMcpTools`. Does NOT open a transport — that is
|
|
108
|
+
* `startMcpServer`'s job — so this is safe to construct in a unit test.
|
|
109
|
+
*/
|
|
110
|
+
export declare function createMcpServer(deps: McpApiDeps): Server;
|
|
111
|
+
/**
|
|
112
|
+
* Starts the real MCP stdio server. Blocks (the transport owns stdin/stdout)
|
|
113
|
+
* until the client disconnects — callers must NOT write to stdout while it
|
|
114
|
+
* runs, since stdout is the MCP protocol channel.
|
|
115
|
+
*/
|
|
116
|
+
export declare function startMcpServer(deps: McpApiDeps): Promise<void>;
|