@p4code/cli 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +801 -72
- package/dist/client/assets/{DiffPanel-DLEF2Os4.js → DiffPanel-BdNsdwM5.js} +3 -3
- package/dist/client/assets/{FilePreviewPanel-8D_2Xs92.js → FilePreviewPanel-CWcDqLso.js} +5 -5
- package/dist/client/assets/PreviewPanel-2u47bK5v.js +2 -0
- package/dist/client/assets/{angular-html-CMBWPyD3.js → angular-html-BLv19dHn.js} +2 -2
- package/dist/client/assets/{angular-ts-BatZhjLf.js → angular-ts-D41w0Au3.js} +2 -2
- package/dist/client/assets/{apl-Cx1sW3hC.js → apl-BEl8UFu4.js} +2 -2
- package/dist/client/assets/arrow-right-Tef5pBUM.js +2 -0
- package/dist/client/assets/{astro-nMa7HQcv.js → astro-U1Y_O85L.js} +2 -2
- package/dist/client/assets/{blade-JxAt8tFv.js → blade-CZ232EWr.js} +2 -2
- package/dist/client/assets/{c-C-yEqtHp.js → c-DirgNKaz.js} +2 -2
- package/dist/client/assets/{cobol-CA3DrkO1.js → cobol-B7WyPi1F.js} +2 -2
- package/dist/client/assets/{coffee-CNzul851.js → coffee-C_qHkMIP.js} +2 -2
- package/dist/client/assets/{cpp-DYasO6ny.js → cpp-SPUhkLTs.js} +2 -2
- package/dist/client/assets/{crystal-BkYnv3Y5.js → crystal-vq6jdakY.js} +2 -2
- package/dist/client/assets/{css-GnxXZE-U.js → css-BAnKum7K.js} +2 -2
- package/dist/client/assets/{edge-DHx6AdO-.js → edge-BuMKesaI.js} +2 -2
- package/dist/client/assets/{elixir-XiEvMT4-.js → elixir-BL-W6BH4.js} +2 -2
- package/dist/client/assets/{elm-BY4GYI5F.js → elm-DiUCNL3v.js} +2 -2
- package/dist/client/assets/{erb-DDG6lOki.js → erb-skcSurJb.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-BTZDcAeh.js → fileCommentAnnotations-BRTew3I1.js} +2 -2
- package/dist/client/assets/{git-rebase-BDUy60An.js → git-rebase-dO-xI28x.js} +2 -2
- package/dist/client/assets/{glimmer-js-Dpr_XG7j.js → glimmer-js-CECukRm7.js} +2 -2
- package/dist/client/assets/{glimmer-ts-CtZ0ZipS.js → glimmer-ts-CIaRC8zm.js} +2 -2
- package/dist/client/assets/{glsl-DHtQlcKL.js → glsl-CKSbugKg.js} +2 -2
- package/dist/client/assets/{graphql-DtNuYKEb.js → graphql-BiZ7twV7.js} +2 -2
- package/dist/client/assets/{hack-BqNfldCe.js → hack-BdAxCPD7.js} +2 -2
- package/dist/client/assets/{haml-mPiLB45s.js → haml-SZR9Ndrp.js} +2 -2
- package/dist/client/assets/{handlebars-BLxX_l2A.js → handlebars-BExVQKqz.js} +2 -2
- package/dist/client/assets/{html-DU5G3F4s.js → html-CkYFYJn1.js} +2 -2
- package/dist/client/assets/{html-derivative-BMJPXTuS.js → html-derivative-Cop3EQeZ.js} +2 -2
- package/dist/client/assets/{http-6kGF1eof.js → http-DQ8c4u3s.js} +2 -2
- package/dist/client/assets/{hurl-CvT1bXUG.js → hurl-BKyyIuNR.js} +2 -2
- package/dist/client/assets/index-ClVe76A5.js +660 -0
- package/dist/client/assets/index-DGu8ejUP.css +1 -0
- package/dist/client/assets/{java-bBnbDfw8.js → java-CedFcWif.js} +2 -2
- package/dist/client/assets/{javascript-CpOINVUc.js → javascript-BdXDoWFM.js} +2 -2
- package/dist/client/assets/{jinja-CItwptlU.js → jinja-CK8YWL7a.js} +2 -2
- package/dist/client/assets/{jison-BWvHru6a.js → jison-C-mnFz-X.js} +2 -2
- package/dist/client/assets/{json-ClObSVU5.js → json-Dxix4Qbo.js} +2 -2
- package/dist/client/assets/{jsx-vHozUqKh.js → jsx-6M0gL61I.js} +2 -2
- package/dist/client/assets/{julia-CITEF0SC.js → julia-SXfQGJ8P.js} +2 -2
- package/dist/client/assets/{just-CAMHq4cU.js → just-O0TR05uE.js} +2 -2
- package/dist/client/assets/{latex-BHB-Vy2g.js → latex-w7R_uAyc.js} +2 -2
- package/dist/client/assets/{liquid-rsijXGco.js → liquid-hPzEzmzZ.js} +2 -2
- package/dist/client/assets/{lua-CPA1zmkS.js → lua-D24pQ94w.js} +2 -2
- package/dist/client/assets/{marko-D9CJEgH2.js → marko-DsaGFeHY.js} +2 -2
- package/dist/client/assets/{mdc-DL5ptUuf.js → mdc-C4vifn2U.js} +2 -2
- package/dist/client/assets/{nginx-DAAmFPDe.js → nginx-KnKOgHWr.js} +2 -2
- package/dist/client/assets/{nim-DmaHLOWa.js → nim-CXVNWegc.js} +2 -2
- package/dist/client/assets/{perl-Bw03qQ4D.js → perl-_PU7gLJn.js} +2 -2
- package/dist/client/assets/{php-DdSlZ5fF.js → php-B--0cDl3.js} +2 -2
- package/dist/client/assets/{pug-CgQdUdQK.js → pug-DELbYjHv.js} +2 -2
- package/dist/client/assets/{qml-6-Z__KDk.js → qml-CyGKPCuH.js} +2 -2
- package/dist/client/assets/{r-BwsNM1XU.js → r-CSjDVJJY.js} +2 -2
- package/dist/client/assets/{razor-DRWY5qRs.js → razor-ppZnQuQy.js} +2 -2
- package/dist/client/assets/{regexp-BGiLplmg.js → regexp-DAYlObpi.js} +2 -2
- package/dist/client/assets/{rst-CND1NmX_.js → rst-DV8sAt14.js} +2 -2
- package/dist/client/assets/{ruby-Dlxt-z_r.js → ruby-DXISWktP.js} +2 -2
- package/dist/client/assets/{sas-DFeunfku.js → sas-CJl6Tu3p.js} +2 -2
- package/dist/client/assets/{scss-D_BTo2XD.js → scss-DmbKMDuD.js} +2 -2
- package/dist/client/assets/{shellscript-cEuOjvsv.js → shellscript-BFH8QS9G.js} +2 -2
- package/dist/client/assets/{shellsession-CeWrE-Lw.js → shellsession-CIHFsdwm.js} +2 -2
- package/dist/client/assets/{soy-DdFNKMwD.js → soy--q_a3wNH.js} +2 -2
- package/dist/client/assets/{sql-3jzdtF3L.js → sql-DE3xygzU.js} +2 -2
- package/dist/client/assets/{stata-CfftDdbo.js → stata-BZORI8K-.js} +2 -2
- package/dist/client/assets/{surrealql-BgLa39M_.js → surrealql-DQwYGqPv.js} +2 -2
- package/dist/client/assets/{svelte-CJNznzEX.js → svelte-C8rcZCbS.js} +2 -2
- package/dist/client/assets/{templ-DiQ0ONH_.js → templ-YxwRimHC.js} +2 -2
- package/dist/client/assets/{tex-Dj5-ewTi.js → tex-CreWrrVU.js} +2 -2
- package/dist/client/assets/textarea-DogWRke3.js +46 -0
- package/dist/client/assets/{ts-tags-Rut2YPAl.js → ts-tags-BGYLwTar.js} +2 -2
- package/dist/client/assets/{tsx-TxGWIfKc.js → tsx-dvRLM93g.js} +2 -2
- package/dist/client/assets/{twig-CEDmL9ir.js → twig-BwKK1q-j.js} +2 -2
- package/dist/client/assets/{typescript-B1NW_Svr.js → typescript-CIA9s0mZ.js} +2 -2
- package/dist/client/assets/{vue-CEjpLlUp.js → vue-RR_2K8-s.js} +2 -2
- package/dist/client/assets/{vue-html-BLRayXbW.js → vue-html-SobvEO2e.js} +2 -2
- package/dist/client/assets/{vue-vine-BaZ_eWYq.js → vue-vine-BQgxB5Yf.js} +2 -2
- package/dist/client/assets/{xml-WjUY_YSL.js → xml-qR9OaTYe.js} +2 -2
- package/dist/client/assets/{xsl-rMBkkP2N.js → xsl-CNAIK0Wp.js} +2 -2
- package/dist/client/assets/{yaml-BVcdKGq_.js → yaml-CnmdSZli.js} +2 -2
- package/dist/client/index.html +3 -3
- package/package.json +1 -1
- package/dist/client/assets/PreviewPanel-DiR-_u2D.js +0 -2
- package/dist/client/assets/arrow-right-D6CCHJEU.js +0 -2
- package/dist/client/assets/index-JvBwT8k1.js +0 -660
- package/dist/client/assets/index-nkPMSYxq.css +0 -1
- package/dist/client/assets/textarea-CtwXMNmJ.js +0 -46
package/dist/bin.mjs
CHANGED
|
@@ -121,7 +121,7 @@ const closeServer = (server) => {
|
|
|
121
121
|
* NetService - Service tag for startup networking helpers.
|
|
122
122
|
*/
|
|
123
123
|
var NetService = class extends Context.Service()("@p4code/shared/Net/NetService") {};
|
|
124
|
-
const make$
|
|
124
|
+
const make$74 = () => {
|
|
125
125
|
/**
|
|
126
126
|
* Returns true when a TCP server can bind to {host, port}.
|
|
127
127
|
* `EADDRNOTAVAIL` is treated as available so IPv6-absent hosts don't fail
|
|
@@ -230,10 +230,10 @@ const make$73 = () => {
|
|
|
230
230
|
})
|
|
231
231
|
};
|
|
232
232
|
};
|
|
233
|
-
const layer$
|
|
233
|
+
const layer$70 = Layer.sync(NetService, make$74);
|
|
234
234
|
//#endregion
|
|
235
235
|
//#region package.json
|
|
236
|
-
var version = "0.1.
|
|
236
|
+
var version = "0.1.14";
|
|
237
237
|
//#endregion
|
|
238
238
|
//#region src/config.ts
|
|
239
239
|
/**
|
|
@@ -254,8 +254,8 @@ var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerC
|
|
|
254
254
|
/** @deprecated Import and use `layerTest` from this module. */
|
|
255
255
|
static layerTest = (cwd, baseDirOrPrefix) => layerTest$2(cwd, baseDirOrPrefix);
|
|
256
256
|
};
|
|
257
|
-
const make$
|
|
258
|
-
const layer$
|
|
257
|
+
const make$73 = (config) => ServerConfig$1.of(config);
|
|
258
|
+
const layer$69 = (config) => Layer.succeed(ServerConfig$1, make$73(config));
|
|
259
259
|
const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
|
|
260
260
|
const { join } = yield* Path.Path;
|
|
261
261
|
const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
|
|
@@ -1657,6 +1657,7 @@ const CompressMode = Schema$1.Literals([
|
|
|
1657
1657
|
"full",
|
|
1658
1658
|
"ultra"
|
|
1659
1659
|
]);
|
|
1660
|
+
const DEFAULT_COMPRESS_MODE = "full";
|
|
1660
1661
|
const ProviderRequestKind = Schema$1.Literals([
|
|
1661
1662
|
"command",
|
|
1662
1663
|
"file-read",
|
|
@@ -1833,7 +1834,7 @@ const OrchestrationThread = Schema$1.Struct({
|
|
|
1833
1834
|
modelSelection: ModelSelection,
|
|
1834
1835
|
runtimeMode: RuntimeMode,
|
|
1835
1836
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1836
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
1837
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
1837
1838
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1838
1839
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1839
1840
|
latestTurn: Schema$1.NullOr(OrchestrationLatestTurn),
|
|
@@ -1874,7 +1875,7 @@ const OrchestrationThreadShell = Schema$1.Struct({
|
|
|
1874
1875
|
modelSelection: ModelSelection,
|
|
1875
1876
|
runtimeMode: RuntimeMode,
|
|
1876
1877
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1877
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
1878
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
1878
1879
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1879
1880
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1880
1881
|
latestTurn: Schema$1.NullOr(OrchestrationLatestTurn),
|
|
@@ -1997,7 +1998,7 @@ const ThreadCreateCommand = Schema$1.Struct({
|
|
|
1997
1998
|
modelSelection: ModelSelection,
|
|
1998
1999
|
runtimeMode: RuntimeMode,
|
|
1999
2000
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
2000
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2001
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2001
2002
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2002
2003
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2003
2004
|
createdAt: IsoDateTime
|
|
@@ -2077,7 +2078,7 @@ const ThreadTurnStartBootstrapCreateThread = Schema$1.Struct({
|
|
|
2077
2078
|
modelSelection: ModelSelection,
|
|
2078
2079
|
runtimeMode: RuntimeMode,
|
|
2079
2080
|
interactionMode: ProviderInteractionMode,
|
|
2080
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2081
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2081
2082
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2082
2083
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2083
2084
|
createdAt: IsoDateTime
|
|
@@ -2107,7 +2108,7 @@ const ThreadTurnStartCommand = Schema$1.Struct({
|
|
|
2107
2108
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
2108
2109
|
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
2109
2110
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
2110
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2111
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2111
2112
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
2112
2113
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
2113
2114
|
createdAt: IsoDateTime
|
|
@@ -2126,7 +2127,7 @@ const ClientThreadTurnStartCommand = Schema$1.Struct({
|
|
|
2126
2127
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
2127
2128
|
runtimeMode: RuntimeMode,
|
|
2128
2129
|
interactionMode: ProviderInteractionMode,
|
|
2129
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2130
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2130
2131
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
2131
2132
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
2132
2133
|
createdAt: IsoDateTime
|
|
@@ -2346,7 +2347,7 @@ const ThreadCreatedPayload$1 = Schema$1.Struct({
|
|
|
2346
2347
|
modelSelection: ModelSelection,
|
|
2347
2348
|
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
2348
2349
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
2349
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2350
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2350
2351
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2351
2352
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
2352
2353
|
createdAt: IsoDateTime,
|
|
@@ -2406,7 +2407,7 @@ const ThreadInteractionModeSetPayload$1 = Schema$1.Struct({
|
|
|
2406
2407
|
});
|
|
2407
2408
|
const ThreadCompressModeSetPayload$1 = Schema$1.Struct({
|
|
2408
2409
|
threadId: ThreadId,
|
|
2409
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2410
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2410
2411
|
updatedAt: IsoDateTime
|
|
2411
2412
|
});
|
|
2412
2413
|
const ThreadMessageSentPayload = Schema$1.Struct({
|
|
@@ -2427,7 +2428,7 @@ const ThreadTurnStartRequestedPayload = Schema$1.Struct({
|
|
|
2427
2428
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
2428
2429
|
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
2429
2430
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
2430
|
-
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(
|
|
2431
|
+
compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
|
|
2431
2432
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
2432
2433
|
createdAt: IsoDateTime
|
|
2433
2434
|
});
|
|
@@ -7651,6 +7652,57 @@ const ThreadControlToolError = Schema$1.Union([
|
|
|
7651
7652
|
ThreadRenameRejectedError,
|
|
7652
7653
|
MemoryAppendFailedError
|
|
7653
7654
|
]);
|
|
7655
|
+
const ThreadWatchEventsInput = Schema$1.Struct({
|
|
7656
|
+
threadId: ThreadId.annotate({ description: "The watched thread to read events from. Must be explicitly granted." }),
|
|
7657
|
+
afterSequence: Schema$1.optional(NonNegativeInt.annotate({ description: "Exclusive sequence cursor. Events with a higher sequence are returned. Omit to read from the beginning." })),
|
|
7658
|
+
limit: Schema$1.optional(NonNegativeInt.check(Schema$1.isLessThanOrEqualTo(200)).annotate({ description: `Maximum events to return (default 50, max 200).` }))
|
|
7659
|
+
});
|
|
7660
|
+
const ThreadWatchEventsResult = Schema$1.Struct({
|
|
7661
|
+
threadId: ThreadId,
|
|
7662
|
+
/** Ordered by sequence ascending; resume with the last event's sequence. */
|
|
7663
|
+
events: Schema$1.Array(OrchestrationEvent),
|
|
7664
|
+
/**
|
|
7665
|
+
* The engine's latest persisted sequence at read time. Equal to the last
|
|
7666
|
+
* returned event's sequence when the watcher is caught up.
|
|
7667
|
+
*/
|
|
7668
|
+
headSequence: NonNegativeInt,
|
|
7669
|
+
/** True when more events for this thread exist past the returned page. */
|
|
7670
|
+
hasMore: Schema$1.Boolean
|
|
7671
|
+
});
|
|
7672
|
+
var WatchToolUnavailableError = class extends Schema$1.TaggedErrorClass()("WatchToolUnavailableError", {
|
|
7673
|
+
capability: Schema$1.Literal("watch"),
|
|
7674
|
+
environmentId: EnvironmentId,
|
|
7675
|
+
threadId: ThreadId,
|
|
7676
|
+
providerSessionId: TrimmedNonEmptyString,
|
|
7677
|
+
providerInstanceId: ProviderInstanceId
|
|
7678
|
+
}) {
|
|
7679
|
+
get message() {
|
|
7680
|
+
return `MCP credential does not grant the ${this.capability} capability.`;
|
|
7681
|
+
}
|
|
7682
|
+
};
|
|
7683
|
+
/**
|
|
7684
|
+
* The capability is present but the requested thread is not in the granted
|
|
7685
|
+
* set. Separate from {@link WatchToolUnavailableError} so a watcher can tell
|
|
7686
|
+
* "you cannot watch at all" apart from "not this thread".
|
|
7687
|
+
*/
|
|
7688
|
+
var ThreadWatchNotPermittedError = class extends Schema$1.TaggedErrorClass()("ThreadWatchNotPermittedError", { threadId: ThreadId }) {
|
|
7689
|
+
get message() {
|
|
7690
|
+
return `This session was not granted watch access to thread ${this.threadId}.`;
|
|
7691
|
+
}
|
|
7692
|
+
};
|
|
7693
|
+
var ThreadWatchFailedError = class extends Schema$1.TaggedErrorClass()("ThreadWatchFailedError", {
|
|
7694
|
+
threadId: ThreadId,
|
|
7695
|
+
detail: Schema$1.String
|
|
7696
|
+
}) {
|
|
7697
|
+
get message() {
|
|
7698
|
+
return `Reading events for thread ${this.threadId} failed: ${this.detail}`;
|
|
7699
|
+
}
|
|
7700
|
+
};
|
|
7701
|
+
const ThreadWatchToolError = Schema$1.Union([
|
|
7702
|
+
WatchToolUnavailableError,
|
|
7703
|
+
ThreadWatchNotPermittedError,
|
|
7704
|
+
ThreadWatchFailedError
|
|
7705
|
+
]);
|
|
7654
7706
|
//#endregion
|
|
7655
7707
|
//#region ../../packages/contracts/src/agentAsset.ts
|
|
7656
7708
|
/**
|
|
@@ -8094,6 +8146,15 @@ const McpSecretSlot = Schema$1.Struct({
|
|
|
8094
8146
|
* have to compute the same string or the value is written where nothing looks.
|
|
8095
8147
|
*/
|
|
8096
8148
|
const mcpSecretStorageName = (input) => `mcp.${input.server}.${input.target}.${input.key}`;
|
|
8149
|
+
/**
|
|
8150
|
+
* The storage name for a server's OAuth record — client id, endpoints, tokens.
|
|
8151
|
+
*
|
|
8152
|
+
* Beside `mcpSecretStorageName` for the same reason that one is here: the
|
|
8153
|
+
* server writing tokens and the registry cleaning up on remove must compute
|
|
8154
|
+
* the same string. Cannot collide with a slot name: slots always carry a
|
|
8155
|
+
* `header.` or `env.` segment where this has `oauth`.
|
|
8156
|
+
*/
|
|
8157
|
+
const mcpOAuthStorageName = (server) => `mcp.${server}.oauth`;
|
|
8097
8158
|
const commonFields = {
|
|
8098
8159
|
name: McpServerName,
|
|
8099
8160
|
/**
|
|
@@ -8135,6 +8196,20 @@ const McpRemoteServer = Schema$1.Struct({
|
|
|
8135
8196
|
*/
|
|
8136
8197
|
const McpServerRegistration = Schema$1.Union([McpStdioServer, McpRemoteServer]);
|
|
8137
8198
|
/**
|
|
8199
|
+
* OAuth state of a remote server, on this machine.
|
|
8200
|
+
*
|
|
8201
|
+
* Present only for a server that answered a readiness probe with a 401
|
|
8202
|
+
* challenge or that already holds a token here. Like `missingSecrets`, this is
|
|
8203
|
+
* per-machine truth about a registration that syncs everywhere: the token never
|
|
8204
|
+
* travels, so each machine reports its own `connected`.
|
|
8205
|
+
*/
|
|
8206
|
+
const McpServerOAuthStatus = Schema$1.Struct({
|
|
8207
|
+
/** The server demanded a bearer token this machine does not send. */
|
|
8208
|
+
required: Schema$1.Boolean,
|
|
8209
|
+
/** This machine holds a token for it. */
|
|
8210
|
+
connected: Schema$1.Boolean
|
|
8211
|
+
});
|
|
8212
|
+
/**
|
|
8138
8213
|
* What a panel needs to show, including what this machine cannot run.
|
|
8139
8214
|
*
|
|
8140
8215
|
* `missingSecrets` is the field that earns this type. A registration syncs
|
|
@@ -8146,7 +8221,9 @@ const McpServerStatus = Schema$1.Struct({
|
|
|
8146
8221
|
registration: McpServerRegistration,
|
|
8147
8222
|
missingSecrets: Schema$1.Array(McpSecretSlot),
|
|
8148
8223
|
/** True when this machine holds everything needed to start it. */
|
|
8149
|
-
ready: Schema$1.Boolean
|
|
8224
|
+
ready: Schema$1.Boolean,
|
|
8225
|
+
/** Absent for servers that never challenged and hold no token here. */
|
|
8226
|
+
oauth: Schema$1.optional(McpServerOAuthStatus)
|
|
8150
8227
|
});
|
|
8151
8228
|
const McpServerList = Schema$1.Struct({ servers: Schema$1.Array(McpServerStatus) });
|
|
8152
8229
|
const McpServerSaveInput = Schema$1.Struct({ registration: McpServerRegistration });
|
|
@@ -8164,6 +8241,12 @@ const McpServerSecretInput = Schema$1.Struct({
|
|
|
8164
8241
|
slot: McpSecretSlot,
|
|
8165
8242
|
value: Schema$1.String
|
|
8166
8243
|
});
|
|
8244
|
+
/**
|
|
8245
|
+
* The one thing the panel needs to continue a sign-in: where to send the
|
|
8246
|
+
* browser. Everything else the flow holds — verifier, client id, endpoints —
|
|
8247
|
+
* stays on the server, because the callback lands there, not on the panel.
|
|
8248
|
+
*/
|
|
8249
|
+
const McpOAuthBeginResult = Schema$1.Struct({ authorizeUrl: Schema$1.String });
|
|
8167
8250
|
var McpRegistryError = class extends Schema$1.TaggedErrorClass()("McpRegistryError", { detail: Schema$1.String }) {
|
|
8168
8251
|
get message() {
|
|
8169
8252
|
return this.detail;
|
|
@@ -8513,6 +8596,8 @@ const WS_METHODS = {
|
|
|
8513
8596
|
mcpSave: "mcp.save",
|
|
8514
8597
|
mcpRemove: "mcp.remove",
|
|
8515
8598
|
mcpSetSecret: "mcp.setSecret",
|
|
8599
|
+
mcpOAuthBegin: "mcp.oauthBegin",
|
|
8600
|
+
mcpOAuthDisconnect: "mcp.oauthDisconnect",
|
|
8516
8601
|
sourceControlLookupRepository: "sourceControl.lookupRepository",
|
|
8517
8602
|
sourceControlCloneRepository: "sourceControl.cloneRepository",
|
|
8518
8603
|
sourceControlPublishRepository: "sourceControl.publishRepository",
|
|
@@ -8782,6 +8867,21 @@ const WsMcpSetSecretRpc = Rpc.make(WS_METHODS.mcpSetSecret, {
|
|
|
8782
8867
|
error: Schema$1.Union([McpRegistryError, EnvironmentAuthorizationError])
|
|
8783
8868
|
});
|
|
8784
8869
|
/**
|
|
8870
|
+
* Starts an OAuth sign-in for a remote server and answers with the authorize
|
|
8871
|
+
* URL. The panel opens it in a browser; the redirect lands on this server's
|
|
8872
|
+
* own `/oauth/callback`, so nothing else crosses the wire to the client.
|
|
8873
|
+
*/
|
|
8874
|
+
const WsMcpOAuthBeginRpc = Rpc.make(WS_METHODS.mcpOAuthBegin, {
|
|
8875
|
+
payload: McpServerNameInput,
|
|
8876
|
+
success: McpOAuthBeginResult,
|
|
8877
|
+
error: Schema$1.Union([McpRegistryError, EnvironmentAuthorizationError])
|
|
8878
|
+
});
|
|
8879
|
+
const WsMcpOAuthDisconnectRpc = Rpc.make(WS_METHODS.mcpOAuthDisconnect, {
|
|
8880
|
+
payload: McpServerNameInput,
|
|
8881
|
+
success: McpServerList,
|
|
8882
|
+
error: Schema$1.Union([McpRegistryError, EnvironmentAuthorizationError])
|
|
8883
|
+
});
|
|
8884
|
+
/**
|
|
8785
8885
|
* The board, then every change to it, for as long as the client stays
|
|
8786
8886
|
* subscribed. The leading snapshot is what makes this sufficient on its own —
|
|
8787
8887
|
* a client does not list first, so there is no window between the two in which
|
|
@@ -9159,7 +9259,7 @@ const WsSubscribeAuthAccessRpc = Rpc.make(WS_METHODS.subscribeAuthAccess, {
|
|
|
9159
9259
|
error: Schema$1.Union([AuthAccessStreamError, EnvironmentAuthorizationError]),
|
|
9160
9260
|
stream: true
|
|
9161
9261
|
});
|
|
9162
|
-
const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsSkillRegistrySearchRpc, WsSkillRegistryFetchRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
|
|
9262
|
+
const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsSkillRegistrySearchRpc, WsSkillRegistryFetchRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsMcpOAuthBeginRpc, WsMcpOAuthDisconnectRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
|
|
9163
9263
|
//#endregion
|
|
9164
9264
|
//#region ../../packages/shared/src/oauthScope.ts
|
|
9165
9265
|
const OAUTH_SCOPE_TOKEN = /^[\u0021\u0023-\u005b\u005d-\u007e]+$/u;
|
|
@@ -9305,7 +9405,7 @@ function deriveAuthClientMetadata(input) {
|
|
|
9305
9405
|
//#endregion
|
|
9306
9406
|
//#region src/auth/EnvironmentAuthPolicy.ts
|
|
9307
9407
|
var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
|
|
9308
|
-
const make$
|
|
9408
|
+
const make$72 = Effect.gen(function* () {
|
|
9309
9409
|
const config = yield* ServerConfig$1;
|
|
9310
9410
|
const isRemoteReachable = isRemoteReachableHost(config.host);
|
|
9311
9411
|
const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
|
|
@@ -9323,7 +9423,7 @@ const make$71 = Effect.gen(function* () {
|
|
|
9323
9423
|
};
|
|
9324
9424
|
return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
|
|
9325
9425
|
});
|
|
9326
|
-
const layer$
|
|
9426
|
+
const layer$68 = Layer.effect(EnvironmentAuthPolicy, make$72);
|
|
9327
9427
|
//#endregion
|
|
9328
9428
|
//#region src/persistence/Errors.ts
|
|
9329
9429
|
function summarizeSchemaIssue(issue) {
|
|
@@ -9504,7 +9604,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
|
|
|
9504
9604
|
cause
|
|
9505
9605
|
});
|
|
9506
9606
|
}
|
|
9507
|
-
const make$
|
|
9607
|
+
const make$71 = Effect.gen(function* () {
|
|
9508
9608
|
const sql = yield* SqlClient.SqlClient;
|
|
9509
9609
|
const createSessionRow = SqlSchema.void({
|
|
9510
9610
|
Request: CreateAuthSessionInput,
|
|
@@ -9638,7 +9738,7 @@ const make$70 = Effect.gen(function* () {
|
|
|
9638
9738
|
setLastConnectedAt
|
|
9639
9739
|
};
|
|
9640
9740
|
});
|
|
9641
|
-
const layer$
|
|
9741
|
+
const layer$67 = Layer.effect(AuthSessionRepository, make$71);
|
|
9642
9742
|
//#endregion
|
|
9643
9743
|
//#region src/auth/ServerSecretStore.ts
|
|
9644
9744
|
const secretStoreErrorContext = {
|
|
@@ -9705,7 +9805,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
|
|
|
9705
9805
|
const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
|
|
9706
9806
|
const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
|
|
9707
9807
|
var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
|
|
9708
|
-
const make$
|
|
9808
|
+
const make$70 = Effect.gen(function* () {
|
|
9709
9809
|
const crypto = yield* Crypto.Crypto;
|
|
9710
9810
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
9711
9811
|
const path = yield* Path.Path;
|
|
@@ -9775,7 +9875,7 @@ const make$69 = Effect.gen(function* () {
|
|
|
9775
9875
|
remove
|
|
9776
9876
|
});
|
|
9777
9877
|
});
|
|
9778
|
-
const layer$
|
|
9878
|
+
const layer$66 = Layer.effect(ServerSecretStore, make$70);
|
|
9779
9879
|
//#endregion
|
|
9780
9880
|
//#region src/auth/SessionStore.ts
|
|
9781
9881
|
var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
|
|
@@ -10013,7 +10113,7 @@ function toAuthClientSession(input) {
|
|
|
10013
10113
|
current: false
|
|
10014
10114
|
};
|
|
10015
10115
|
}
|
|
10016
|
-
const make$
|
|
10116
|
+
const make$69 = Effect.gen(function* () {
|
|
10017
10117
|
const crypto = yield* Crypto.Crypto;
|
|
10018
10118
|
const serverConfig = yield* ServerConfig$1;
|
|
10019
10119
|
const secretStore = yield* ServerSecretStore;
|
|
@@ -10327,7 +10427,7 @@ const make$68 = Effect.gen(function* () {
|
|
|
10327
10427
|
markDisconnected
|
|
10328
10428
|
});
|
|
10329
10429
|
});
|
|
10330
|
-
const layer$
|
|
10430
|
+
const layer$65 = Layer.effect(SessionStore, make$69).pipe(Layer.provideMerge(layer$67));
|
|
10331
10431
|
//#endregion
|
|
10332
10432
|
//#region src/persistence/AuthPairingLinks.ts
|
|
10333
10433
|
const AuthPairingLinkRecord = Schema$1.Struct({
|
|
@@ -10388,7 +10488,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
|
|
|
10388
10488
|
cause
|
|
10389
10489
|
});
|
|
10390
10490
|
}
|
|
10391
|
-
const make$
|
|
10491
|
+
const make$68 = Effect.gen(function* () {
|
|
10392
10492
|
const sql = yield* SqlClient.SqlClient;
|
|
10393
10493
|
const createPairingLinkRow = SqlSchema.void({
|
|
10394
10494
|
Request: CreateAuthPairingLinkInput,
|
|
@@ -10523,7 +10623,7 @@ const make$67 = Effect.gen(function* () {
|
|
|
10523
10623
|
getByCredential
|
|
10524
10624
|
};
|
|
10525
10625
|
});
|
|
10526
|
-
const layer$
|
|
10626
|
+
const layer$64 = Layer.effect(AuthPairingLinkRepository, make$68);
|
|
10527
10627
|
//#endregion
|
|
10528
10628
|
//#region src/auth/PairingGrantStore.ts
|
|
10529
10629
|
var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
|
|
@@ -10618,7 +10718,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
|
|
|
10618
10718
|
const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
10619
10719
|
const PAIRING_TOKEN_LENGTH = 12;
|
|
10620
10720
|
const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
|
|
10621
|
-
const make$
|
|
10721
|
+
const make$67 = Effect.gen(function* () {
|
|
10622
10722
|
const crypto = yield* Crypto.Crypto;
|
|
10623
10723
|
const config = yield* ServerConfig$1;
|
|
10624
10724
|
const pairingLinks = yield* AuthPairingLinkRepository;
|
|
@@ -10816,7 +10916,7 @@ const make$66 = Effect.gen(function* () {
|
|
|
10816
10916
|
consume
|
|
10817
10917
|
});
|
|
10818
10918
|
});
|
|
10819
|
-
const layer$
|
|
10919
|
+
const layer$63 = Layer.effect(PairingGrantStore, make$67).pipe(Layer.provideMerge(layer$64));
|
|
10820
10920
|
//#endregion
|
|
10821
10921
|
//#region src/persistence/Migrations/001_OrchestrationEvents.ts
|
|
10822
10922
|
var _001_OrchestrationEvents_default = Effect.gen(function* () {
|
|
@@ -12671,7 +12771,7 @@ function parseBearerToken(request) {
|
|
|
12671
12771
|
const token = header.slice(7).trim();
|
|
12672
12772
|
return token.length > 0 ? token : null;
|
|
12673
12773
|
}
|
|
12674
|
-
const make$
|
|
12774
|
+
const make$66 = Effect.gen(function* () {
|
|
12675
12775
|
const policy = yield* EnvironmentAuthPolicy;
|
|
12676
12776
|
const bootstrapCredentials = yield* PairingGrantStore;
|
|
12677
12777
|
const sessions = yield* SessionStore;
|
|
@@ -12866,9 +12966,9 @@ const make$65 = Effect.gen(function* () {
|
|
|
12866
12966
|
issueStartupPairingUrl
|
|
12867
12967
|
});
|
|
12868
12968
|
});
|
|
12869
|
-
const layer$
|
|
12870
|
-
const storageLayer = Layer.mergeAll(layer$
|
|
12871
|
-
const runtimeLayer = layer$
|
|
12969
|
+
const layer$62 = Layer.effect(EnvironmentAuth, make$66).pipe(Layer.provideMerge(layer$63), Layer.provideMerge(layer$65), Layer.provideMerge(layer$68));
|
|
12970
|
+
const storageLayer = Layer.mergeAll(layer$66, layerConfig);
|
|
12971
|
+
const runtimeLayer = layer$62.pipe(Layer.provideMerge(storageLayer));
|
|
12872
12972
|
//#endregion
|
|
12873
12973
|
//#region src/cliAuthFormat.ts
|
|
12874
12974
|
const newline = "\n";
|
|
@@ -13623,7 +13723,7 @@ const runWithEnvironmentAuth = (flags, run, options) => Effect.gen(function* ()
|
|
|
13623
13723
|
}
|
|
13624
13724
|
return yield* Effect.gen(function* () {
|
|
13625
13725
|
return yield* run(yield* EnvironmentAuth);
|
|
13626
|
-
}).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$
|
|
13726
|
+
}).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
|
|
13627
13727
|
});
|
|
13628
13728
|
const ttlFlag = Flag.string("ttl").pipe(Flag.withSchema(DurationFromString), Flag.withDescription("TTL, for example `5m`, `1h`, `30d`, or `15 minutes`."), Flag.optional);
|
|
13629
13729
|
const jsonFlag = Flag.boolean("json").pipe(Flag.withDescription("Emit JSON instead of human-readable output."), Flag.withDefault(false));
|
|
@@ -13763,7 +13863,7 @@ const DEFAULT_LIMITS = {
|
|
|
13763
13863
|
windowMillis: FAILURE_WINDOW_MS,
|
|
13764
13864
|
blockMillis: BLOCK_DURATION_MS
|
|
13765
13865
|
};
|
|
13766
|
-
const make$
|
|
13866
|
+
const make$65 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
|
|
13767
13867
|
const state = yield* Ref.make(initialThrottleState);
|
|
13768
13868
|
return HubAuthThrottle.of({
|
|
13769
13869
|
shouldRefuse: Effect.gen(function* () {
|
|
@@ -13777,7 +13877,7 @@ const make$64 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
|
|
|
13777
13877
|
})
|
|
13778
13878
|
});
|
|
13779
13879
|
});
|
|
13780
|
-
const layer$
|
|
13880
|
+
const layer$61 = Layer.effect(HubAuthThrottle, make$65());
|
|
13781
13881
|
//#endregion
|
|
13782
13882
|
//#region src/hub/HubAuth.ts
|
|
13783
13883
|
/**
|
|
@@ -14576,7 +14676,7 @@ const deleteAssetRoute = HttpRouter.add("DELETE", "/assets/:kind/:name", respond
|
|
|
14576
14676
|
const outcome = yield* (yield* AgentAssetRepository).deleteByName(requested);
|
|
14577
14677
|
return outcome._tag === "conflict" ? assetConflict(Option.getOrNull(outcome.current)) : HttpServerResponse.empty({ status: 204 });
|
|
14578
14678
|
})));
|
|
14579
|
-
const layer$
|
|
14679
|
+
const layer$60 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
|
|
14580
14680
|
//#endregion
|
|
14581
14681
|
//#region src/hub/Migrations/001_Tasks.ts
|
|
14582
14682
|
/**
|
|
@@ -14855,7 +14955,7 @@ const announce = Layer.effectDiscard(Effect.gen(function* () {
|
|
|
14855
14955
|
});
|
|
14856
14956
|
if (isRemoteReachableHost(config.host)) yield* Effect.logWarning("Hub is reachable beyond loopback. The bearer token is the only control — repeated auth failures are not rate limited.", { host: config.host });
|
|
14857
14957
|
}));
|
|
14858
|
-
const makeHubLayer = HttpRouter.serve(layer$
|
|
14958
|
+
const makeHubLayer = HttpRouter.serve(layer$60).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$61), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
|
|
14859
14959
|
const runHub = Layer.launch(makeHubLayer);
|
|
14860
14960
|
//#endregion
|
|
14861
14961
|
//#region src/atomicWrite.ts
|
|
@@ -14979,7 +15079,7 @@ function stripDefaultServerSettings(current, defaults) {
|
|
|
14979
15079
|
}
|
|
14980
15080
|
return Object.is(current, defaults) ? void 0 : current;
|
|
14981
15081
|
}
|
|
14982
|
-
const make$
|
|
15082
|
+
const make$64 = Effect.gen(function* () {
|
|
14983
15083
|
const { settingsPath } = yield* ServerConfig$1;
|
|
14984
15084
|
const fs = yield* FileSystem.FileSystem;
|
|
14985
15085
|
const pathService = yield* Path.Path;
|
|
@@ -15200,7 +15300,7 @@ const make$63 = Effect.gen(function* () {
|
|
|
15200
15300
|
}
|
|
15201
15301
|
};
|
|
15202
15302
|
});
|
|
15203
|
-
const layer$
|
|
15303
|
+
const layer$59 = Layer.effect(ServerSettingsService, make$64);
|
|
15204
15304
|
//#endregion
|
|
15205
15305
|
//#region src/pathExpansion.ts
|
|
15206
15306
|
/**
|
|
@@ -15409,6 +15509,464 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
|
|
|
15409
15509
|
}
|
|
15410
15510
|
return [...skillsByName.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
15411
15511
|
});
|
|
15512
|
+
//#endregion
|
|
15513
|
+
//#region src/mcp/McpOAuth.ts
|
|
15514
|
+
/**
|
|
15515
|
+
* OAuth sign-in for remote MCP servers, per the MCP authorization spec.
|
|
15516
|
+
*
|
|
15517
|
+
* The whole flow runs on this server: RFC 9728 protected-resource discovery,
|
|
15518
|
+
* RFC 8414 authorization-server metadata, RFC 7591 dynamic client
|
|
15519
|
+
* registration, PKCE, and the token exchange when the browser lands on
|
|
15520
|
+
* `/oauth/callback`. The panel only ever sees one string — the authorize URL —
|
|
15521
|
+
* because everything else in the flow is either a secret or only meaningful to
|
|
15522
|
+
* the machine the callback returns to.
|
|
15523
|
+
*
|
|
15524
|
+
* **Everything learned per server is one JSON secret** in `ServerSecretStore`
|
|
15525
|
+
* (`mcp.<server>.oauth`): client id, endpoints, tokens. Registrations sync
|
|
15526
|
+
* between machines; this record deliberately does not, which is what makes
|
|
15527
|
+
* "each machine signs in for itself" true by construction rather than policy.
|
|
15528
|
+
*
|
|
15529
|
+
* @module mcp/McpOAuth
|
|
15530
|
+
*/
|
|
15531
|
+
/** How long a probe's verdict is trusted before the server is asked again. */
|
|
15532
|
+
const PROBE_CACHE_TTL_MS = 300 * 1e3;
|
|
15533
|
+
/** An authorize URL nobody returned from within this window is abandoned. */
|
|
15534
|
+
const PENDING_FLOW_TTL_MS = 600 * 1e3;
|
|
15535
|
+
/** A token this close to expiry is refreshed rather than handed to a session. */
|
|
15536
|
+
const TOKEN_EXPIRY_MARGIN_MS = 60 * 1e3;
|
|
15537
|
+
/** Outbound discovery, registration and token requests all use this cap. */
|
|
15538
|
+
const OAUTH_REQUEST_TIMEOUT_MS = 10 * 1e3;
|
|
15539
|
+
const CODE_VERIFIER_BYTES = 32;
|
|
15540
|
+
const STATE_BYTES = 16;
|
|
15541
|
+
/** Sent in the probe's initialize request; any spec revision the server accepts will do. */
|
|
15542
|
+
const MCP_PROBE_PROTOCOL_VERSION = "2025-06-18";
|
|
15543
|
+
/** What the authorization server's consent screen shows. See `registerClient`. */
|
|
15544
|
+
const OAUTH_CLIENT_NAME = "Claude Code (p4code)";
|
|
15545
|
+
/** The path the environment server answers on; also sent as the redirect URI. */
|
|
15546
|
+
const OAUTH_CALLBACK_PATH = "/oauth/callback";
|
|
15547
|
+
const StoredTokens = Schema$1.Struct({
|
|
15548
|
+
accessToken: Schema$1.String,
|
|
15549
|
+
refreshToken: Schema$1.optional(Schema$1.String),
|
|
15550
|
+
/** Epoch milliseconds. Absent when the server did not say. */
|
|
15551
|
+
expiresAt: Schema$1.optional(Schema$1.Number)
|
|
15552
|
+
});
|
|
15553
|
+
/**
|
|
15554
|
+
* Everything this machine holds about one server's OAuth relationship.
|
|
15555
|
+
*
|
|
15556
|
+
* Endpoints and client id live beside the tokens so that disconnect can drop
|
|
15557
|
+
* the tokens and a later reconnect can skip re-registration — a client id is
|
|
15558
|
+
* not a credential, but re-registering on every sign-in litters the
|
|
15559
|
+
* authorization server with one-use clients.
|
|
15560
|
+
*/
|
|
15561
|
+
const StoredOAuth = Schema$1.Struct({
|
|
15562
|
+
clientId: Schema$1.String,
|
|
15563
|
+
clientSecret: Schema$1.optional(Schema$1.String),
|
|
15564
|
+
authorizationEndpoint: Schema$1.String,
|
|
15565
|
+
tokenEndpoint: Schema$1.String,
|
|
15566
|
+
/** RFC 8707 resource indicator: the canonical MCP server URL. */
|
|
15567
|
+
resource: Schema$1.optional(Schema$1.String),
|
|
15568
|
+
scope: Schema$1.optional(Schema$1.String),
|
|
15569
|
+
tokens: Schema$1.optional(StoredTokens)
|
|
15570
|
+
});
|
|
15571
|
+
const StoredOAuthFromJson = Schema$1.fromJsonString(StoredOAuth);
|
|
15572
|
+
const decodeStored = Schema$1.decodeUnknownExit(StoredOAuthFromJson);
|
|
15573
|
+
const encodeStored = Schema$1.encodeSync(StoredOAuthFromJson);
|
|
15574
|
+
/**
|
|
15575
|
+
* Parse a `WWW-Authenticate` challenge into its scheme and parameters.
|
|
15576
|
+
*
|
|
15577
|
+
* Handles the shape MCP servers actually send — `Bearer` followed by
|
|
15578
|
+
* comma-separated `key="value"` or bare `key=value` pairs. Exported for tests;
|
|
15579
|
+
* a wrong parse here turns "needs sign-in" into "broken server".
|
|
15580
|
+
*/
|
|
15581
|
+
function parseWwwAuthenticate(header) {
|
|
15582
|
+
const trimmed = header.trim();
|
|
15583
|
+
const spaceIndex = trimmed.indexOf(" ");
|
|
15584
|
+
const scheme = (spaceIndex === -1 ? trimmed : trimmed.slice(0, spaceIndex)).toLowerCase();
|
|
15585
|
+
const rest = spaceIndex === -1 ? "" : trimmed.slice(spaceIndex + 1);
|
|
15586
|
+
const params = {};
|
|
15587
|
+
for (const match of rest.matchAll(/([a-zA-Z0-9_-]+)\s*=\s*(?:"([^"]*)"|([^\s,]+))/gu)) {
|
|
15588
|
+
const key = match[1];
|
|
15589
|
+
const value = match[2] ?? match[3];
|
|
15590
|
+
if (key !== void 0 && value !== void 0) params[key.toLowerCase()] = value;
|
|
15591
|
+
}
|
|
15592
|
+
return {
|
|
15593
|
+
scheme,
|
|
15594
|
+
params
|
|
15595
|
+
};
|
|
15596
|
+
}
|
|
15597
|
+
/**
|
|
15598
|
+
* The RFC 8414 lookup locations for an issuer, in the order worth trying.
|
|
15599
|
+
*
|
|
15600
|
+
* Path insertion first — `https://a/.well-known/oauth-authorization-server/x`
|
|
15601
|
+
* for issuer `https://a/x` — then the OIDC variants, because real servers are
|
|
15602
|
+
* split between the two specs and a miss costs one request.
|
|
15603
|
+
*/
|
|
15604
|
+
function authServerMetadataUrls(issuer) {
|
|
15605
|
+
const url = new URL(issuer);
|
|
15606
|
+
const path = url.pathname === "/" ? "" : url.pathname.replace(/\/$/u, "");
|
|
15607
|
+
return [
|
|
15608
|
+
`${url.origin}/.well-known/oauth-authorization-server${path}`,
|
|
15609
|
+
`${url.origin}/.well-known/openid-configuration${path}`,
|
|
15610
|
+
...path === "" ? [] : [`${url.origin}${path}/.well-known/openid-configuration`]
|
|
15611
|
+
];
|
|
15612
|
+
}
|
|
15613
|
+
const AuthServerMetadata = Schema$1.Struct({
|
|
15614
|
+
authorization_endpoint: Schema$1.String,
|
|
15615
|
+
token_endpoint: Schema$1.String,
|
|
15616
|
+
registration_endpoint: Schema$1.optional(Schema$1.String),
|
|
15617
|
+
scopes_supported: Schema$1.optional(Schema$1.Array(Schema$1.String))
|
|
15618
|
+
});
|
|
15619
|
+
const ProtectedResourceMetadata = Schema$1.Struct({
|
|
15620
|
+
authorization_servers: Schema$1.optional(Schema$1.Array(Schema$1.String)),
|
|
15621
|
+
scopes_supported: Schema$1.optional(Schema$1.Array(Schema$1.String))
|
|
15622
|
+
});
|
|
15623
|
+
const ClientRegistrationResponse = Schema$1.Struct({
|
|
15624
|
+
client_id: Schema$1.String,
|
|
15625
|
+
client_secret: Schema$1.optional(Schema$1.String)
|
|
15626
|
+
});
|
|
15627
|
+
const TokenResponse = Schema$1.Struct({
|
|
15628
|
+
access_token: Schema$1.String,
|
|
15629
|
+
refresh_token: Schema$1.optional(Schema$1.String),
|
|
15630
|
+
expires_in: Schema$1.optional(Schema$1.Number)
|
|
15631
|
+
});
|
|
15632
|
+
const decodeJsonBody = Schema$1.decodeUnknownExit(Schema$1.UnknownFromJsonString);
|
|
15633
|
+
const decodeAuthServerMetadata = Schema$1.decodeUnknownExit(AuthServerMetadata);
|
|
15634
|
+
const decodeProtectedResourceMetadata = Schema$1.decodeUnknownExit(ProtectedResourceMetadata);
|
|
15635
|
+
const decodeClientRegistration = Schema$1.decodeUnknownExit(ClientRegistrationResponse);
|
|
15636
|
+
const decodeTokenResponse = Schema$1.decodeUnknownExit(TokenResponse);
|
|
15637
|
+
var McpOAuth = class extends Context.Service()("@p4code/cli/mcp/McpOAuth") {};
|
|
15638
|
+
const registryError = (detail) => new McpRegistryError({ detail });
|
|
15639
|
+
const make$63 = Effect.gen(function* () {
|
|
15640
|
+
const config = yield* ServerConfig$1;
|
|
15641
|
+
const secrets = yield* ServerSecretStore;
|
|
15642
|
+
const http = yield* HttpClient.HttpClient;
|
|
15643
|
+
const crypto = yield* Crypto.Crypto;
|
|
15644
|
+
const pendingFlows = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
15645
|
+
const probeCache = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
15646
|
+
const redirectUri = `http://127.0.0.1:${config.port}${OAUTH_CALLBACK_PATH}`;
|
|
15647
|
+
const nowMillis = Effect.map(DateTime.now, DateTime.toEpochMillis);
|
|
15648
|
+
const readRecord = Effect.fn("McpOAuth.readRecord")(function* (server) {
|
|
15649
|
+
const stored = yield* secrets.get(mcpOAuthStorageName(server)).pipe(Effect.orElseSucceed(() => Option.none()));
|
|
15650
|
+
if (Option.isNone(stored)) return Option.none();
|
|
15651
|
+
const decoded = decodeStored(new TextDecoder().decode(stored.value));
|
|
15652
|
+
return decoded._tag === "Success" ? Option.some(decoded.value) : Option.none();
|
|
15653
|
+
});
|
|
15654
|
+
const writeRecord = Effect.fn("McpOAuth.writeRecord")(function* (server, record) {
|
|
15655
|
+
yield* secrets.set(mcpOAuthStorageName(server), new TextEncoder().encode(encodeStored(record))).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp oauth record write failed", {
|
|
15656
|
+
cause,
|
|
15657
|
+
server
|
|
15658
|
+
})));
|
|
15659
|
+
});
|
|
15660
|
+
const fetchJson = Effect.fn("McpOAuth.fetchJson")(function* (request) {
|
|
15661
|
+
const response = yield* http.execute(HttpClientRequest.setHeader(request, "accept", "application/json")).pipe(Effect.timeout(OAUTH_REQUEST_TIMEOUT_MS));
|
|
15662
|
+
const text = yield* response.text;
|
|
15663
|
+
const parsed = decodeJsonBody(text);
|
|
15664
|
+
return {
|
|
15665
|
+
status: response.status,
|
|
15666
|
+
json: parsed._tag === "Success" ? parsed.value : void 0
|
|
15667
|
+
};
|
|
15668
|
+
});
|
|
15669
|
+
/**
|
|
15670
|
+
* Ask the server, without credentials, whether it wants any.
|
|
15671
|
+
*
|
|
15672
|
+
* A real MCP initialize request rather than a bare GET, because the GET is
|
|
15673
|
+
* not part of the streamable-http contract and real servers 405 it — Figma
|
|
15674
|
+
* does — while answering the initialize POST with the 401 challenge this
|
|
15675
|
+
* probe exists to see.
|
|
15676
|
+
*/
|
|
15677
|
+
const probe = Effect.fn("McpOAuth.probe")(function* (registration) {
|
|
15678
|
+
const now = yield* nowMillis;
|
|
15679
|
+
const cached = (yield* Ref.get(probeCache)).get(registration.url);
|
|
15680
|
+
if (cached !== void 0 && now - cached.at < PROBE_CACHE_TTL_MS) return cached;
|
|
15681
|
+
const verdict = yield* http.execute(HttpClientRequest.bodyJsonUnsafe(HttpClientRequest.setHeaders(HttpClientRequest.post(registration.url), {
|
|
15682
|
+
...registration.headers,
|
|
15683
|
+
accept: "application/json, text/event-stream"
|
|
15684
|
+
}), {
|
|
15685
|
+
jsonrpc: "2.0",
|
|
15686
|
+
id: 0,
|
|
15687
|
+
method: "initialize",
|
|
15688
|
+
params: {
|
|
15689
|
+
protocolVersion: MCP_PROBE_PROTOCOL_VERSION,
|
|
15690
|
+
capabilities: {},
|
|
15691
|
+
clientInfo: {
|
|
15692
|
+
name: "p4code",
|
|
15693
|
+
version: "0.0.0"
|
|
15694
|
+
}
|
|
15695
|
+
}
|
|
15696
|
+
})).pipe(Effect.timeout(OAUTH_REQUEST_TIMEOUT_MS), Effect.map((response) => {
|
|
15697
|
+
const challengeHeader = response.headers["www-authenticate"];
|
|
15698
|
+
const challenge = response.status === 401 && challengeHeader !== void 0 ? parseWwwAuthenticate(challengeHeader) : void 0;
|
|
15699
|
+
return {
|
|
15700
|
+
at: now,
|
|
15701
|
+
requiresAuth: response.status === 401,
|
|
15702
|
+
resourceMetadataUrl: challenge?.params["resource_metadata"],
|
|
15703
|
+
scope: challenge?.params["scope"]
|
|
15704
|
+
};
|
|
15705
|
+
}), Effect.orElseSucceed(() => ({
|
|
15706
|
+
at: now,
|
|
15707
|
+
requiresAuth: false,
|
|
15708
|
+
resourceMetadataUrl: void 0,
|
|
15709
|
+
scope: void 0
|
|
15710
|
+
})));
|
|
15711
|
+
yield* Ref.update(probeCache, (cache) => {
|
|
15712
|
+
const next = new Map(cache);
|
|
15713
|
+
next.set(registration.url, verdict);
|
|
15714
|
+
return next;
|
|
15715
|
+
});
|
|
15716
|
+
return verdict;
|
|
15717
|
+
});
|
|
15718
|
+
const forgetProbe = (url) => Ref.update(probeCache, (cache) => {
|
|
15719
|
+
const next = new Map(cache);
|
|
15720
|
+
next.delete(url);
|
|
15721
|
+
return next;
|
|
15722
|
+
});
|
|
15723
|
+
const statusFor = (registration) => Effect.gen(function* () {
|
|
15724
|
+
const record = yield* readRecord(registration.name);
|
|
15725
|
+
if (Option.isSome(record) && record.value.tokens !== void 0) return Option.some({
|
|
15726
|
+
required: true,
|
|
15727
|
+
connected: true
|
|
15728
|
+
});
|
|
15729
|
+
if ((yield* probe(registration)).requiresAuth || Option.isSome(record)) return Option.some({
|
|
15730
|
+
required: true,
|
|
15731
|
+
connected: false
|
|
15732
|
+
});
|
|
15733
|
+
return Option.none();
|
|
15734
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp oauth status failed", {
|
|
15735
|
+
cause,
|
|
15736
|
+
server: registration.name
|
|
15737
|
+
}).pipe(Effect.as(Option.none()))));
|
|
15738
|
+
/**
|
|
15739
|
+
* Find the authorization server for an MCP endpoint.
|
|
15740
|
+
*
|
|
15741
|
+
* RFC 9728 first: the 401 challenge names a protected-resource metadata URL,
|
|
15742
|
+
* which names the authorization servers. When the challenge does not say —
|
|
15743
|
+
* the spec's fallback — the MCP origin itself is tried as the issuer.
|
|
15744
|
+
*/
|
|
15745
|
+
const discover = Effect.fn("McpOAuth.discover")(function* (registration) {
|
|
15746
|
+
yield* forgetProbe(registration.url);
|
|
15747
|
+
const verdict = yield* probe(registration);
|
|
15748
|
+
let issuers = [new URL(registration.url).origin];
|
|
15749
|
+
let resourceScopes;
|
|
15750
|
+
const metadataUrl = verdict.resourceMetadataUrl ?? `${new URL(registration.url).origin}/.well-known/oauth-protected-resource${new URL(registration.url).pathname.replace(/\/$/u, "")}`;
|
|
15751
|
+
const resourceMetadata = yield* fetchJson(HttpClientRequest.get(metadataUrl)).pipe(Effect.map(({ status, json }) => {
|
|
15752
|
+
if (status !== 200) return void 0;
|
|
15753
|
+
const decoded = decodeProtectedResourceMetadata(json);
|
|
15754
|
+
return decoded._tag === "Success" ? decoded.value : void 0;
|
|
15755
|
+
}), Effect.orElseSucceed(() => void 0));
|
|
15756
|
+
if (resourceMetadata !== void 0) {
|
|
15757
|
+
if ((resourceMetadata.authorization_servers?.length ?? 0) > 0) issuers = resourceMetadata.authorization_servers ?? issuers;
|
|
15758
|
+
resourceScopes = resourceMetadata.scopes_supported;
|
|
15759
|
+
}
|
|
15760
|
+
for (const issuer of issuers) for (const candidate of authServerMetadataUrls(issuer)) {
|
|
15761
|
+
const metadata = yield* fetchJson(HttpClientRequest.get(candidate)).pipe(Effect.map(({ status, json }) => {
|
|
15762
|
+
if (status !== 200) return void 0;
|
|
15763
|
+
const decoded = decodeAuthServerMetadata(json);
|
|
15764
|
+
return decoded._tag === "Success" ? decoded.value : void 0;
|
|
15765
|
+
}), Effect.orElseSucceed(() => void 0));
|
|
15766
|
+
if (metadata !== void 0) return {
|
|
15767
|
+
metadata,
|
|
15768
|
+
scope: verdict.scope ?? (resourceScopes !== void 0 && resourceScopes.length > 0 ? resourceScopes.join(" ") : void 0)
|
|
15769
|
+
};
|
|
15770
|
+
}
|
|
15771
|
+
return yield* registryError(`Could not discover an OAuth authorization server for ${registration.url}.`);
|
|
15772
|
+
});
|
|
15773
|
+
const registerClient = Effect.fn("McpOAuth.registerClient")(function* (metadata) {
|
|
15774
|
+
if (metadata.registration_endpoint === void 0) return yield* registryError("The authorization server does not support dynamic client registration.");
|
|
15775
|
+
const { status, json } = yield* fetchJson(HttpClientRequest.bodyJsonUnsafe(HttpClientRequest.post(metadata.registration_endpoint), {
|
|
15776
|
+
client_name: OAUTH_CLIENT_NAME,
|
|
15777
|
+
redirect_uris: [redirectUri],
|
|
15778
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
15779
|
+
response_types: ["code"],
|
|
15780
|
+
token_endpoint_auth_method: "none"
|
|
15781
|
+
})).pipe(Effect.mapError(() => registryError("Client registration request failed.")));
|
|
15782
|
+
if (status !== 200 && status !== 201) return yield* registryError(`Client registration was rejected with status ${status}.`);
|
|
15783
|
+
const decoded = decodeClientRegistration(json);
|
|
15784
|
+
if (decoded._tag !== "Success") return yield* registryError("Client registration answered an unexpected shape.");
|
|
15785
|
+
return decoded.value;
|
|
15786
|
+
});
|
|
15787
|
+
const randomUrlSafe = (bytes) => crypto.randomBytes(bytes).pipe(Effect.map(Encoding.encodeBase64Url));
|
|
15788
|
+
const begin = (registration) => Effect.gen(function* () {
|
|
15789
|
+
const { metadata, scope } = yield* discover(registration);
|
|
15790
|
+
const existing = yield* readRecord(registration.name);
|
|
15791
|
+
const reusable = Option.filter(existing, (record) => record.tokenEndpoint === metadata.token_endpoint && record.authorizationEndpoint === metadata.authorization_endpoint);
|
|
15792
|
+
const client = Option.isSome(reusable) ? {
|
|
15793
|
+
client_id: reusable.value.clientId,
|
|
15794
|
+
client_secret: reusable.value.clientSecret
|
|
15795
|
+
} : yield* registerClient(metadata);
|
|
15796
|
+
const codeVerifier = yield* randomUrlSafe(CODE_VERIFIER_BYTES).pipe(Effect.mapError(() => registryError("Could not generate a PKCE verifier.")));
|
|
15797
|
+
const challengeBytes = yield* crypto.digest("SHA-256", new TextEncoder().encode(codeVerifier)).pipe(Effect.mapError(() => registryError("Could not hash the PKCE verifier.")));
|
|
15798
|
+
const state = yield* randomUrlSafe(STATE_BYTES).pipe(Effect.mapError(() => registryError("Could not generate a state value.")));
|
|
15799
|
+
const record = {
|
|
15800
|
+
clientId: client.client_id,
|
|
15801
|
+
...client.client_secret === void 0 ? {} : { clientSecret: client.client_secret },
|
|
15802
|
+
authorizationEndpoint: metadata.authorization_endpoint,
|
|
15803
|
+
tokenEndpoint: metadata.token_endpoint,
|
|
15804
|
+
resource: registration.url,
|
|
15805
|
+
...scope === void 0 ? {} : { scope }
|
|
15806
|
+
};
|
|
15807
|
+
yield* writeRecord(registration.name, record);
|
|
15808
|
+
const startedAt = yield* nowMillis;
|
|
15809
|
+
yield* Ref.update(pendingFlows, (flows) => {
|
|
15810
|
+
const next = new Map([...flows].filter(([, flow]) => startedAt - flow.startedAt < PENDING_FLOW_TTL_MS));
|
|
15811
|
+
next.set(state, {
|
|
15812
|
+
server: registration.name,
|
|
15813
|
+
codeVerifier,
|
|
15814
|
+
redirectUri,
|
|
15815
|
+
record,
|
|
15816
|
+
startedAt
|
|
15817
|
+
});
|
|
15818
|
+
return next;
|
|
15819
|
+
});
|
|
15820
|
+
const authorizeUrl = new URL(metadata.authorization_endpoint);
|
|
15821
|
+
authorizeUrl.searchParams.set("response_type", "code");
|
|
15822
|
+
authorizeUrl.searchParams.set("client_id", client.client_id);
|
|
15823
|
+
authorizeUrl.searchParams.set("redirect_uri", redirectUri);
|
|
15824
|
+
authorizeUrl.searchParams.set("state", state);
|
|
15825
|
+
authorizeUrl.searchParams.set("code_challenge", Encoding.encodeBase64Url(challengeBytes));
|
|
15826
|
+
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
15827
|
+
authorizeUrl.searchParams.set("resource", registration.url);
|
|
15828
|
+
if (scope !== void 0) authorizeUrl.searchParams.set("scope", scope);
|
|
15829
|
+
return { authorizeUrl: authorizeUrl.toString() };
|
|
15830
|
+
});
|
|
15831
|
+
const exchangeToken = Effect.fn("McpOAuth.exchangeToken")(function* (flow, code) {
|
|
15832
|
+
const { status, json } = yield* fetchJson(HttpClientRequest.bodyUrlParams(HttpClientRequest.post(flow.record.tokenEndpoint), {
|
|
15833
|
+
grant_type: "authorization_code",
|
|
15834
|
+
code,
|
|
15835
|
+
redirect_uri: flow.redirectUri,
|
|
15836
|
+
client_id: flow.record.clientId,
|
|
15837
|
+
code_verifier: flow.codeVerifier,
|
|
15838
|
+
...flow.record.clientSecret === void 0 ? {} : { client_secret: flow.record.clientSecret },
|
|
15839
|
+
...flow.record.resource === void 0 ? {} : { resource: flow.record.resource }
|
|
15840
|
+
}));
|
|
15841
|
+
if (status !== 200) return yield* Effect.fail(`token endpoint answered status ${status}`);
|
|
15842
|
+
const decoded = decodeTokenResponse(json);
|
|
15843
|
+
if (decoded._tag !== "Success") return yield* Effect.fail("token endpoint answered an unexpected shape");
|
|
15844
|
+
return decoded.value;
|
|
15845
|
+
});
|
|
15846
|
+
const handleCallback = (params) => Effect.gen(function* () {
|
|
15847
|
+
if (params.state === void 0) return {
|
|
15848
|
+
ok: false,
|
|
15849
|
+
detail: "The redirect carried no state value."
|
|
15850
|
+
};
|
|
15851
|
+
const flow = (yield* Ref.get(pendingFlows)).get(params.state);
|
|
15852
|
+
if (flow === void 0) return {
|
|
15853
|
+
ok: false,
|
|
15854
|
+
detail: "This sign-in is unknown or has expired. Start it again from settings."
|
|
15855
|
+
};
|
|
15856
|
+
yield* Ref.update(pendingFlows, (current) => {
|
|
15857
|
+
const next = new Map(current);
|
|
15858
|
+
next.delete(params.state);
|
|
15859
|
+
return next;
|
|
15860
|
+
});
|
|
15861
|
+
if (params.error !== void 0) return {
|
|
15862
|
+
ok: false,
|
|
15863
|
+
detail: params.errorDescription ?? `The authorization server answered: ${params.error}.`
|
|
15864
|
+
};
|
|
15865
|
+
if (params.code === void 0) return {
|
|
15866
|
+
ok: false,
|
|
15867
|
+
detail: "The redirect carried no authorization code."
|
|
15868
|
+
};
|
|
15869
|
+
const now = yield* nowMillis;
|
|
15870
|
+
const exchanged = yield* exchangeToken(flow, params.code).pipe(Effect.map((response) => ({
|
|
15871
|
+
failed: false,
|
|
15872
|
+
response
|
|
15873
|
+
})), Effect.catch((detail) => Effect.succeed({
|
|
15874
|
+
failed: true,
|
|
15875
|
+
detail: typeof detail === "string" ? detail : "the token request failed"
|
|
15876
|
+
})));
|
|
15877
|
+
if (exchanged.failed) {
|
|
15878
|
+
yield* Effect.logWarning("mcp oauth token exchange failed", {
|
|
15879
|
+
server: flow.server,
|
|
15880
|
+
detail: exchanged.detail
|
|
15881
|
+
});
|
|
15882
|
+
return {
|
|
15883
|
+
ok: false,
|
|
15884
|
+
detail: `Token exchange failed: ${exchanged.detail}.`
|
|
15885
|
+
};
|
|
15886
|
+
}
|
|
15887
|
+
yield* writeRecord(flow.server, {
|
|
15888
|
+
...flow.record,
|
|
15889
|
+
tokens: {
|
|
15890
|
+
accessToken: exchanged.response.access_token,
|
|
15891
|
+
...exchanged.response.refresh_token === void 0 ? {} : { refreshToken: exchanged.response.refresh_token },
|
|
15892
|
+
...exchanged.response.expires_in === void 0 ? {} : { expiresAt: now + exchanged.response.expires_in * 1e3 }
|
|
15893
|
+
}
|
|
15894
|
+
});
|
|
15895
|
+
return {
|
|
15896
|
+
ok: true,
|
|
15897
|
+
server: flow.server
|
|
15898
|
+
};
|
|
15899
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp oauth callback failed", { cause }).pipe(Effect.as({
|
|
15900
|
+
ok: false,
|
|
15901
|
+
detail: "The sign-in failed. See the server log."
|
|
15902
|
+
}))));
|
|
15903
|
+
const disconnect = (name) => Effect.gen(function* () {
|
|
15904
|
+
const record = yield* readRecord(name);
|
|
15905
|
+
if (Option.isNone(record)) return;
|
|
15906
|
+
const { tokens: _dropped, ...rest } = record.value;
|
|
15907
|
+
yield* writeRecord(name, rest);
|
|
15908
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp oauth disconnect failed", {
|
|
15909
|
+
cause,
|
|
15910
|
+
server: name
|
|
15911
|
+
}).pipe(Effect.asVoid)));
|
|
15912
|
+
const refreshTokens = Effect.fn("McpOAuth.refreshTokens")(function* (server, record, refreshToken) {
|
|
15913
|
+
const { status, json } = yield* fetchJson(HttpClientRequest.bodyUrlParams(HttpClientRequest.post(record.tokenEndpoint), {
|
|
15914
|
+
grant_type: "refresh_token",
|
|
15915
|
+
refresh_token: refreshToken,
|
|
15916
|
+
client_id: record.clientId,
|
|
15917
|
+
...record.clientSecret === void 0 ? {} : { client_secret: record.clientSecret },
|
|
15918
|
+
...record.resource === void 0 ? {} : { resource: record.resource }
|
|
15919
|
+
}));
|
|
15920
|
+
if (status !== 200) return yield* Effect.fail(`status ${status}`);
|
|
15921
|
+
const decoded = decodeTokenResponse(json);
|
|
15922
|
+
if (decoded._tag !== "Success") return yield* Effect.fail("unexpected shape");
|
|
15923
|
+
const response = decoded.value;
|
|
15924
|
+
const now = yield* nowMillis;
|
|
15925
|
+
const tokens = {
|
|
15926
|
+
accessToken: response.access_token,
|
|
15927
|
+
refreshToken: response.refresh_token ?? refreshToken,
|
|
15928
|
+
...response.expires_in === void 0 ? {} : { expiresAt: now + response.expires_in * 1e3 }
|
|
15929
|
+
};
|
|
15930
|
+
yield* writeRecord(server, {
|
|
15931
|
+
...record,
|
|
15932
|
+
tokens
|
|
15933
|
+
});
|
|
15934
|
+
return tokens.accessToken;
|
|
15935
|
+
});
|
|
15936
|
+
const accessTokenFor = (registration) => Effect.gen(function* () {
|
|
15937
|
+
const record = yield* readRecord(registration.name);
|
|
15938
|
+
if (Option.isNone(record) || record.value.tokens === void 0) return Option.none();
|
|
15939
|
+
const tokens = record.value.tokens;
|
|
15940
|
+
const now = yield* nowMillis;
|
|
15941
|
+
if (!(tokens.expiresAt !== void 0 && now >= tokens.expiresAt - TOKEN_EXPIRY_MARGIN_MS)) return Option.some(tokens.accessToken);
|
|
15942
|
+
if (tokens.refreshToken === void 0) return Option.none();
|
|
15943
|
+
return yield* refreshTokens(registration.name, record.value, tokens.refreshToken).pipe(Effect.map(Option.some), Effect.catchCause((cause) => Effect.logWarning("mcp oauth refresh failed", {
|
|
15944
|
+
cause,
|
|
15945
|
+
server: registration.name
|
|
15946
|
+
}).pipe(Effect.as(Option.none()))));
|
|
15947
|
+
}).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp oauth token lookup failed", {
|
|
15948
|
+
cause,
|
|
15949
|
+
server: registration.name
|
|
15950
|
+
}).pipe(Effect.as(Option.none()))));
|
|
15951
|
+
return {
|
|
15952
|
+
statusFor,
|
|
15953
|
+
begin,
|
|
15954
|
+
handleCallback,
|
|
15955
|
+
disconnect,
|
|
15956
|
+
accessTokenFor
|
|
15957
|
+
};
|
|
15958
|
+
});
|
|
15959
|
+
const layer$58 = Layer.effect(McpOAuth, make$63);
|
|
15960
|
+
Layer.succeed(McpOAuth, {
|
|
15961
|
+
statusFor: () => Effect.succeed(Option.none()),
|
|
15962
|
+
begin: () => Effect.fail(new McpRegistryError({ detail: "OAuth sign-in is not available." })),
|
|
15963
|
+
handleCallback: () => Effect.succeed({
|
|
15964
|
+
ok: false,
|
|
15965
|
+
detail: "OAuth sign-in is not available."
|
|
15966
|
+
}),
|
|
15967
|
+
disconnect: () => Effect.void,
|
|
15968
|
+
accessTokenFor: () => Effect.succeed(Option.none())
|
|
15969
|
+
});
|
|
15412
15970
|
/** Extension for a registration file, so the sync's asset name is `<server>.json`. */
|
|
15413
15971
|
const MCP_REGISTRATION_SUFFIX = ".json";
|
|
15414
15972
|
const RegistrationFromJson$1 = Schema$1.fromJsonString(McpServerRegistration);
|
|
@@ -15419,6 +15977,7 @@ const slotsOf = (registration) => registration.secrets ?? [];
|
|
|
15419
15977
|
const make$62 = Effect.gen(function* () {
|
|
15420
15978
|
const config = yield* ServerConfig$1;
|
|
15421
15979
|
const secrets = yield* ServerSecretStore;
|
|
15980
|
+
const oauth = yield* McpOAuth;
|
|
15422
15981
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
15423
15982
|
const path = yield* Path.Path;
|
|
15424
15983
|
const services = yield* Effect.context();
|
|
@@ -15461,10 +16020,13 @@ const make$62 = Effect.gen(function* () {
|
|
|
15461
16020
|
const value = yield* readSecret(registration.name, slot);
|
|
15462
16021
|
if (Option.isNone(value)) missingSecrets.push(slot);
|
|
15463
16022
|
}
|
|
16023
|
+
const oauthStatus = registration.transport === "stdio" || !registration.enabled ? Option.none() : yield* oauth.statusFor(registration);
|
|
16024
|
+
const needsSignIn = Option.isSome(oauthStatus) && !oauthStatus.value.connected;
|
|
15464
16025
|
statuses.push({
|
|
15465
16026
|
registration,
|
|
15466
16027
|
missingSecrets,
|
|
15467
|
-
ready: registration.enabled && missingSecrets.length === 0
|
|
16028
|
+
ready: registration.enabled && missingSecrets.length === 0 && !needsSignIn,
|
|
16029
|
+
...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {}
|
|
15468
16030
|
});
|
|
15469
16031
|
}
|
|
15470
16032
|
return statuses;
|
|
@@ -15484,6 +16046,7 @@ const make$62 = Effect.gen(function* () {
|
|
|
15484
16046
|
target: slot.target,
|
|
15485
16047
|
key: slot.key
|
|
15486
16048
|
})).pipe(Effect.ignore);
|
|
16049
|
+
yield* secrets.remove(mcpOAuthStorageName(name)).pipe(Effect.ignore);
|
|
15487
16050
|
}).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry remove failed", { cause }).pipe(Effect.asVoid)));
|
|
15488
16051
|
const setSecret = ({ name, slot, value }) => secrets.set(mcpSecretStorageName({
|
|
15489
16052
|
server: name,
|
|
@@ -15513,6 +16076,11 @@ const make$62 = Effect.gen(function* () {
|
|
|
15513
16076
|
else env[slot.key] = value.value;
|
|
15514
16077
|
}
|
|
15515
16078
|
if (!complete) continue;
|
|
16079
|
+
const hasExplicitAuthorization = Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
|
|
16080
|
+
if (registration.transport !== "stdio" && !hasExplicitAuthorization) {
|
|
16081
|
+
const token = yield* oauth.accessTokenFor(registration);
|
|
16082
|
+
if (Option.isSome(token)) headers["Authorization"] = `Bearer ${token.value}`;
|
|
16083
|
+
}
|
|
15516
16084
|
resolved[registration.name] = registration.transport === "stdio" ? {
|
|
15517
16085
|
type: "stdio",
|
|
15518
16086
|
command: registration.command,
|
|
@@ -17245,7 +17813,7 @@ const make$59 = Effect.gen(function* () {
|
|
|
17245
17813
|
const layer$54 = Layer.effect(AssetSync, make$59);
|
|
17246
17814
|
//#endregion
|
|
17247
17815
|
//#region src/cli/assets.ts
|
|
17248
|
-
const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$
|
|
17816
|
+
const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$59.pipe(Layer.provide(layer$66))), Layer.provideMerge(layer$66), Layer.provideMerge(FetchHttpClient.layer));
|
|
17249
17817
|
const runWithSync = (flags, run) => Effect.gen(function* () {
|
|
17250
17818
|
const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
|
|
17251
17819
|
return yield* Effect.gen(function* () {
|
|
@@ -17253,7 +17821,7 @@ const runWithSync = (flags, run) => Effect.gen(function* () {
|
|
|
17253
17821
|
sync: yield* AssetSync,
|
|
17254
17822
|
link: yield* HubLink
|
|
17255
17823
|
});
|
|
17256
|
-
}).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$
|
|
17824
|
+
}).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
|
|
17257
17825
|
});
|
|
17258
17826
|
const STATE_LABEL = {
|
|
17259
17827
|
synced: "synced",
|
|
@@ -23936,11 +24504,66 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
23936
24504
|
});
|
|
23937
24505
|
const OrchestrationProjectionSnapshotQueryLive = Layer.effect(ProjectionSnapshotQuery, makeProjectionSnapshotQuery);
|
|
23938
24506
|
//#endregion
|
|
24507
|
+
//#region src/orchestration/Services/ThreadEventStream.ts
|
|
24508
|
+
var ThreadEventStreamService = class extends Context.Service()("@p4code/cli/orchestration/Services/ThreadEventStream/ThreadEventStreamService") {};
|
|
24509
|
+
//#endregion
|
|
24510
|
+
//#region src/orchestration/Layers/ThreadEventStream.ts
|
|
24511
|
+
const makeThreadEventStream = Effect.gen(function* () {
|
|
24512
|
+
const engine = yield* OrchestrationEngineService;
|
|
24513
|
+
const isThreadEvent = (threadId) => (event) => event.aggregateKind === "thread" && event.aggregateId === threadId;
|
|
24514
|
+
const watch = (input) => Stream.unwrap(Effect.gen(function* () {
|
|
24515
|
+
const matchesThread = isThreadEvent(input.threadId);
|
|
24516
|
+
const liveBuffer = yield* Queue.unbounded();
|
|
24517
|
+
yield* Effect.forkScoped(engine.streamDomainEvents.pipe(Stream.filter(matchesThread), Stream.runForEach((event) => Queue.offer(liveBuffer, event))), { startImmediately: true });
|
|
24518
|
+
const afterSequence = input.afterSequence ?? 0;
|
|
24519
|
+
const headSequence = yield* engine.latestSequence;
|
|
24520
|
+
const replayGap = headSequence - afterSequence;
|
|
24521
|
+
const catchUp = replayGap > 0 ? engine.readEvents(afterSequence, replayGap).pipe(Stream.filter(matchesThread)) : Stream.empty;
|
|
24522
|
+
const caughtUp = Stream.make({
|
|
24523
|
+
kind: "caught-up",
|
|
24524
|
+
headSequence
|
|
24525
|
+
});
|
|
24526
|
+
const live = Stream.fromQueue(liveBuffer).pipe(Stream.filter((event) => event.sequence > headSequence));
|
|
24527
|
+
return Stream.concat(catchUp.pipe(Stream.map((event) => ({
|
|
24528
|
+
kind: "event",
|
|
24529
|
+
event
|
|
24530
|
+
}))), Stream.concat(caughtUp, live.pipe(Stream.map((event) => ({
|
|
24531
|
+
kind: "event",
|
|
24532
|
+
event
|
|
24533
|
+
})))));
|
|
24534
|
+
}));
|
|
24535
|
+
const read = (input) => Effect.gen(function* () {
|
|
24536
|
+
const matchesThread = isThreadEvent(input.threadId);
|
|
24537
|
+
const afterSequence = input.afterSequence ?? 0;
|
|
24538
|
+
const headSequence = yield* engine.latestSequence;
|
|
24539
|
+
const replayGap = headSequence - afterSequence;
|
|
24540
|
+
if (replayGap <= 0) return {
|
|
24541
|
+
events: [],
|
|
24542
|
+
headSequence,
|
|
24543
|
+
hasMore: false
|
|
24544
|
+
};
|
|
24545
|
+
const collected = yield* engine.readEvents(afterSequence, replayGap).pipe(Stream.filter(matchesThread), Stream.take(input.limit + 1), Stream.runCollect);
|
|
24546
|
+
const events = Array.from(collected);
|
|
24547
|
+
const hasMore = events.length > input.limit;
|
|
24548
|
+
return {
|
|
24549
|
+
events: hasMore ? events.slice(0, input.limit) : events,
|
|
24550
|
+
headSequence,
|
|
24551
|
+
hasMore
|
|
24552
|
+
};
|
|
24553
|
+
});
|
|
24554
|
+
return ThreadEventStreamService.of({
|
|
24555
|
+
watch,
|
|
24556
|
+
read
|
|
24557
|
+
});
|
|
24558
|
+
});
|
|
24559
|
+
const ThreadEventStreamLive = Layer.effect(ThreadEventStreamService, makeThreadEventStream);
|
|
24560
|
+
//#endregion
|
|
23939
24561
|
//#region src/orchestration/runtimeLayer.ts
|
|
23940
24562
|
const OrchestrationEventInfrastructureLayerLive = Layer.mergeAll(OrchestrationEventStoreLive, OrchestrationCommandReceiptRepositoryLive);
|
|
23941
24563
|
const OrchestrationProjectionPipelineLayerLive = OrchestrationProjectionPipelineLive.pipe(Layer.provide(OrchestrationEventStoreLive));
|
|
23942
24564
|
const OrchestrationInfrastructureLayerLive = Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
|
|
23943
|
-
const
|
|
24565
|
+
const OrchestrationEngineLayerLive = OrchestrationEngineLive.pipe(Layer.provide(OrchestrationInfrastructureLayerLive));
|
|
24566
|
+
const OrchestrationLayerLive = Layer.mergeAll(OrchestrationInfrastructureLayerLive, OrchestrationEngineLayerLive, ThreadEventStreamLive.pipe(Layer.provide(OrchestrationEngineLayerLive)));
|
|
23944
24567
|
//#endregion
|
|
23945
24568
|
//#region ../../packages/shared/src/keybindings.ts
|
|
23946
24569
|
const DEFAULT_KEYBINDINGS = [
|
|
@@ -27210,7 +27833,7 @@ const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
|
27210
27833
|
title: "New thread",
|
|
27211
27834
|
modelSelection: nextProjectDefaultModelSelection,
|
|
27212
27835
|
interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
|
|
27213
|
-
compressMode:
|
|
27836
|
+
compressMode: DEFAULT_COMPRESS_MODE,
|
|
27214
27837
|
runtimeMode: "full-access",
|
|
27215
27838
|
branch: null,
|
|
27216
27839
|
worktreePath: null,
|
|
@@ -27784,7 +28407,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
|
|
|
27784
28407
|
});
|
|
27785
28408
|
yield* Console.log(output);
|
|
27786
28409
|
}));
|
|
27787
|
-
const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$
|
|
28410
|
+
const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
|
|
27788
28411
|
return yield* Effect.gen(function* () {
|
|
27789
28412
|
const snapshot = yield* getOfflineSnapshot();
|
|
27790
28413
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
@@ -27795,7 +28418,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
|
|
|
27795
28418
|
});
|
|
27796
28419
|
yield* Console.log(output);
|
|
27797
28420
|
}).pipe(Effect.provide(offlineRuntimeLayer));
|
|
27798
|
-
}).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$43).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$
|
|
28421
|
+
}).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$43).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
|
|
27799
28422
|
});
|
|
27800
28423
|
const projectAddCommand = Command.make("add", {
|
|
27801
28424
|
...projectLocationFlags,
|
|
@@ -29115,6 +29738,40 @@ const otlpTracesProxyRouteLayer = HttpRouter.add("POST", OTLP_TRACES_PROXY_PATH,
|
|
|
29115
29738
|
EnvironmentInternalError: HttpServerRespondable.toResponse,
|
|
29116
29739
|
EnvironmentScopeRequiredError: HttpServerRespondable.toResponse
|
|
29117
29740
|
})));
|
|
29741
|
+
const escapeHtml = (input) => input.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
29742
|
+
const oauthResultPage = (input) => HttpServerResponse.text([
|
|
29743
|
+
"<!doctype html>",
|
|
29744
|
+
`<html><head><meta charset="utf-8"><title>${escapeHtml(input.title)}</title></head>`,
|
|
29745
|
+
"<body style=\"font-family: system-ui, sans-serif; max-width: 32rem; margin: 4rem auto;\">",
|
|
29746
|
+
`<h1 style="font-size: 1.25rem;">${escapeHtml(input.title)}</h1>`,
|
|
29747
|
+
`<p>${escapeHtml(input.detail)}</p>`,
|
|
29748
|
+
"</body></html>"
|
|
29749
|
+
].join(""), { contentType: "text/html; charset=utf-8" });
|
|
29750
|
+
/**
|
|
29751
|
+
* Where the browser lands after an MCP server sign-in.
|
|
29752
|
+
*
|
|
29753
|
+
* Deliberately unauthenticated: the redirect comes from an authorization
|
|
29754
|
+
* server that holds no p4code credential. The `state` value — minted by
|
|
29755
|
+
* `McpOAuth.begin`, single-use, expiring — is what ties the request to a flow
|
|
29756
|
+
* this server started; a request without a live one changes nothing.
|
|
29757
|
+
*/
|
|
29758
|
+
const mcpOAuthCallbackRouteLayer = HttpRouter.add("GET", OAUTH_CALLBACK_PATH, Effect.gen(function* () {
|
|
29759
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
29760
|
+
const url = new URL(request.url, "http://localhost.invalid");
|
|
29761
|
+
const outcome = yield* (yield* McpOAuth).handleCallback({
|
|
29762
|
+
state: url.searchParams.get("state") ?? void 0,
|
|
29763
|
+
code: url.searchParams.get("code") ?? void 0,
|
|
29764
|
+
error: url.searchParams.get("error") ?? void 0,
|
|
29765
|
+
errorDescription: url.searchParams.get("error_description") ?? void 0
|
|
29766
|
+
});
|
|
29767
|
+
return outcome.ok ? oauthResultPage({
|
|
29768
|
+
title: "Signed in",
|
|
29769
|
+
detail: `${outcome.server} is connected. You can close this tab and return to p4code.`
|
|
29770
|
+
}) : oauthResultPage({
|
|
29771
|
+
title: "Sign-in failed",
|
|
29772
|
+
detail: outcome.detail
|
|
29773
|
+
});
|
|
29774
|
+
}));
|
|
29118
29775
|
const assetRouteLayer = HttpRouter.add("GET", `${ASSET_ROUTE_PREFIX}/*`, Effect.gen(function* () {
|
|
29119
29776
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
29120
29777
|
const url = HttpServerRequest.toURL(request);
|
|
@@ -33254,6 +33911,12 @@ const toTaskStoreError = (operation) => (cause) => Effect.logWarning("task store
|
|
|
33254
33911
|
/**
|
|
33255
33912
|
* The `auto` rendering: here is the task, do it.
|
|
33256
33913
|
*
|
|
33914
|
+
* The prompt carries a reference to the task, not a copy of it. Inlining the
|
|
33915
|
+
* body flattened the row into plain text: labels, project and priority were
|
|
33916
|
+
* lost, and an edit made after the thread started was invisible to an agent
|
|
33917
|
+
* still reading its stale snapshot. The row stays the single source of truth
|
|
33918
|
+
* and the agent reads it live over MCP.
|
|
33919
|
+
*
|
|
33257
33920
|
* Two instructions carry their weight. The agent is told its thread is already
|
|
33258
33921
|
* linked to the task, because otherwise its first useful move is to guess which
|
|
33259
33922
|
* board row it is on. And it is told to leave `status` alone: the server moved
|
|
@@ -33262,18 +33925,16 @@ const toTaskStoreError = (operation) => (cause) => Effect.logWarning("task store
|
|
|
33262
33925
|
* the reason the board's columns still mean something.
|
|
33263
33926
|
*/
|
|
33264
33927
|
const buildAutoPrompt = (task) => {
|
|
33265
|
-
const
|
|
33266
|
-
return `
|
|
33928
|
+
const reference = task.readableId ?? task.taskId;
|
|
33929
|
+
return `Picking up board task \`${reference}\`: ${task.title}
|
|
33267
33930
|
|
|
33268
|
-
|
|
33931
|
+
Read the task first via \`task_current\` (or \`task_get\` with \`${reference}\`). Body, labels, project and priority live on the row, not in this message; the row may have changed since this thread started - the current row is the source of truth. Re-read it the same way whenever you need the fields again.
|
|
33269
33932
|
|
|
33270
|
-
|
|
33933
|
+
This thread is already linked to the task, status In progress. Do the work.
|
|
33271
33934
|
|
|
33272
|
-
|
|
33935
|
+
Record findings via \`task_update\` as you go - decisions made, constraints hit, things the task turned out to be wrong about. That is what makes the row worth reading afterwards. Leave \`status\` alone: moving work across the board is the user's call.
|
|
33273
33936
|
|
|
33274
|
-
|
|
33275
|
-
|
|
33276
|
-
Start by reading the code the task concerns. If it turns out to be specified too poorly to act on, say so and stop rather than guessing at what was meant.`;
|
|
33937
|
+
After reading the task, read the code it concerns. If it is specified too poorly to act on, say so and stop rather than guessing.`;
|
|
33277
33938
|
};
|
|
33278
33939
|
/**
|
|
33279
33940
|
* Render a task into the prompt that seeds its thread.
|
|
@@ -36228,6 +36889,24 @@ const requireTaskCapability = Effect.fn("mcp.requireTaskCapability")(function* (
|
|
|
36228
36889
|
});
|
|
36229
36890
|
return invocation;
|
|
36230
36891
|
});
|
|
36892
|
+
/**
|
|
36893
|
+
* The watch capability's guard is two checks, not one: the capability must be
|
|
36894
|
+
* present AND the requested thread must be in the explicit grant set. The two
|
|
36895
|
+
* failures are distinct errors so a watcher can tell "this session cannot
|
|
36896
|
+
* watch at all" apart from "not this thread".
|
|
36897
|
+
*/
|
|
36898
|
+
const requireWatchCapability = Effect.fn("mcp.requireWatchCapability")(function* (watchedThreadId) {
|
|
36899
|
+
const invocation = yield* McpInvocationContext;
|
|
36900
|
+
if (!invocation.capabilities.has("watch")) return yield* new WatchToolUnavailableError({
|
|
36901
|
+
capability: "watch",
|
|
36902
|
+
environmentId: invocation.environmentId,
|
|
36903
|
+
threadId: invocation.threadId,
|
|
36904
|
+
providerSessionId: invocation.providerSessionId,
|
|
36905
|
+
providerInstanceId: invocation.providerInstanceId
|
|
36906
|
+
});
|
|
36907
|
+
if (!invocation.watchThreadIds?.has(watchedThreadId)) return yield* new ThreadWatchNotPermittedError({ threadId: watchedThreadId });
|
|
36908
|
+
return invocation;
|
|
36909
|
+
});
|
|
36231
36910
|
/** Third of the trio, for the same reason the second exists. */
|
|
36232
36911
|
const requireThreadCapability = Effect.fn("mcp.requireThreadCapability")(function* () {
|
|
36233
36912
|
const invocation = yield* McpInvocationContext;
|
|
@@ -43279,6 +43958,8 @@ const RPC_REQUIRED_SCOPE = /* @__PURE__ */ new Map([
|
|
|
43279
43958
|
[WS_METHODS.mcpSave, AuthOrchestrationOperateScope],
|
|
43280
43959
|
[WS_METHODS.mcpRemove, AuthOrchestrationOperateScope],
|
|
43281
43960
|
[WS_METHODS.mcpSetSecret, AuthOrchestrationOperateScope],
|
|
43961
|
+
[WS_METHODS.mcpOAuthBegin, AuthOrchestrationOperateScope],
|
|
43962
|
+
[WS_METHODS.mcpOAuthDisconnect, AuthOrchestrationOperateScope],
|
|
43282
43963
|
[WS_METHODS.serverGetSettings, AuthOrchestrationReadScope],
|
|
43283
43964
|
[WS_METHODS.serverUpdateSettings, AuthOrchestrationOperateScope],
|
|
43284
43965
|
[WS_METHODS.serverDiscoverSourceControl, AuthOrchestrationReadScope],
|
|
@@ -43392,6 +44073,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
43392
44073
|
const hubLink = yield* HubLink;
|
|
43393
44074
|
const assetSync = yield* AssetSync;
|
|
43394
44075
|
const mcpRegistry = yield* McpRegistry;
|
|
44076
|
+
const mcpOAuth = yield* McpOAuth;
|
|
43395
44077
|
const skillRegistry = yield* SkillRegistry;
|
|
43396
44078
|
const startup = yield* ServerRuntimeStartup;
|
|
43397
44079
|
const workspaceEntries = yield* WorkspaceEntries;
|
|
@@ -43885,8 +44567,8 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
43885
44567
|
mode: "auto",
|
|
43886
44568
|
task: {
|
|
43887
44569
|
taskId,
|
|
43888
|
-
|
|
43889
|
-
|
|
44570
|
+
readableId: task.readableId,
|
|
44571
|
+
title: task.title
|
|
43890
44572
|
}
|
|
43891
44573
|
}),
|
|
43892
44574
|
attachments: []
|
|
@@ -43895,14 +44577,14 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
43895
44577
|
titleSeed: threadTitle,
|
|
43896
44578
|
runtimeMode: DEFAULT_RUNTIME_MODE$2,
|
|
43897
44579
|
interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
|
|
43898
|
-
compressMode:
|
|
44580
|
+
compressMode: DEFAULT_COMPRESS_MODE,
|
|
43899
44581
|
bootstrap: { createThread: {
|
|
43900
44582
|
projectId: plan.projectId,
|
|
43901
44583
|
title: threadTitle,
|
|
43902
44584
|
modelSelection,
|
|
43903
44585
|
runtimeMode: DEFAULT_RUNTIME_MODE$2,
|
|
43904
44586
|
interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
|
|
43905
|
-
compressMode:
|
|
44587
|
+
compressMode: DEFAULT_COMPRESS_MODE,
|
|
43906
44588
|
branch: null,
|
|
43907
44589
|
worktreePath: null,
|
|
43908
44590
|
createdAt
|
|
@@ -43993,6 +44675,13 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
43993
44675
|
slot,
|
|
43994
44676
|
value
|
|
43995
44677
|
}).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
|
|
44678
|
+
[WS_METHODS.mcpOAuthBegin]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthBegin, Effect.gen(function* () {
|
|
44679
|
+
const found = (yield* mcpRegistry.list).find((status) => status.registration.name === name);
|
|
44680
|
+
if (found === void 0) return yield* new McpRegistryError({ detail: `No server is named ${name}.` });
|
|
44681
|
+
if (found.registration.transport === "stdio") return yield* new McpRegistryError({ detail: "A stdio server is launched locally and has no sign-in." });
|
|
44682
|
+
return yield* mcpOAuth.begin(found.registration);
|
|
44683
|
+
}), { "rpc.aggregate": "mcp" }),
|
|
44684
|
+
[WS_METHODS.mcpOAuthDisconnect]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthDisconnect, mcpOAuth.disconnect(name).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
|
|
43996
44685
|
[WS_METHODS.serverGetSettings]: (_input) => observeRpcEffect$1(WS_METHODS.serverGetSettings, serverSettings.getSettings.pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
|
|
43997
44686
|
[WS_METHODS.serverUpdateSettings]: ({ patch }) => observeRpcEffect$1(WS_METHODS.serverUpdateSettings, serverSettings.updateSettings(patch).pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
|
|
43998
44687
|
[WS_METHODS.serverDiscoverSourceControl]: (_input) => observeRpcEffect$1(WS_METHODS.serverDiscoverSourceControl, sourceControlDiscovery.discover, { "rpc.aggregate": "server" }),
|
|
@@ -45186,16 +45875,20 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
|
|
|
45186
45875
|
const providerSessionId = yield* crypto.randomUUIDv4.pipe(Effect.orDie);
|
|
45187
45876
|
const rawToken = yield* crypto.randomBytes(32).pipe(Effect.map(tokenFromBytes), Effect.orDie);
|
|
45188
45877
|
const tokenHash = yield* hashToken(rawToken);
|
|
45878
|
+
const watchThreadIds = new Set((request.watchThreadIds ?? []).map((threadId) => ThreadId.make(threadId)));
|
|
45879
|
+
const capabilities = /* @__PURE__ */ new Set([
|
|
45880
|
+
"preview",
|
|
45881
|
+
"tasks",
|
|
45882
|
+
"threads"
|
|
45883
|
+
]);
|
|
45884
|
+
if (watchThreadIds.size > 0) capabilities.add("watch");
|
|
45189
45885
|
const scope = {
|
|
45190
45886
|
environmentId,
|
|
45191
45887
|
threadId: ThreadId.make(request.threadId),
|
|
45192
45888
|
providerSessionId,
|
|
45193
45889
|
providerInstanceId: ProviderInstanceId.make(request.providerInstanceId),
|
|
45194
|
-
capabilities
|
|
45195
|
-
|
|
45196
|
-
"tasks",
|
|
45197
|
-
"threads"
|
|
45198
|
-
]),
|
|
45890
|
+
capabilities,
|
|
45891
|
+
...watchThreadIds.size > 0 ? { watchThreadIds } : {},
|
|
45199
45892
|
issuedAt
|
|
45200
45893
|
};
|
|
45201
45894
|
yield* SynchronizedRef.update(state, ({ records }) => {
|
|
@@ -46486,7 +47179,7 @@ const makeOpenCodeRuntime = Effect.gen(function* () {
|
|
|
46486
47179
|
};
|
|
46487
47180
|
});
|
|
46488
47181
|
var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/opencodeRuntime") {};
|
|
46489
|
-
const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$
|
|
47182
|
+
const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$70));
|
|
46490
47183
|
//#endregion
|
|
46491
47184
|
//#region src/textGeneration/TextGenerationUtils.ts
|
|
46492
47185
|
const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
|
|
@@ -82309,7 +83002,7 @@ const invokeTargeted = (operation, input, timeoutMs) => {
|
|
|
82309
83002
|
const { tabId, ...operationInput } = input;
|
|
82310
83003
|
return invoke(operation, operationInput, timeoutMs, tabId);
|
|
82311
83004
|
};
|
|
82312
|
-
const handlers$
|
|
83005
|
+
const handlers$3 = {
|
|
82313
83006
|
preview_status: (input) => invokeTargeted("status", input ?? {}),
|
|
82314
83007
|
preview_open: (input) => invokeTargeted("open", normalizePreviewOpenInput(input)),
|
|
82315
83008
|
preview_navigate: (input) => invokeTargeted("navigate", input, input.timeoutMs),
|
|
@@ -82325,10 +83018,10 @@ const handlers$2 = {
|
|
|
82325
83018
|
preview_recording_start: (input) => invokeTargeted("recordingStart", input ?? {}),
|
|
82326
83019
|
preview_recording_stop: (input) => invokeTargeted("recordingStop", input ?? {})
|
|
82327
83020
|
};
|
|
82328
|
-
const { preview_snapshot, ...standardHandlers } = handlers$
|
|
83021
|
+
const { preview_snapshot, ...standardHandlers } = handlers$3;
|
|
82329
83022
|
const PreviewStandardToolkitHandlersLive = PreviewStandardToolkit.toLayer(standardHandlers);
|
|
82330
83023
|
const PreviewSnapshotToolkitHandlersLive = PreviewSnapshotToolkit.toLayer({ preview_snapshot });
|
|
82331
|
-
PreviewToolkit.toLayer(handlers$
|
|
83024
|
+
PreviewToolkit.toLayer(handlers$3);
|
|
82332
83025
|
//#endregion
|
|
82333
83026
|
//#region src/mcp/toolkits/tasks/tools.ts
|
|
82334
83027
|
const dependencies = [McpInvocationContext, TaskRepository];
|
|
@@ -82561,6 +83254,41 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
|
|
|
82561
83254
|
})
|
|
82562
83255
|
});
|
|
82563
83256
|
//#endregion
|
|
83257
|
+
//#region src/mcp/toolkits/watch/tools.ts
|
|
83258
|
+
/**
|
|
83259
|
+
* Cross-thread by design, which is exactly why it is the most guarded tool in
|
|
83260
|
+
* the registry: the handler admits only threads in the session's explicit
|
|
83261
|
+
* `watchThreadIds` grant, never the token's whole reach. The read is a cursor
|
|
83262
|
+
* poll because MCP tools are request/response; a watcher advances
|
|
83263
|
+
* `afterSequence` with each page and knows it is caught up when `hasMore` is
|
|
83264
|
+
* false and the last sequence equals `headSequence`.
|
|
83265
|
+
*/
|
|
83266
|
+
const ThreadWatchEventsTool = Tool.make("thread_watch_events", {
|
|
83267
|
+
description: "Read a watched thread's orchestration events after a sequence cursor. Returns an ordered page plus the head sequence; pass the last event's sequence back as afterSequence to poll forward. Only threads this session was explicitly granted are readable.",
|
|
83268
|
+
parameters: ThreadWatchEventsInput,
|
|
83269
|
+
success: ThreadWatchEventsResult,
|
|
83270
|
+
failure: ThreadWatchToolError,
|
|
83271
|
+
dependencies: [McpInvocationContext, ThreadEventStreamService]
|
|
83272
|
+
}).annotate(Tool.Title, "Read watched thread events").annotate(Tool.Readonly, true).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, true);
|
|
83273
|
+
const WatchToolkit = Toolkit.make(ThreadWatchEventsTool);
|
|
83274
|
+
const WatchToolkitHandlersLive = WatchToolkit.toLayer({ thread_watch_events: (input) => Effect.gen(function* () {
|
|
83275
|
+
yield* requireWatchCapability(input.threadId);
|
|
83276
|
+
const page = yield* (yield* ThreadEventStreamService).read({
|
|
83277
|
+
threadId: input.threadId,
|
|
83278
|
+
...input.afterSequence !== void 0 ? { afterSequence: input.afterSequence } : {},
|
|
83279
|
+
limit: input.limit ?? 50
|
|
83280
|
+
}).pipe(Effect.mapError((cause) => new ThreadWatchFailedError({
|
|
83281
|
+
threadId: input.threadId,
|
|
83282
|
+
detail: cause.message
|
|
83283
|
+
})));
|
|
83284
|
+
return {
|
|
83285
|
+
threadId: input.threadId,
|
|
83286
|
+
events: page.events,
|
|
83287
|
+
headSequence: page.headSequence,
|
|
83288
|
+
hasMore: page.hasMore
|
|
83289
|
+
};
|
|
83290
|
+
}) });
|
|
83291
|
+
//#endregion
|
|
82564
83292
|
//#region src/mcp/McpHttpServer.ts
|
|
82565
83293
|
const unauthorized = HttpServerResponse.jsonUnsafe({
|
|
82566
83294
|
error: "invalid_mcp_credential",
|
|
@@ -82665,12 +83393,13 @@ const PreviewSnapshotRegistrationLive = Layer.effectDiscard(registerPreviewSnaps
|
|
|
82665
83393
|
const PreviewToolkitRegistrationLive = Layer.mergeAll(PreviewStandardToolkitRegistrationLive, PreviewSnapshotRegistrationLive);
|
|
82666
83394
|
const TaskToolkitRegistrationLive = McpServer.toolkit(TaskToolkit).pipe(Layer.provide(TaskToolkitHandlersLive));
|
|
82667
83395
|
const ThreadToolkitRegistrationLive = McpServer.toolkit(ThreadToolkit).pipe(Layer.provide(ThreadToolkitHandlersLive));
|
|
83396
|
+
const WatchToolkitRegistrationLive = McpServer.toolkit(WatchToolkit).pipe(Layer.provide(WatchToolkitHandlersLive));
|
|
82668
83397
|
const McpTransportLive = McpServer.layerHttp({
|
|
82669
83398
|
name: "P4Code",
|
|
82670
83399
|
version,
|
|
82671
83400
|
path: "/mcp"
|
|
82672
83401
|
}).pipe(Layer.provide(McpAuthMiddlewareLive));
|
|
82673
|
-
const layer = Layer.mergeAll(PreviewToolkitRegistrationLive, TaskToolkitRegistrationLive, ThreadToolkitRegistrationLive).pipe(Layer.provideMerge(McpTransportLive));
|
|
83402
|
+
const layer = Layer.mergeAll(PreviewToolkitRegistrationLive, TaskToolkitRegistrationLive, ThreadToolkitRegistrationLive, WatchToolkitRegistrationLive).pipe(Layer.provideMerge(McpTransportLive));
|
|
82674
83403
|
//#endregion
|
|
82675
83404
|
//#region src/orchestration/Services/CheckpointReactor.ts
|
|
82676
83405
|
/**
|
|
@@ -85735,9 +86464,9 @@ const WorkspaceEntriesLayerLive = layer$25.pipe(Layer.provide(layer$43));
|
|
|
85735
86464
|
const WorkspaceFileSystemLayerLive = layer$24.pipe(Layer.provide(layer$43), Layer.provide(WorkspaceEntriesLayerLive));
|
|
85736
86465
|
const WorkspaceLayerLive = Layer.mergeAll(layer$43, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
|
|
85737
86466
|
const ProjectFaviconResolverLayerLive = layer$41.pipe(Layer.provide(layer$43), Layer.provide(layer$42));
|
|
85738
|
-
const AuthLayerLive = layer$
|
|
86467
|
+
const AuthLayerLive = layer$62.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$66));
|
|
85739
86468
|
const ProviderRuntimeLayerLive = ProviderSessionReaperLive.pipe(Layer.provideMerge(ProviderLayerLive), Layer.provideMerge(OrchestrationLayerLive));
|
|
85740
|
-
const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive)), Layer.provideMerge(PersistenceLayerLive), Layer.provideMerge(layer$51), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$
|
|
86469
|
+
const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive)), Layer.provideMerge(PersistenceLayerLive), Layer.provideMerge(layer$51), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$59.pipe(Layer.provide(layer$66))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$52), Layer.provideMerge(layer$45), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(Layer.mergeAll(layer$57, layer$31).pipe(Layer.provideMerge(layer$58))), Layer.provideMerge(layer$66)).pipe(Layer.provideMerge(layer$8), Layer.provideMerge(layer$7), Layer.provideMerge(layer$6), Layer.provideMerge(layer$48), Layer.provideMerge(layer$50), Layer.provideMerge(layer$49), Layer.provide(layer$70));
|
|
85741
86470
|
/**
|
|
85742
86471
|
* Hub asset sync.
|
|
85743
86472
|
*
|
|
@@ -85747,7 +86476,7 @@ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(Checkpo
|
|
|
85747
86476
|
*/
|
|
85748
86477
|
const AssetSyncLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56));
|
|
85749
86478
|
const RuntimeServicesLive = layer$44.pipe(Layer.provideMerge(AssetSyncLive), Layer.provideMerge(RuntimeDependenciesLive));
|
|
85750
|
-
const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$2))).pipe(Layer.provide(RoutedTaskRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$42), Layer.provide(layer$28), Layer.provide(layer$46), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
|
|
86479
|
+
const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, mcpOAuthCallbackRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$2))).pipe(Layer.provide(RoutedTaskRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$42), Layer.provide(layer$28), Layer.provide(layer$46), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
|
|
85751
86480
|
const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
85752
86481
|
const config = yield* ServerConfig$1;
|
|
85753
86482
|
yield* fixPath();
|
|
@@ -86157,7 +86886,7 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
|
|
|
86157
86886
|
]));
|
|
86158
86887
|
//#endregion
|
|
86159
86888
|
//#region src/bin.ts
|
|
86160
|
-
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$
|
|
86889
|
+
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$70, FetchHttpClient.layer);
|
|
86161
86890
|
/**
|
|
86162
86891
|
* Prints an update reminder before dispatching, at most once a day.
|
|
86163
86892
|
*
|