@cmmd-center/forge 0.13.3 → 0.13.4
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/{BunHttpServer-VI75aqJw.mjs → BunHttpServer-CDh4Vioe.mjs} +6 -6
- package/dist/{BunHttpServer-BhE7Szci.cjs → BunHttpServer-DKvSpNd1.cjs} +6 -6
- package/dist/{BunPTY-oVISucl_.mjs → BunPTY-DkAIzLIx.mjs} +3 -3
- package/dist/{BunPTY-86ttlTi6.cjs → BunPTY-uyreNRGp.cjs} +3 -3
- package/dist/{BunServices-D0JTDujL.mjs → BunServices-D6PAheqS.mjs} +3 -3
- package/dist/{BunServices-BwE9KexF.cjs → BunServices-DDh7Whyx.cjs} +3 -3
- package/dist/{Cache-p0X77SKw.mjs → Cache-BVilO50s.mjs} +3 -3
- package/dist/{Cache-CWlxNDbC.cjs → Cache-DCF22Dfk.cjs} +3 -3
- package/dist/{Config-AqUR_lhX.mjs → Config-Cdfpphpo.mjs} +2 -2
- package/dist/{Config-CkEzdD9L.cjs → Config-CwKCCk14.cjs} +2 -2
- package/dist/{HttpServer-DNGCTTdk.mjs → HttpServer-ClsGgAq1.mjs} +3 -3
- package/dist/{HttpServer-DGoLR-kU.cjs → HttpServer-D1gSU7NX.cjs} +3 -3
- package/dist/{NodeHttpServer-Dw7ivXfX.mjs → NodeHttpServer-DT0TF8s4.mjs} +7 -7
- package/dist/{NodeHttpServer-BPjxt_DT.cjs → NodeHttpServer-Dfc7nSMq.cjs} +7 -7
- package/dist/{NodePTY-Cps0jsDA.cjs → NodePTY-S4tPEwZc.cjs} +4 -4
- package/dist/{NodePTY-CVH2yNYl.mjs → NodePTY-loxi8Vku.mjs} +4 -4
- package/dist/{NodeServices-CBNXOYLG.mjs → NodeServices-BahzLhbo.mjs} +3 -3
- package/dist/{NodeServices-Cw6SxEbl.cjs → NodeServices-Cb0rXFb2.cjs} +3 -3
- package/dist/{NodeServices-Ddr-tYRu.cjs → NodeServices-DE8jhdcU.cjs} +1 -1
- package/dist/{NodeSqliteClient-DGInbxQ3.mjs → NodeSqliteClient-DqFjB3u_.mjs} +6 -6
- package/dist/{NodeSqliteClient-CmxPzcBf.cjs → NodeSqliteClient-qjBWAOGq.cjs} +6 -6
- package/dist/{NodeTerminal-BEGtoMSS.mjs → NodeTerminal-BPw7bktz.mjs} +3 -3
- package/dist/{NodeTerminal-5iWbO0B2.cjs → NodeTerminal-rYbifme7.cjs} +3 -3
- package/dist/{PTY-BxYDiW3h.cjs → PTY-B4ZctbwQ.cjs} +2 -2
- package/dist/{PTY-rIPf52QR.mjs → PTY-BzdbZ0Ym.mjs} +2 -2
- package/dist/{Path-C6Zb2WHp.mjs → Path-C851t6sC.mjs} +2 -2
- package/dist/{Path-Be7zSwar.cjs → Path-CGCc_dDx.cjs} +2 -2
- package/dist/{Schema-dLi7Qssy.cjs → Schema-CDCJ3xZo.cjs} +7 -1
- package/dist/{Schema-CJyk7ah1.mjs → Schema-DOBWF8gQ.mjs} +2 -2
- package/dist/{SqlError-cyJT2IRY.mjs → SqlError-3aqibZrj.mjs} +3 -3
- package/dist/{SqlError-Bt0Bcd5C.cjs → SqlError-CzB6p9lL.cjs} +3 -3
- package/dist/{SqliteClient-B08FzZM4.cjs → SqliteClient-Cq1peWN1.cjs} +5 -5
- package/dist/{SqliteClient-CIsITMoQ.mjs → SqliteClient-DTWCGkrj.mjs} +5 -5
- package/dist/bin.cjs +1086 -110
- package/dist/bin.mjs +1109 -136
- package/dist/client/assets/{CanvasPanel-BrVen-8G.js → CanvasPanel-DkUmuXgO.js} +3 -3
- package/dist/client/assets/CompositeItem-DG5YBMcI.js +2 -0
- package/dist/client/assets/{DiffPanel-B_HjSs6Q.js → DiffPanel-DLCCD1ht.js} +3 -3
- package/dist/client/assets/DiffPanel.logic-dIDfHUQm.js +21 -0
- package/dist/client/assets/DiffPanelShell-Ba6NA1s7.js +2531 -0
- package/dist/client/assets/{DiffWorkerPoolProvider-CwUTD5yv.js → DiffWorkerPoolProvider-Bqy6DzWP.js} +52 -52
- package/dist/client/assets/PullRequestCodePanel-8SJWZPM5.js +5 -0
- package/dist/client/assets/canvasStateStore-BWZ8xdXr.js +2 -0
- package/dist/client/assets/{cmmdAuthRedirect-sqR8W6vY.js → cmmdAuthRedirect--srSJjFS.js} +2 -2
- package/dist/client/assets/diffTargetResolution-DA0SlQE0.js +2 -0
- package/dist/client/assets/index-C9Upewz-.js +151 -0
- package/dist/client/assets/index-DlyGyVH6.css +1 -0
- package/dist/client/assets/src-DwOYg6gv.js +3 -0
- package/dist/client/assets/toggle-Ozy-3fZ2.js +2 -0
- package/dist/client/assets/useTriggerFocusGuards-FzV_CNjl.js +2 -0
- package/dist/client/index.html +11 -11
- package/dist/forge-build.json +1 -1
- package/dist/{open-FIgTDosf.mjs → open-D8mGyWmt.mjs} +3 -3
- package/package.json +1 -1
- package/dist/client/assets/CompositeItem-BNZfMUvm.js +0 -2
- package/dist/client/assets/DiffPanel.logic-_zUBJ9_7.js +0 -21
- package/dist/client/assets/DiffPanelShell-DmjIQbsj.js +0 -2531
- package/dist/client/assets/PullRequestCodePanel-CAaS8yoZ.js +0 -5
- package/dist/client/assets/canvasStateStore-DN5mPB5B.js +0 -2
- package/dist/client/assets/diffTargetResolution-IthQ5nAw.js +0 -2
- package/dist/client/assets/index-CgwIqrjs.js +0 -151
- package/dist/client/assets/index-Dk7T0zVg.css +0 -1
- package/dist/client/assets/src-CFqnisEM.js +0 -3
- package/dist/client/assets/toggle-CLUqZXdO.js +0 -2
- package/dist/client/assets/useTriggerFocusGuards-CaUimC-O.js +0 -2
package/dist/bin.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-C5ckVeoz.mjs";
|
|
4
|
-
import { $ as encodeEffect, $a as make$39, $c as
|
|
5
|
-
import { $ as toAsyncIterable, A as make$45, At as make$44, Bt as publish, C as fromEffect, Ct as make$43, E as fromQueue, Et as end, F as merge$4, Ft as shutdown$1, G as runFold, H as run$2, Ht as subscribe$1, It as sliding, Jt as getCurrent, K as runForEach, Kt as makeUnsafe$7, Lt as take$1, M as mapAccum, Mt as offerAll, N as mapEffect$1, Nt as offerUnsafe, O as fromSubscription, Ot as failCause$4, Q as tick, R as onExit$1, Rt as takeAll, S as fromChannel, T as fromPubSub, Tt as bounded, U as runCollect, Ut as unbounded$1, V as provideContext$1, Vt as shutdown$2, W as runDrain, Y as succeed$4, Yt as interrupt$4, Z as takeWhile, Zt as runIn, _t as mapInput, at as make$46, b as flatMap$3, bt as fromTransform, c as callback$1, d as debounce$1, f as decodeText$1, g as ensuring$1, h as encodeText, it as get$4, j as map$7, jt as offer$1, k as isStream, l as catchCause$1, m as empty$5, mt as forEach$1, ot as get$5, pt as drain, q as runForEachArray, qt as await_, r as FileSystem, rt as unwrap$1, st as make$47, t as Path$2, u as concat$2, v as failCause$5, w as fromIterable$1, wt as makeUnsafe$6, x as fromAsyncIterable, y as filter$2, yt as fromSubscriptionArray, zt as unbounded$2 } from "./Path-
|
|
6
|
-
import { _ as ChildProcessSpawner, a as Stdio, g as make$48, o as make$49, r as isQuitError } from "./NodeTerminal-
|
|
7
|
-
import { n as layer$7 } from "./NodeServices-
|
|
8
|
-
import { $ as file, A as SocketErrorReason, At as merge$5, Bt as set$3, Ct as HttpClientErrorSchema, Dt as empty$7, Ft as getAndSet, G as TracerPropagationEnabled, Ht as updateAndGet, I as HttpServerError, It as getUnsafe$2, J as transformResponse, K as filterStatusOk$1, Lt as make$50, Ot as fromInput$1, Pt as get$6, Q as empty$6, Rt as makeUnsafe$8, St as setBody, Tt as jsonUnsafe$1, U as layer$8, Vt as update$4, W as HttpClient, Z as symbol$1, _ as schemaBodyUrlParams, _t as acceptJson, a as withLogAddress, at as setCookie, bt as get$7, ct as stream, d as logger$1, dt as filterStatusOk, et as isHttpServerResponse, f as withLoggerDisabled, ft as matchStatus, g as schemaBodyJson, gt as schemaBodyJson$1, i as serve$1, it as schemaJson, kt as fromRecordUnsafe, lt as text$2, m as ParsedSearchParams, nt as raw, ot as setCookies, p as HttpServerRequest, q as retryTransient, rt as redirect, st as setHeader, t as HttpServer, tt as jsonUnsafe, u as cors, ut as uint8Array, v as schemaHeaders, vt as bearerToken, wt as isHttpClientError, xt as post, y as toURL, yt as bodyJson, z as RouteNotFound, zt as modify$3 } from "./HttpServer-
|
|
9
|
-
import { _ as withDefault$3, a as all$1, c as logLevel, d as option$1, f as port, g as url$2, i as TrueValues, l as map$8, m as string$7, n as FalseValues, o as boolean$5, p as schema$2, r as Record$1, s as int$2, t as Boolean$2, u as number$2 } from "./Config-
|
|
10
|
-
import { a as make$51, i as keys, n as getOption, o as makeWith$1, r as invalidate, s as set$4, t as get$8 } from "./Cache-
|
|
11
|
-
import { S as layer$9, _ as defaultEscape, a as DeadlockError, b as makeCompiler$1, c as SqlError, d as UnknownError, g as custom, h as make$52, i as ConstraintError, l as SqlSyntaxError, m as SqlClient, n as AuthorizationError, o as LockTimeoutError, r as ConnectionError, s as SerializationError, t as AuthenticationError, u as StatementTimeoutError, v as defaultTransforms, y as fragment } from "./SqlError-
|
|
4
|
+
import { $ as encodeEffect, $a as make$39, $c as fromNullishOr, $i as spaced, $l as constTrue, $n as filterMapOrFail, $r as runPromise, $s as millis, $t as stringifyJson, Aa as Scope$1, Ai as void_$1, Al as format, An as cached$3, Ar as match$1, As as uninterruptibleMask, At as withConstructorDefault, Ba as CurrentLogSpans, Bc as add$2, Bi as counter, Bl as compose$1, Bn as catch_, Bo as addFinalizer, Br as orDie, Bs as make$42, Bt as head, C as Record, Ca as mergeAll, Ci as tx$1, Cn as andThen, Co as hasDies, Cr as logInfo, Cs as sleep$3, Ct as optionalKey, D as TaggedStruct, Da as succeedContext, Di as uninterruptibleMask$1, Dn as as$3, Do as interruptors, Ds as suspend, Dt as toCodecStringTree, E as TaggedErrorClass, Ea as succeed$2, Ei as uninterruptible, En as annotateSpans, Eo as interrupt$2, Er as map$3, Et as toCodecJson, F as UndefinedOr, Fa as forkUnsafe, Fc as isSuccess$1, Fi as withParentSpan, Fn as catchFilter, Fr as onError$1, Fs as MinimumTraceLevel, G as decodeExit, Ga as done, Gc as getUnsafe$1, Gi as withAttributes, Gl as isNullish, Gn as die$1, Gr as provideService, Gs as format$1, Gt as Transformation, H as declare, Hc as get$3, Hi as snapshotUnsafe, Hl as isNotNull, Hn as contextWith, Ho as as$2, Hr as promise, Ht as size$2, I as Union, Ia as make$37, Ii as withSpan, In as catchIf, Io as ConsoleRef, Ir as onExit, Is as NativeSpan, It as assign, J as decodeUnknownEffect, Ja as failCause$3, Jc as merge$2, Ji as exponential, Jn as exit, Jr as repeat, Js as hours, Jt as transformOrFail, K as decodeSync, Kc as make$35, Ki as addDelay, Kl as isObject$1, Ko as consolePretty$1, Kr as race, Ks as fromInput, L as Unknown, La as makeUnsafe$4, Lc as succeed$1, Li as withTracerEnabled, Ln as catchReason, Lo as CurrentLoggers$1, Ls as ParentSpan, Lt as append$1, M as URLFromString, Ma as addFinalizerExit, Mi as whileLoop, Mn as callback, Mo as pretty, Ms as void_$2, Na as close, Ni as withFiber$1, Nn as catchCause, No as prettyErrors, Nr as matchEffect, O as TemplateLiteral, Oa as sync$2, Ol as NodeInspectSymbol, On as asSome, Or as mapError, Os as sync, Ot as toJsonSchemaDocument, P as Undefined, Pa as closeUnsafe, Pc as isFailure$1, Pl as equals, Pn as catchDefect, Po as squash, Pr as never$1, Q as encode$4, Qc as flatten$1, Qi as recurs, Qn as filter$1, Qr as runForkWith, Qs as max, R as UnknownFromJsonString$1, Ra as provide$2, Rc as Reference$1, Ri as yieldNow, Rn as catchTag, Rr as onInterrupt, Rs as Tracer, Rt as drop$1, S as Option, Sa as merge$3, Sc as sort, Si as try_, Sn as all, Sr as logFatal, Ss as scopeAddFinalizerExit, St as optional$4, T as Struct, Ta as provideMerge, Ti as undefined_, Tl as withFiber, Tn as annotateLogs, To as hasInterruptsOnly, Tr as makeSpanScoped, Tt as tag, Ua as TracerTimingEnabled, Ui as timer, Ul as isNotNullish, Un as currentSpan, Ur as provide, Ut as toArray, V as brand, Va as MinimumLogLevel, Vc as empty$1, Vi as gauge, Vl as hasProperty, Vn as context, Vo as andThen$1, Vr as orElseSucceed, Vt as isEmpty$2, W as decodeEffect, Wa as _await, Wi as update$3, Wl as isNotUndefined, Wr as provideContext, Ws as days, X as decodeUnknownOption, Xc as firstSomeOf, Xl as cast, Xn as failCause$1, Xr as retry, Xt as onSome, Y as decodeUnknownExit, Yi as forever$2, Yn as fail, Yr as result, Z as decodeUnknownSync, Za as isDeferred, Zc as flatMap$2, Zi as passthrough$1, Zl as compose, Zr as runFork, Zt as parseJson$1, _ as NonEmptyArray, _a as effectContext, _i as tapErrorTag, _l as YieldableProto, _n as toUtc, _t as isSchemaError, a as DateTimeUtc, aa as Random$1, ac as toSeconds, al as isSome, an as value, ao as interrupt$3, ar as fnUntraced, at as isBetween, au as identity, b as NullOr, bi as timeoutOrElse, bn as acquireUseRelease, br as logDebug, bs as reportCauseUnsafe, bt as makeFilter, c as Defect, ca as Clock, cc as empty$3, ci as sleep$4, cl as none$4, cn as add$3, co as match$2, cr as forkChild, cs as flatMap$1, ct as isGreaterThanOrEqualTo, d as Exit, dc as flatMapNullishOr, di as succeedSome, dl as make$41, dn as isGreaterThanOrEqualTo$1, dr as forkScoped, ds as forkDetach, dt as isMaxLength, ea as catchDone, ec as min, el as fromUndefinedOr, er as filterOrFail, et as encodeSync, eu as constUndefined, fa as TaggedError, fc as fromIterable, fi as suspend$1, fn as make$38, fr as gen, ft as isMaxProperties, g as Never, ga as effect, gi as tapError, gl as PipeInspectableProto, gn as toEpochMillis, gr as interruptible, gt as isSchema, h as Literals, ha as buildWithMemoMap, hc as isReadonlyArrayNonEmpty, hi as tapCause, hn as toDate, hr as interrupt$1, ht as isPattern, i as Class, ic as toMillis, ii as scoped, il as isNone, in as make$40, io as failCause$2, ir as fn$1, it as is$1, ja as addFinalizer$1, jc as fail$1, jn as cachedWithTTL, jo as map$6, jr as matchCauseEffect, jt as withDecodingDefault, k as Trim, ka as unwrap, ki as useSpan, kl as toJson, kn as asVoid, ks as tracerLogger$1, kt as toType, l as Duration, la as currentTimeMillis, lc as ensure, li as succeed, ll as some, ln as distance, lr as forkDetach$1, ls as fnUntraced$1, lt as isInt, m as Literal, ma as build, mc as isArrayNonEmpty, mi as tap, mn as now, mo as StackTrace, mr as ignoreCause, ms as loggerMake, mt as isNonEmpty, n as ArraySchema, nc as seconds, nl as getOrNull, no as die$2, nt as encodeUnknownExit, nu as constant, o as DateTimeUtcFromString, oa as clamp, oc as zero, oi as service, ol as map$5, oo as isFailure, or as forEach, ot as isFinite$1, ou as pipe$1, p as Int$1, pa as CurrentMemoMap, pi as sync$1, pn as makeUnsafe$5, po as NoSuchElementError, pr as ignore, pt as isMinLength, q as decodeTo, qa as fail$3, qc as makeUnsafe$3, qi as both, ql as isTagged, qn as ensuring, qr as raceFirst, qs as fromInputUnsafe, r as Boolean$1, ra as isDoneCause, rc as times, ri as scope$1, rl as getOrUndefined, rn as makeFormatterDefault, ro as fail$2, rr as flatten$2, rt as fromJsonString, ru as dual, sa as parse$6, sc as allocate, si as serviceOption, sl as match, sn as encodeBase64Url$2, so as isSuccess, sr as forever$1, st as isGreaterThan, su as pipeArguments, t as Any, tc as minutes, ti as runPromiseWith, tl as getOrElse, tn as InvalidValue$1, to as succeed$3, tr as flatMap, ts as fiberInterrupt, tt as encodeUnknownEffect, tu as constVoid, u as ErrorClass, ua as Class$1, uc as filter, ui as succeedNone, ul as Number$2, un as formatIso, uo as void_$3, ur as forkIn, us as forever, ut as isLessThanOrEqualTo, v as NonEmptyString, va as effectDiscard, vi as timeout$1, vn as Transaction$1, vo as done$1, vr as isEffect, w as String$1, wa as provide$1, wi as txRetry, wl as isEffect$1, wn as annotateCurrentSpan, wo as hasInterrupts, wr as logWarning$1, wt as suspend$2, x as Number$1, xa as launch$1, xc as reverse, xi as tryPromise, xn as addFinalizer$2, xr as logError, xs as scope, xt as mutable, y as Null, ya as empty$4, yc as map$4, yi as timeoutOption, yn as acquireRelease, yo as fail$4, yr as log$4, yt as make$36, z as Void, za as CurrentLogAnnotations, zc as Service$1, zi as zipWith, zn as catchTags, zr as option, zs as externalSpan, zt as empty$2 } from "./Schema-DOBWF8gQ.mjs";
|
|
5
|
+
import { $ as toAsyncIterable, A as make$45, At as make$44, Bt as publish, C as fromEffect, Ct as make$43, E as fromQueue, Et as end, F as merge$4, Ft as shutdown$1, G as runFold, H as run$2, Ht as subscribe$1, It as sliding, Jt as getCurrent, K as runForEach, Kt as makeUnsafe$7, Lt as take$1, M as mapAccum, Mt as offerAll, N as mapEffect$1, Nt as offerUnsafe, O as fromSubscription, Ot as failCause$4, Q as tick, R as onExit$1, Rt as takeAll, S as fromChannel, T as fromPubSub, Tt as bounded, U as runCollect, Ut as unbounded$1, V as provideContext$1, Vt as shutdown$2, W as runDrain, Y as succeed$4, Yt as interrupt$4, Z as takeWhile, Zt as runIn, _t as mapInput, at as make$46, b as flatMap$3, bt as fromTransform, c as callback$1, d as debounce$1, f as decodeText$1, g as ensuring$1, h as encodeText, it as get$4, j as map$7, jt as offer$1, k as isStream, l as catchCause$1, m as empty$5, mt as forEach$1, ot as get$5, pt as drain, q as runForEachArray, qt as await_, r as FileSystem, rt as unwrap$1, st as make$47, t as Path$2, u as concat$2, v as failCause$5, w as fromIterable$1, wt as makeUnsafe$6, x as fromAsyncIterable, y as filter$2, yt as fromSubscriptionArray, zt as unbounded$2 } from "./Path-C851t6sC.mjs";
|
|
6
|
+
import { _ as ChildProcessSpawner, a as Stdio, g as make$48, o as make$49, r as isQuitError } from "./NodeTerminal-BPw7bktz.mjs";
|
|
7
|
+
import { n as layer$7 } from "./NodeServices-BahzLhbo.mjs";
|
|
8
|
+
import { $ as file, A as SocketErrorReason, At as merge$5, Bt as set$3, Ct as HttpClientErrorSchema, Dt as empty$7, Ft as getAndSet, G as TracerPropagationEnabled, Ht as updateAndGet, I as HttpServerError, It as getUnsafe$2, J as transformResponse, K as filterStatusOk$1, Lt as make$50, Ot as fromInput$1, Pt as get$6, Q as empty$6, Rt as makeUnsafe$8, St as setBody, Tt as jsonUnsafe$1, U as layer$8, Vt as update$4, W as HttpClient, Z as symbol$1, _ as schemaBodyUrlParams, _t as acceptJson, a as withLogAddress, at as setCookie, bt as get$7, ct as stream, d as logger$1, dt as filterStatusOk, et as isHttpServerResponse, f as withLoggerDisabled, ft as matchStatus, g as schemaBodyJson, gt as schemaBodyJson$1, i as serve$1, it as schemaJson, kt as fromRecordUnsafe, lt as text$2, m as ParsedSearchParams, nt as raw, ot as setCookies, p as HttpServerRequest, q as retryTransient, rt as redirect, st as setHeader, t as HttpServer, tt as jsonUnsafe, u as cors, ut as uint8Array, v as schemaHeaders, vt as bearerToken, wt as isHttpClientError, xt as post, y as toURL, yt as bodyJson, z as RouteNotFound, zt as modify$3 } from "./HttpServer-ClsGgAq1.mjs";
|
|
9
|
+
import { _ as withDefault$3, a as all$1, c as logLevel, d as option$1, f as port, g as url$2, i as TrueValues, l as map$8, m as string$7, n as FalseValues, o as boolean$5, p as schema$2, r as Record$1, s as int$2, t as Boolean$2, u as number$2 } from "./Config-Cdfpphpo.mjs";
|
|
10
|
+
import { a as make$51, i as keys, n as getOption, o as makeWith$1, r as invalidate, s as set$4, t as get$8 } from "./Cache-BVilO50s.mjs";
|
|
11
|
+
import { S as layer$9, _ as defaultEscape, a as DeadlockError, b as makeCompiler$1, c as SqlError, d as UnknownError, g as custom, h as make$52, i as ConstraintError, l as SqlSyntaxError, m as SqlClient, n as AuthorizationError, o as LockTimeoutError, r as ConnectionError, s as SerializationError, t as AuthenticationError, u as StatementTimeoutError, v as defaultTransforms, y as fragment } from "./SqlError-3aqibZrj.mjs";
|
|
12
12
|
import { r as wrapper_default, t as Mime_default } from "./Mime-Dq9IoNiV.mjs";
|
|
13
13
|
import { a as diag, c as SpanKind$1, d as TraceFlags, f as ROOT_CONTEXT, i as propagation, l as isSpanContextValid, m as DiagLogLevel, n as init_esm$1, o as context$1, p as createContextKey, r as trace, s as SpanStatusCode, t as esm_exports$1 } from "./esm-wLIF-u3N.mjs";
|
|
14
14
|
import { a as verifyCmmdAuthRuntimeTicket, c as verifyCmmdRuntimeTicket, d as setRuntimeGrantToken, f as createReadOnceFileTokenAccessor, i as sendRuntimeControlHeartbeat, l as verifyCmmdRuntimeTicketRefreshProof, n as bootstrapRuntimeControlAuthorityFromNarrowGrant, o as verifyCmmdClaudeReadinessTicket, r as readRuntimeControlAuthority, s as verifyCmmdClaudeUsageTicket, t as bootstrapRuntimeControlAuthority, u as runtimeGrantToken } from "./runtimeControlAuthority-D_zKr_eI.mjs";
|
|
15
|
-
import { n as PtySpawnError, t as PtyAdapter } from "./PTY-
|
|
15
|
+
import { n as PtySpawnError, t as PtyAdapter } from "./PTY-BzdbZ0Ym.mjs";
|
|
16
16
|
import { createRequire } from "node:module";
|
|
17
17
|
import * as HE from "node:child_process";
|
|
18
18
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -22,7 +22,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
|
|
|
22
22
|
import * as FS$1 from "node:fs";
|
|
23
23
|
import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
24
24
|
import * as NodeOS from "node:os";
|
|
25
|
-
import
|
|
25
|
+
import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
26
26
|
import * as Path$1 from "node:path";
|
|
27
27
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
28
28
|
import { pathToFileURL } from "node:url";
|
|
@@ -16520,7 +16520,7 @@ function makeNetServiceShape(createServer = Net.createServer) {
|
|
|
16520
16520
|
}
|
|
16521
16521
|
//#endregion
|
|
16522
16522
|
//#region ../../packages/shared/src/releaseInfo.generated.ts
|
|
16523
|
-
const FORGE_RELEASE_VERSION = "0.13.
|
|
16523
|
+
const FORGE_RELEASE_VERSION = "0.13.4";
|
|
16524
16524
|
//#endregion
|
|
16525
16525
|
//#region ../../packages/shared/src/hostProcess.ts
|
|
16526
16526
|
/**
|
|
@@ -16644,6 +16644,70 @@ const CheckpointRef = makeEntityId("CheckpointRef");
|
|
|
16644
16644
|
*/
|
|
16645
16645
|
const ThreadEnvMode = Literals(["local", "worktree"]);
|
|
16646
16646
|
//#endregion
|
|
16647
|
+
//#region ../../packages/contracts/src/assets.ts
|
|
16648
|
+
/**
|
|
16649
|
+
* Addresses for the bytes a client cannot fetch by guessing.
|
|
16650
|
+
*
|
|
16651
|
+
* Forge already serves the bytes: attachments under `/attachments/*` and
|
|
16652
|
+
* project favicons at `GET /api/project-favicon?cwd=`. What it did not serve
|
|
16653
|
+
* was the question "what is the URL for this thing", which is the only way a
|
|
16654
|
+
* client that holds an attachment id or a workspace root can reach either.
|
|
16655
|
+
* The phone asks that question on the thread list for every project, so
|
|
16656
|
+
* until this existed the answer was an error the phone drew as a spinner.
|
|
16657
|
+
*
|
|
16658
|
+
* These schemas are the Forge side of `assets.*` in the vendored t3 contracts.
|
|
16659
|
+
* They must decode what that package encodes: same tags, same field names.
|
|
16660
|
+
*/
|
|
16661
|
+
const ASSET_PATH_MAX_LENGTH = 1024;
|
|
16662
|
+
const ASSET_ID_MAX_LENGTH = 256;
|
|
16663
|
+
const ASSET_URL_MAX_LENGTH = 4096;
|
|
16664
|
+
const AssetResource = Union([
|
|
16665
|
+
TaggedStruct("workspace-file", {
|
|
16666
|
+
threadId: ThreadId,
|
|
16667
|
+
path: TrimmedNonEmptyString.check(isMaxLength(ASSET_PATH_MAX_LENGTH))
|
|
16668
|
+
}),
|
|
16669
|
+
TaggedStruct("attachment", { attachmentId: TrimmedNonEmptyString.check(isMaxLength(ASSET_ID_MAX_LENGTH)) }),
|
|
16670
|
+
TaggedStruct("project-favicon", {
|
|
16671
|
+
cwd: TrimmedNonEmptyString.check(isMaxLength(ASSET_PATH_MAX_LENGTH)),
|
|
16672
|
+
path: optional$4(TrimmedNonEmptyString.check(isMaxLength(ASSET_PATH_MAX_LENGTH)))
|
|
16673
|
+
})
|
|
16674
|
+
]);
|
|
16675
|
+
const AssetCreateUrlInput = Struct({ resource: AssetResource });
|
|
16676
|
+
const AssetCreateUrlResult = Struct({
|
|
16677
|
+
relativeUrl: TrimmedNonEmptyString.check(isMaxLength(ASSET_URL_MAX_LENGTH)),
|
|
16678
|
+
expiresAt: Number$1,
|
|
16679
|
+
sourcePath: optional$4(TrimmedNonEmptyString.check(isMaxLength(ASSET_PATH_MAX_LENGTH)))
|
|
16680
|
+
});
|
|
16681
|
+
/**
|
|
16682
|
+
* The resource cannot be addressed by URL on this server.
|
|
16683
|
+
*
|
|
16684
|
+
* Tag and message match the vendored client's `AssetAccessError` union so the
|
|
16685
|
+
* phone decodes the failure rather than falling through to a generic transport
|
|
16686
|
+
* error. `workspace-file` is the case that lands here.
|
|
16687
|
+
*/
|
|
16688
|
+
var AssetWorkspaceResolutionError = class extends TaggedErrorClass()("AssetWorkspaceResolutionError", {
|
|
16689
|
+
resource: AssetResource,
|
|
16690
|
+
cause: optional$4(Defect)
|
|
16691
|
+
}) {
|
|
16692
|
+
get message() {
|
|
16693
|
+
return "Failed to resolve workspace.";
|
|
16694
|
+
}
|
|
16695
|
+
};
|
|
16696
|
+
/** The signing key that makes an asset URL self-authenticating could not be read. */
|
|
16697
|
+
var AssetSigningKeyLoadError = class extends TaggedErrorClass()("AssetSigningKeyLoadError", {
|
|
16698
|
+
resource: AssetResource,
|
|
16699
|
+
cause: optional$4(Defect)
|
|
16700
|
+
}) {
|
|
16701
|
+
get message() {
|
|
16702
|
+
return "Failed to load the asset signing key.";
|
|
16703
|
+
}
|
|
16704
|
+
};
|
|
16705
|
+
const AssetAccessError = Union([AssetWorkspaceResolutionError, AssetSigningKeyLoadError]);
|
|
16706
|
+
const AssetsRpcSchemas = { createUrl: {
|
|
16707
|
+
input: AssetCreateUrlInput,
|
|
16708
|
+
output: AssetCreateUrlResult
|
|
16709
|
+
} };
|
|
16710
|
+
//#endregion
|
|
16647
16711
|
//#region ../../node_modules/.bun/effect@4.0.0-beta.51/node_modules/effect/dist/unstable/rpc/RpcMiddleware.js
|
|
16648
16712
|
/**
|
|
16649
16713
|
* @since 4.0.0
|
|
@@ -18144,6 +18208,7 @@ const ExecutionEnvironmentCapabilities = Struct({
|
|
|
18144
18208
|
threadPullRequestLinking: optionalKey(Boolean$1),
|
|
18145
18209
|
cloudMode: Boolean$1.pipe(withDecodingDefault(succeed(false))),
|
|
18146
18210
|
threadSettlement: optionalKey(Boolean$1),
|
|
18211
|
+
threadTitleRegeneration: optionalKey(Boolean$1),
|
|
18147
18212
|
posthogPublicKey: NullOr(String$1).pipe(withDecodingDefault(succeed(null))),
|
|
18148
18213
|
posthogHost: NullOr(String$1).pipe(withDecodingDefault(succeed(null))),
|
|
18149
18214
|
runtime: optionalKey(ExecutionEnvironmentRuntimeCapabilities),
|
|
@@ -19141,6 +19206,51 @@ Struct({
|
|
|
19141
19206
|
headRepositoryNameWithOwner: optional$4(NullOr(TrimmedNonEmptyString)),
|
|
19142
19207
|
headRepositoryOwnerLogin: optional$4(NullOr(TrimmedNonEmptyString))
|
|
19143
19208
|
});
|
|
19209
|
+
const SourceControlCloneProtocol = Literals([
|
|
19210
|
+
"auto",
|
|
19211
|
+
"ssh",
|
|
19212
|
+
"https"
|
|
19213
|
+
]);
|
|
19214
|
+
const SourceControlRepositoryInfo = Struct({
|
|
19215
|
+
provider: SourceControlProviderKind$1,
|
|
19216
|
+
nameWithOwner: TrimmedNonEmptyString,
|
|
19217
|
+
url: TrimmedNonEmptyString,
|
|
19218
|
+
sshUrl: TrimmedNonEmptyString
|
|
19219
|
+
});
|
|
19220
|
+
const SourceControlRepositoryLookupInput = Struct({
|
|
19221
|
+
provider: SourceControlProviderKind$1,
|
|
19222
|
+
repository: TrimmedNonEmptyString,
|
|
19223
|
+
cwd: optional$4(TrimmedNonEmptyString)
|
|
19224
|
+
});
|
|
19225
|
+
/**
|
|
19226
|
+
* Either name the repository (`provider` + `repository`) or paste a clone URL
|
|
19227
|
+
* (`remoteUrl`). Both are optional in the schema because the phone sends one
|
|
19228
|
+
* or the other depending on how the user got here; the server rejects a call
|
|
19229
|
+
* that supplies neither, and rejects a `remoteUrl` it cannot resolve to a
|
|
19230
|
+
* repository it is allowed to fetch a token for.
|
|
19231
|
+
*/
|
|
19232
|
+
const SourceControlCloneRepositoryInput = Struct({
|
|
19233
|
+
provider: optional$4(SourceControlProviderKind$1),
|
|
19234
|
+
repository: optional$4(TrimmedNonEmptyString),
|
|
19235
|
+
remoteUrl: optional$4(TrimmedNonEmptyString),
|
|
19236
|
+
destinationPath: TrimmedNonEmptyString,
|
|
19237
|
+
protocol: optional$4(SourceControlCloneProtocol)
|
|
19238
|
+
});
|
|
19239
|
+
const SourceControlCloneRepositoryResult = Struct({
|
|
19240
|
+
cwd: TrimmedNonEmptyString,
|
|
19241
|
+
remoteUrl: TrimmedNonEmptyString,
|
|
19242
|
+
repository: NullOr(SourceControlRepositoryInfo)
|
|
19243
|
+
});
|
|
19244
|
+
var SourceControlRepositoryError = class extends TaggedErrorClass()("SourceControlRepositoryError", {
|
|
19245
|
+
provider: SourceControlProviderKind$1,
|
|
19246
|
+
operation: String$1,
|
|
19247
|
+
detail: String$1,
|
|
19248
|
+
cause: optional$4(Defect)
|
|
19249
|
+
}) {
|
|
19250
|
+
get message() {
|
|
19251
|
+
return `Source control repository operation ${this.operation} failed for ${this.provider}: ${this.detail}`;
|
|
19252
|
+
}
|
|
19253
|
+
};
|
|
19144
19254
|
//#endregion
|
|
19145
19255
|
//#region ../../packages/contracts/src/orchestration.ts
|
|
19146
19256
|
const ORCHESTRATION_WS_METHODS = {
|
|
@@ -19152,7 +19262,8 @@ const ORCHESTRATION_WS_METHODS = {
|
|
|
19152
19262
|
replayEvents: "orchestration.replayEvents",
|
|
19153
19263
|
getArchivedShellSnapshot: "orchestration.getArchivedShellSnapshot",
|
|
19154
19264
|
subscribeShell: "orchestration.subscribeShell",
|
|
19155
|
-
subscribeThread: "orchestration.subscribeThread"
|
|
19265
|
+
subscribeThread: "orchestration.subscribeThread",
|
|
19266
|
+
searchThreads: "orchestration.searchThreads"
|
|
19156
19267
|
};
|
|
19157
19268
|
const ProviderKind = Literals([
|
|
19158
19269
|
"codex",
|
|
@@ -20508,6 +20619,31 @@ const OrchestrationGetFullThreadDiffInput = Struct({
|
|
|
20508
20619
|
const OrchestrationGetFullThreadDiffResult = ThreadTurnDiff;
|
|
20509
20620
|
const OrchestrationReplayEventsInput = Struct({ fromSequenceExclusive: NonNegativeInt });
|
|
20510
20621
|
const OrchestrationReplayEventsResult = ArraySchema(OrchestrationEvent);
|
|
20622
|
+
/**
|
|
20623
|
+
* Which side of the conversation a search hit came from. `null`
|
|
20624
|
+
* `messageCreatedAt` on a match means it came from the thread's own metadata
|
|
20625
|
+
* (its title or its branch) rather than from a message.
|
|
20626
|
+
*/
|
|
20627
|
+
const OrchestrationThreadSearchSource = Literals(["user", "assistant"]);
|
|
20628
|
+
/**
|
|
20629
|
+
* The server's SQLite client is synchronous and single-connection, so both the
|
|
20630
|
+
* scan input and the response size are bounded: a search must not be able to
|
|
20631
|
+
* monopolize the connection every keystroke.
|
|
20632
|
+
*/
|
|
20633
|
+
const OrchestrationSearchThreadsInput = Struct({
|
|
20634
|
+
query: TrimmedString.check(isMinLength(2), isMaxLength(200)),
|
|
20635
|
+
limit: optionalKey(Int$1.check(isBetween({
|
|
20636
|
+
minimum: 1,
|
|
20637
|
+
maximum: 50
|
|
20638
|
+
})))
|
|
20639
|
+
});
|
|
20640
|
+
const OrchestrationSearchThreadsResult = Struct({ matches: ArraySchema(Struct({
|
|
20641
|
+
threadId: ThreadId,
|
|
20642
|
+
projectId: ProjectId,
|
|
20643
|
+
source: OrchestrationThreadSearchSource,
|
|
20644
|
+
snippet: String$1.check(isMaxLength(240)),
|
|
20645
|
+
messageCreatedAt: NullOr(IsoDateTime)
|
|
20646
|
+
})) });
|
|
20511
20647
|
const ProgressPercent = NonNegativeInt.check(isLessThanOrEqualTo(100));
|
|
20512
20648
|
const AgentProtocolMessage = Union([
|
|
20513
20649
|
Struct({
|
|
@@ -20578,6 +20714,10 @@ const OrchestrationRpcSchemas = {
|
|
|
20578
20714
|
getArchivedShellSnapshot: {
|
|
20579
20715
|
input: Struct({}),
|
|
20580
20716
|
output: OrchestrationShellSnapshot
|
|
20717
|
+
},
|
|
20718
|
+
searchThreads: {
|
|
20719
|
+
input: OrchestrationSearchThreadsInput,
|
|
20720
|
+
output: OrchestrationSearchThreadsResult
|
|
20581
20721
|
}
|
|
20582
20722
|
};
|
|
20583
20723
|
var OrchestrationGetSnapshotError = class extends TaggedErrorClass()("OrchestrationGetSnapshotError", {
|
|
@@ -20600,6 +20740,10 @@ var OrchestrationReplayEventsError = class extends TaggedErrorClass()("Orchestra
|
|
|
20600
20740
|
message: TrimmedNonEmptyString,
|
|
20601
20741
|
cause: optional$4(Defect)
|
|
20602
20742
|
}) {};
|
|
20743
|
+
var OrchestrationSearchThreadsError = class extends TaggedErrorClass()("OrchestrationSearchThreadsError", {
|
|
20744
|
+
message: TrimmedNonEmptyString,
|
|
20745
|
+
cause: optional$4(Defect)
|
|
20746
|
+
}) {};
|
|
20603
20747
|
Struct({
|
|
20604
20748
|
provider: ProviderKind,
|
|
20605
20749
|
status: Literals([
|
|
@@ -20659,6 +20803,31 @@ const ProviderRespondToUserInputInput = Struct({
|
|
|
20659
20803
|
requestId: ApprovalRequestId,
|
|
20660
20804
|
answers: ProviderUserInputAnswers
|
|
20661
20805
|
});
|
|
20806
|
+
/**
|
|
20807
|
+
* Sending a thread to the people who maintain Forge.
|
|
20808
|
+
*
|
|
20809
|
+
* The vendored client's `/feedback` slash command calls this. Upstream it
|
|
20810
|
+
* uploads the transcript to the model provider; Forge routes it to the same
|
|
20811
|
+
* CMMD feedback intake the web app's feedback dialog already posts to, so one
|
|
20812
|
+
* report lands in one place no matter which surface filed it.
|
|
20813
|
+
*
|
|
20814
|
+
* `reason` is what the person typed after the command, and is the only part
|
|
20815
|
+
* of the report they wrote. The server fills in the rest.
|
|
20816
|
+
*/
|
|
20817
|
+
const ProviderUploadFeedbackInput = Struct({
|
|
20818
|
+
threadId: ThreadId,
|
|
20819
|
+
reason: optional$4(TrimmedNonEmptyString.check(isMaxLength(4e3)))
|
|
20820
|
+
});
|
|
20821
|
+
const ProviderUploadFeedbackResult = Struct({ feedbackId: TrimmedNonEmptyString });
|
|
20822
|
+
var ProviderUploadFeedbackError = class extends TaggedErrorClass()("ProviderUploadFeedbackError", {
|
|
20823
|
+
threadId: ThreadId,
|
|
20824
|
+
reason: optional$4(TrimmedNonEmptyString.check(isMaxLength(500))),
|
|
20825
|
+
cause: optional$4(Defect)
|
|
20826
|
+
}) {
|
|
20827
|
+
get message() {
|
|
20828
|
+
return this.reason ?? "Feedback could not be sent. Please try again.";
|
|
20829
|
+
}
|
|
20830
|
+
};
|
|
20662
20831
|
Struct({
|
|
20663
20832
|
id: EventId,
|
|
20664
20833
|
kind: Literals([
|
|
@@ -21133,6 +21302,46 @@ const TaskStartedPayload = Struct({
|
|
|
21133
21302
|
description: optional$4(TrimmedNonEmptyStringSchema$2),
|
|
21134
21303
|
taskType: optional$4(TrimmedNonEmptyStringSchema$2)
|
|
21135
21304
|
});
|
|
21305
|
+
/**
|
|
21306
|
+
* Watch-loop task types: Monitor-tool tasks plus background shells. A shell
|
|
21307
|
+
* that outlives its turn is in practice a watch loop, not delegated work.
|
|
21308
|
+
*/
|
|
21309
|
+
const MONITOR_TASK_TYPES = new Set([
|
|
21310
|
+
"monitor",
|
|
21311
|
+
"monitor_mcp",
|
|
21312
|
+
"local_bash",
|
|
21313
|
+
"shell"
|
|
21314
|
+
]);
|
|
21315
|
+
/** Task types that are neither agents nor watch loops (plan-mode bookkeeping). */
|
|
21316
|
+
const INERT_TASK_TYPES = new Set(["plan", "dream"]);
|
|
21317
|
+
/**
|
|
21318
|
+
* Agent-vs-background classification for a task row.
|
|
21319
|
+
*
|
|
21320
|
+
* The mobile client reads `agentKind` off the persisted activity payload and
|
|
21321
|
+
* treats a row without it as background, so a server that never stamps the
|
|
21322
|
+
* field leaves the Agents roster permanently empty however much subagent work
|
|
21323
|
+
* is running (FOR-36646). This is the stamp.
|
|
21324
|
+
*
|
|
21325
|
+
* A denylist, not an allowlist, and deliberately so: the agent-flavoured type
|
|
21326
|
+
* names drift with the SDKs (subagent, local_agent, local_workflow, and
|
|
21327
|
+
* whatever lands next), and an allowlist drops real subagents the day a new
|
|
21328
|
+
* name appears. Only the watch loops and the plan-mode bookkeeping types are
|
|
21329
|
+
* named here; everything else is delegated work.
|
|
21330
|
+
*
|
|
21331
|
+
* A task launched from inside a subagent (`agentId` set) is agent-internal
|
|
21332
|
+
* background work unless it is itself agent-flavoured, because a nested agent
|
|
21333
|
+
* can outlive its parent and has to stay in the roster.
|
|
21334
|
+
*
|
|
21335
|
+
* This mirrors `classifyTaskAgentKind` in the contracts the phone speaks. The
|
|
21336
|
+
* two packages do not import each other, so the sets are duplicated on
|
|
21337
|
+
* purpose; they have to agree, and the tests on both sides pin the same cases.
|
|
21338
|
+
*/
|
|
21339
|
+
function classifyTaskAgentKind(input) {
|
|
21340
|
+
const { taskType, agentId } = input;
|
|
21341
|
+
const nonAgentType = taskType !== void 0 && (MONITOR_TASK_TYPES.has(taskType) || INERT_TASK_TYPES.has(taskType));
|
|
21342
|
+
if (agentId !== void 0 && agentId.trim().length > 0) return taskType === void 0 || nonAgentType ? "background" : "agent";
|
|
21343
|
+
return nonAgentType ? "background" : "agent";
|
|
21344
|
+
}
|
|
21136
21345
|
const TaskProgressPayload = Struct({
|
|
21137
21346
|
taskId: RuntimeTaskId,
|
|
21138
21347
|
description: TrimmedNonEmptyStringSchema$2,
|
|
@@ -25715,6 +25924,8 @@ const WS_METHODS = {
|
|
|
25715
25924
|
projectsListEntries: "projects.listEntries",
|
|
25716
25925
|
serverDiscoverSourceControl: "server.discoverSourceControl",
|
|
25717
25926
|
serverReportClientActivity: "server.reportClientActivity",
|
|
25927
|
+
sourceControlLookupRepository: "sourceControl.lookupRepository",
|
|
25928
|
+
sourceControlCloneRepository: "sourceControl.cloneRepository",
|
|
25718
25929
|
projectsWriteFile: "projects.writeFile",
|
|
25719
25930
|
projectCheckoutDeletionPreview: "projectCheckoutDeletion.preview",
|
|
25720
25931
|
projectCheckoutDeletionExecute: "projectCheckoutDeletion.execute",
|
|
@@ -25818,7 +26029,9 @@ const WS_METHODS = {
|
|
|
25818
26029
|
subscribeServerConfig: "subscribeServerConfig",
|
|
25819
26030
|
subscribeServerLifecycle: "subscribeServerLifecycle",
|
|
25820
26031
|
subscribeAuthAccess: "subscribeAuthAccess",
|
|
25821
|
-
subscribeWorkspaceReadiness: "subscribeWorkspaceReadiness"
|
|
26032
|
+
subscribeWorkspaceReadiness: "subscribeWorkspaceReadiness",
|
|
26033
|
+
assetsCreateUrl: "assets.createUrl",
|
|
26034
|
+
providerUploadFeedback: "provider.uploadFeedback"
|
|
25822
26035
|
};
|
|
25823
26036
|
const WsServerUpsertKeybindingRpc = make$30(WS_METHODS.serverUpsertKeybinding, {
|
|
25824
26037
|
payload: ServerUpsertKeybindingInput,
|
|
@@ -26347,6 +26560,29 @@ const WsOrchestrationGetArchivedShellSnapshotRpc = make$30(ORCHESTRATION_WS_METH
|
|
|
26347
26560
|
success: OrchestrationRpcSchemas.getArchivedShellSnapshot.output,
|
|
26348
26561
|
error: OrchestrationGetSnapshotError
|
|
26349
26562
|
});
|
|
26563
|
+
const WsOrchestrationSearchThreadsRpc = make$30(ORCHESTRATION_WS_METHODS.searchThreads, {
|
|
26564
|
+
payload: OrchestrationSearchThreadsInput,
|
|
26565
|
+
success: OrchestrationRpcSchemas.searchThreads.output,
|
|
26566
|
+
error: OrchestrationSearchThreadsError
|
|
26567
|
+
});
|
|
26568
|
+
/**
|
|
26569
|
+
* Resolve `owner/repo` to the repository the caller is allowed to clone.
|
|
26570
|
+
*
|
|
26571
|
+
* Both of these run against the same CMMD-brokered GitHub credential the web
|
|
26572
|
+
* add-project flow uses, so a lookup that answers is a lookup whose clone can
|
|
26573
|
+
* also be authorized, and a repository the caller cannot reach is a failure
|
|
26574
|
+
* here rather than a clone that dies half way.
|
|
26575
|
+
*/
|
|
26576
|
+
const WsSourceControlLookupRepositoryRpc = make$30(WS_METHODS.sourceControlLookupRepository, {
|
|
26577
|
+
payload: SourceControlRepositoryLookupInput,
|
|
26578
|
+
success: SourceControlRepositoryInfo,
|
|
26579
|
+
error: SourceControlRepositoryError
|
|
26580
|
+
});
|
|
26581
|
+
const WsSourceControlCloneRepositoryRpc = make$30(WS_METHODS.sourceControlCloneRepository, {
|
|
26582
|
+
payload: SourceControlCloneRepositoryInput,
|
|
26583
|
+
success: SourceControlCloneRepositoryResult,
|
|
26584
|
+
error: SourceControlRepositoryError
|
|
26585
|
+
});
|
|
26350
26586
|
const WsOrchestrationSubscribeShellRpc = make$30(ORCHESTRATION_WS_METHODS.subscribeShell, {
|
|
26351
26587
|
payload: OrchestrationRpcSchemas.subscribeShell.input,
|
|
26352
26588
|
success: OrchestrationRpcSchemas.subscribeShell.output,
|
|
@@ -26427,7 +26663,15 @@ const WsRpcGroup = make$29(WsServerGetConfigRpc, WsServerRefreshProvidersRpc, Ws
|
|
|
26427
26663
|
payload: UsageSummaryInput,
|
|
26428
26664
|
success: UsageSummary,
|
|
26429
26665
|
error: UsageReadError
|
|
26430
|
-
}), WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsThreadCommentsRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsProjectCheckoutDeletionPreviewRpc, WsProjectCheckoutDeletionExecuteRpc, WsCodeGraphSummaryRpc, WsCodeGraphNeighborhoodRpc, WsCodeGraphSearchRpc, WsWorkspaceReadFileRpc, WsWorkspaceBeginWriteFileRpc, WsWorkspaceWriteFileChunkRpc, WsWorkspaceCommitWriteFileRpc, WsWorkspaceCancelWriteFileRpc, WsShellOpenInEditorRpc, WsSubscribeGitStatusRpc, WsGitPullRpc, WsGitRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsGitListBranchesRpc, WsVcsListRefsRpc, WsVcsRefreshStatusRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsGitCreateWorktreeRpc, WsGitRemoveWorktreeRpc, WsGitCreateBranchRpc, WsGitCheckoutRpc, WsGitInitRpc, WsFilesystemBrowseRpc, WsProjectsReadFileRpc, WsReviewGetDiffPreviewRpc, WsCloudListRuntimesRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalSignalRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsBrowserOpenSessionRpc, WsBrowserListSessionsRpc, WsBrowserCloseSessionRpc, WsBrowserGetSessionRpc, WsBrowserCommandRpc, WsBrowserClearBrowsingDataRpc, WsBrowserAttachDisplayRpc, WsBrowserAddDisplayIceCandidateRpc, WsComputerInputRpc, WsDevTunnelRegisterRpc, WsDevTunnelUnregisterRpc, WsDevTunnelListRpc, WsThreadDevRuntimeGetRpc, WsThreadDevRuntimeAllocatePortRpc, WsThreadDevRuntimeReleaseRpc, WsWorkspaceEnvironmentPreflightRpc, WsWorkspaceEnsureScratchRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsProjectsListEntriesRpc, WsServerDiscoverSourceControlRpc, WsServerReportClientActivityRpc, WsSubscribeBrowserEventsRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsSubscribeWorkspaceReadinessRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationStreamTurnDiffRpc, WsOrchestrationStreamFullThreadDiffRpc, WsOrchestrationReplayEventsRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc
|
|
26666
|
+
}), WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsThreadCommentsRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsProjectCheckoutDeletionPreviewRpc, WsProjectCheckoutDeletionExecuteRpc, WsCodeGraphSummaryRpc, WsCodeGraphNeighborhoodRpc, WsCodeGraphSearchRpc, WsWorkspaceReadFileRpc, WsWorkspaceBeginWriteFileRpc, WsWorkspaceWriteFileChunkRpc, WsWorkspaceCommitWriteFileRpc, WsWorkspaceCancelWriteFileRpc, WsShellOpenInEditorRpc, WsSubscribeGitStatusRpc, WsGitPullRpc, WsGitRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsGitListBranchesRpc, WsVcsListRefsRpc, WsVcsRefreshStatusRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsGitCreateWorktreeRpc, WsGitRemoveWorktreeRpc, WsGitCreateBranchRpc, WsGitCheckoutRpc, WsGitInitRpc, WsFilesystemBrowseRpc, WsProjectsReadFileRpc, WsReviewGetDiffPreviewRpc, WsCloudListRuntimesRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalSignalRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsBrowserOpenSessionRpc, WsBrowserListSessionsRpc, WsBrowserCloseSessionRpc, WsBrowserGetSessionRpc, WsBrowserCommandRpc, WsBrowserClearBrowsingDataRpc, WsBrowserAttachDisplayRpc, WsBrowserAddDisplayIceCandidateRpc, WsComputerInputRpc, WsDevTunnelRegisterRpc, WsDevTunnelUnregisterRpc, WsDevTunnelListRpc, WsThreadDevRuntimeGetRpc, WsThreadDevRuntimeAllocatePortRpc, WsThreadDevRuntimeReleaseRpc, WsWorkspaceEnvironmentPreflightRpc, WsWorkspaceEnsureScratchRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsProjectsListEntriesRpc, WsServerDiscoverSourceControlRpc, WsServerReportClientActivityRpc, WsSubscribeBrowserEventsRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsSubscribeWorkspaceReadinessRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationStreamTurnDiffRpc, WsOrchestrationStreamFullThreadDiffRpc, WsOrchestrationReplayEventsRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc, make$30(WS_METHODS.assetsCreateUrl, {
|
|
26667
|
+
payload: AssetsRpcSchemas.createUrl.input,
|
|
26668
|
+
success: AssetsRpcSchemas.createUrl.output,
|
|
26669
|
+
error: AssetAccessError
|
|
26670
|
+
}), make$30(WS_METHODS.providerUploadFeedback, {
|
|
26671
|
+
payload: ProviderUploadFeedbackInput,
|
|
26672
|
+
success: ProviderUploadFeedbackResult,
|
|
26673
|
+
error: ProviderUploadFeedbackError
|
|
26674
|
+
}), WsOrchestrationSearchThreadsRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc);
|
|
26431
26675
|
const RelayWsRpcGroup = WsRpcGroup.middleware(RelayAuthorizationMiddleware).middleware(RelayDeliveryMiddleware);
|
|
26432
26676
|
/**
|
|
26433
26677
|
* The direct-WebSocket mount of the same group, with per-method scope
|
|
@@ -31559,6 +31803,31 @@ const RELAY_METHOD_POLICY_BASES = [
|
|
|
31559
31803
|
method: ORCHESTRATION_WS_METHODS.subscribeThread,
|
|
31560
31804
|
requiredScope: "thread.read",
|
|
31561
31805
|
deliveryClass: "subscription"
|
|
31806
|
+
},
|
|
31807
|
+
{
|
|
31808
|
+
method: WS_METHODS.assetsCreateUrl,
|
|
31809
|
+
requiredScope: "thread.read",
|
|
31810
|
+
deliveryClass: "read"
|
|
31811
|
+
},
|
|
31812
|
+
{
|
|
31813
|
+
method: ORCHESTRATION_WS_METHODS.searchThreads,
|
|
31814
|
+
requiredScope: "thread.read",
|
|
31815
|
+
deliveryClass: "read"
|
|
31816
|
+
},
|
|
31817
|
+
{
|
|
31818
|
+
method: WS_METHODS.providerUploadFeedback,
|
|
31819
|
+
requiredScope: "thread.read",
|
|
31820
|
+
deliveryClass: "create-command"
|
|
31821
|
+
},
|
|
31822
|
+
{
|
|
31823
|
+
method: WS_METHODS.sourceControlLookupRepository,
|
|
31824
|
+
requiredScope: "git.read",
|
|
31825
|
+
deliveryClass: "read"
|
|
31826
|
+
},
|
|
31827
|
+
{
|
|
31828
|
+
method: WS_METHODS.sourceControlCloneRepository,
|
|
31829
|
+
requiredScope: "project.write",
|
|
31830
|
+
deliveryClass: "idempotent-command"
|
|
31562
31831
|
}
|
|
31563
31832
|
];
|
|
31564
31833
|
const FRAME_JOURNALED_METHODS = new Set([
|
|
@@ -33726,7 +33995,7 @@ function isRejectedCredential(cause) {
|
|
|
33726
33995
|
//#region src/connect/hiddenInput.ts
|
|
33727
33996
|
/** Ctrl-C arrives as this byte on a raw TTY rather than as a signal. */
|
|
33728
33997
|
const END_OF_TEXT = "";
|
|
33729
|
-
function firstLine(value) {
|
|
33998
|
+
function firstLine$1(value) {
|
|
33730
33999
|
const index = value.indexOf("\n");
|
|
33731
34000
|
const line = index === -1 ? value : value.slice(0, index);
|
|
33732
34001
|
return line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
@@ -33751,7 +34020,7 @@ function readHiddenLine(input) {
|
|
|
33751
34020
|
settled = true;
|
|
33752
34021
|
detach();
|
|
33753
34022
|
input.output.write("\n");
|
|
33754
|
-
resolve(firstLine(value));
|
|
34023
|
+
resolve(firstLine$1(value));
|
|
33755
34024
|
};
|
|
33756
34025
|
const onData = (chunk) => {
|
|
33757
34026
|
buffer += chunk.toString();
|
|
@@ -35183,7 +35452,7 @@ function stringify(value, fallback = "[unserializable]") {
|
|
|
35183
35452
|
return typeof fallback === "function" ? fallback(value) : fallback;
|
|
35184
35453
|
}
|
|
35185
35454
|
}
|
|
35186
|
-
function truncate$
|
|
35455
|
+
function truncate$2(str, max = 0) {
|
|
35187
35456
|
if (typeof str !== "string" || max === 0) return str;
|
|
35188
35457
|
return str.length <= max ? str : `${str.slice(0, max)}...`;
|
|
35189
35458
|
}
|
|
@@ -35790,7 +36059,7 @@ var Scope = class Scope {
|
|
|
35790
36059
|
const mergedBreadcrumb = {
|
|
35791
36060
|
timestamp: dateTimestampInSeconds(),
|
|
35792
36061
|
...breadcrumb,
|
|
35793
|
-
message: breadcrumb.message ? truncate$
|
|
36062
|
+
message: breadcrumb.message ? truncate$2(breadcrumb.message, 2048) : breadcrumb.message
|
|
35794
36063
|
};
|
|
35795
36064
|
this._breadcrumbs.push(mergedBreadcrumb);
|
|
35796
36065
|
if (this._breadcrumbs.length > maxCrumbs) {
|
|
@@ -38448,9 +38717,9 @@ function applyClientOptions(event, options) {
|
|
|
38448
38717
|
if (!event.release && release) event.release = release;
|
|
38449
38718
|
if (!event.dist && dist) event.dist = dist;
|
|
38450
38719
|
const request = event.request;
|
|
38451
|
-
if (request?.url && maxValueLength) request.url = truncate$
|
|
38720
|
+
if (request?.url && maxValueLength) request.url = truncate$2(request.url, maxValueLength);
|
|
38452
38721
|
if (maxValueLength) event.exception?.values?.forEach((exception) => {
|
|
38453
|
-
if (exception.value) exception.value = truncate$
|
|
38722
|
+
if (exception.value) exception.value = truncate$2(exception.value, maxValueLength);
|
|
38454
38723
|
});
|
|
38455
38724
|
}
|
|
38456
38725
|
function applyDebugIds(event, stackParser) {
|
|
@@ -50194,7 +50463,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
50194
50463
|
const min = forceColor || 0;
|
|
50195
50464
|
if (env.TERM === "dumb") return min;
|
|
50196
50465
|
if (process$1.platform === "win32") {
|
|
50197
|
-
const osRelease =
|
|
50466
|
+
const osRelease = $U.release().split(".");
|
|
50198
50467
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
50199
50468
|
return 1;
|
|
50200
50469
|
}
|
|
@@ -52637,7 +52906,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52637
52906
|
exports.processDetector = void 0;
|
|
52638
52907
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
52639
52908
|
const semconv_1 = require_semconv$1();
|
|
52640
|
-
const os$
|
|
52909
|
+
const os$3 = __require("os");
|
|
52641
52910
|
/**
|
|
52642
52911
|
* ProcessDetector will be used to detect the resources related current process running
|
|
52643
52912
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -52659,7 +52928,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52659
52928
|
};
|
|
52660
52929
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
52661
52930
|
try {
|
|
52662
|
-
const userInfo = os$
|
|
52931
|
+
const userInfo = os$3.userInfo();
|
|
52663
52932
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
52664
52933
|
} catch (e) {
|
|
52665
52934
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -62067,7 +62336,7 @@ const cacheResponseHook = (span, redisCommand, cmdArgs, response) => {
|
|
|
62067
62336
|
[SEMANTIC_ATTRIBUTE_CACHE_KEY]: safeKey
|
|
62068
62337
|
});
|
|
62069
62338
|
const spanDescription = safeKey.join(", ");
|
|
62070
|
-
span.updateName(_redisOptions.maxCacheKeyLength ? truncate$
|
|
62339
|
+
span.updateName(_redisOptions.maxCacheKeyLength ? truncate$2(spanDescription, _redisOptions.maxCacheKeyLength) : spanDescription);
|
|
62071
62340
|
};
|
|
62072
62341
|
//#endregion
|
|
62073
62342
|
//#region ../../node_modules/.bun/@sentry+node@10.70.0+cfd4f484ffd29da6/node_modules/@sentry/node/build/esm/integrations/tracing/redis/vendored/semconv.js
|
|
@@ -65582,7 +65851,7 @@ function normalizeNumberish(value) {
|
|
|
65582
65851
|
}
|
|
65583
65852
|
//#endregion
|
|
65584
65853
|
//#region package.json
|
|
65585
|
-
var version$1 = "0.13.
|
|
65854
|
+
var version$1 = "0.13.4";
|
|
65586
65855
|
//#endregion
|
|
65587
65856
|
//#region src/sentry.ts
|
|
65588
65857
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -69101,6 +69370,102 @@ var BrowserTraceCollector = class extends Service$1()("forge/observability/Servi
|
|
|
69101
69370
|
*/
|
|
69102
69371
|
var ProjectFaviconResolver = class extends Service$1()("forge/project/Services/ProjectFaviconResolver") {};
|
|
69103
69372
|
//#endregion
|
|
69373
|
+
//#region src/auth/Services/ServerSecretStore.ts
|
|
69374
|
+
var SecretStoreError = class extends TaggedError("SecretStoreError") {};
|
|
69375
|
+
var ServerSecretStore = class extends Service$1()("forge/auth/Services/ServerSecretStore") {};
|
|
69376
|
+
//#endregion
|
|
69377
|
+
//#region src/auth/assetUrlToken.ts
|
|
69378
|
+
/**
|
|
69379
|
+
* A credential an image tag can carry.
|
|
69380
|
+
*
|
|
69381
|
+
* `/attachments/*` and `GET /api/project-favicon` both require an authenticated
|
|
69382
|
+
* request, and the clients that render those bytes hand a bare URL to an image
|
|
69383
|
+
* loader that sends no cookie and no Authorization header. Web gets away with
|
|
69384
|
+
* it because the browser attaches the session cookie itself. The phone holds a
|
|
69385
|
+
* bearer token it has no way to attach, so every asset it fetched would 401.
|
|
69386
|
+
*
|
|
69387
|
+
* So the URL carries its own proof. The token is signed with the same server
|
|
69388
|
+
* signing key as the session and WebSocket credentials, and it is deliberately
|
|
69389
|
+
* weaker than either of those: it names one resource, and presenting it grants
|
|
69390
|
+
* that resource and nothing else. A leaked favicon URL is a leaked favicon.
|
|
69391
|
+
*/
|
|
69392
|
+
const ASSET_TOKEN_KIND = "asset";
|
|
69393
|
+
const ASSET_URL_TOKEN_QUERY_PARAM = "assetToken";
|
|
69394
|
+
/**
|
|
69395
|
+
* An hour, against a client that re-asks every thirty minutes.
|
|
69396
|
+
*
|
|
69397
|
+
* The vendored client refreshes asset URLs on a thirty-minute interval, so a
|
|
69398
|
+
* shorter life would expire URLs the client still believes are good, and the
|
|
69399
|
+
* failure would show up as an image that worked and then stopped.
|
|
69400
|
+
*/
|
|
69401
|
+
const DEFAULT_ASSET_URL_TOKEN_TTL = hours(1);
|
|
69402
|
+
const SIGNING_SECRET_NAME$1 = "server-signing-key";
|
|
69403
|
+
const decodeAssetTokenClaims = decodeUnknownEffect(fromJsonString(Struct({
|
|
69404
|
+
v: Literal(1),
|
|
69405
|
+
kind: Literal(ASSET_TOKEN_KIND),
|
|
69406
|
+
sid: String$1,
|
|
69407
|
+
res: String$1,
|
|
69408
|
+
iat: Number$1,
|
|
69409
|
+
exp: Number$1
|
|
69410
|
+
})));
|
|
69411
|
+
/**
|
|
69412
|
+
* The canonical name of one addressable asset.
|
|
69413
|
+
*
|
|
69414
|
+
* Both the mint and the check compute this from their own side: the RPC from
|
|
69415
|
+
* the resource it was asked about, the route from the request it received. They
|
|
69416
|
+
* have to agree exactly, which is the point. A token minted for one attachment
|
|
69417
|
+
* cannot be replayed against another, or against a favicon.
|
|
69418
|
+
*
|
|
69419
|
+
* The key is built from the address, not the logical id, because the address is
|
|
69420
|
+
* what both sides actually hold. The attachments route reads its id straight
|
|
69421
|
+
* out of the URL path without percent-decoding, so keying on the decoded id
|
|
69422
|
+
* would let the two sides disagree about an id that encodes to something else.
|
|
69423
|
+
*/
|
|
69424
|
+
function assetResourceKey(resource) {
|
|
69425
|
+
return resource.kind === "attachment" ? `attachment:${resource.urlPathSegment}` : `project-favicon:${resource.cwd}`;
|
|
69426
|
+
}
|
|
69427
|
+
const resolveSigningSecret = gen(function* () {
|
|
69428
|
+
const serverConfig = yield* ServerConfig;
|
|
69429
|
+
const secretStore = yield* ServerSecretStore;
|
|
69430
|
+
return resolveConfiguredSigningKey(serverConfig.sessionSigningKey) ?? (yield* secretStore.getOrCreateRandom(SIGNING_SECRET_NAME$1, 32));
|
|
69431
|
+
});
|
|
69432
|
+
const issueAssetUrlToken = (input) => gen(function* () {
|
|
69433
|
+
const secret = yield* resolveSigningSecret;
|
|
69434
|
+
const issuedAt = yield* now;
|
|
69435
|
+
const expiresAt = add$3(issuedAt, { milliseconds: toMillis(input.ttl ?? DEFAULT_ASSET_URL_TOKEN_TTL) });
|
|
69436
|
+
const claims = {
|
|
69437
|
+
v: 1,
|
|
69438
|
+
kind: ASSET_TOKEN_KIND,
|
|
69439
|
+
sid: input.sessionId,
|
|
69440
|
+
res: input.resourceKey,
|
|
69441
|
+
iat: issuedAt.epochMilliseconds,
|
|
69442
|
+
exp: expiresAt.epochMilliseconds
|
|
69443
|
+
};
|
|
69444
|
+
const encodedPayload = base64UrlEncode(JSON.stringify(claims));
|
|
69445
|
+
return {
|
|
69446
|
+
token: `${encodedPayload}.${signPayload(encodedPayload, secret)}`,
|
|
69447
|
+
expiresAt: expiresAt.epochMilliseconds
|
|
69448
|
+
};
|
|
69449
|
+
});
|
|
69450
|
+
/**
|
|
69451
|
+
* Whether this token opens this resource, right now.
|
|
69452
|
+
*
|
|
69453
|
+
* Returns a boolean rather than failing, because every negative answer means
|
|
69454
|
+
* the same thing to the caller: fall through to ordinary request
|
|
69455
|
+
* authentication. A malformed token from a stale client should behave like no
|
|
69456
|
+
* token at all, not like a different error.
|
|
69457
|
+
*/
|
|
69458
|
+
const verifyAssetUrlToken = (input) => gen(function* () {
|
|
69459
|
+
const [encodedPayload, signature] = input.token.split(".");
|
|
69460
|
+
if (!encodedPayload || !signature) return false;
|
|
69461
|
+
if (!timingSafeEqualBase64Url(signature, signPayload(encodedPayload, yield* resolveSigningSecret))) return false;
|
|
69462
|
+
const claims = yield* decodeAssetTokenClaims(base64UrlDecodeUtf8(encodedPayload)).pipe(orElseSucceed(() => null));
|
|
69463
|
+
if (!claims) return false;
|
|
69464
|
+
if (claims.res !== input.resourceKey) return false;
|
|
69465
|
+
const now = yield* currentTimeMillis;
|
|
69466
|
+
return claims.exp > now;
|
|
69467
|
+
}).pipe(orElseSucceed(() => false));
|
|
69468
|
+
//#endregion
|
|
69104
69469
|
//#region src/environment/Services/ServerEnvironment.ts
|
|
69105
69470
|
var ServerEnvironment = class extends Service$1()("forge/environment/Services/ServerEnvironment") {};
|
|
69106
69471
|
//#endregion
|
|
@@ -69375,6 +69740,28 @@ const requireAuthenticatedRequest$1 = gen(function* () {
|
|
|
69375
69740
|
const request = yield* HttpServerRequest;
|
|
69376
69741
|
yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
69377
69742
|
});
|
|
69743
|
+
/**
|
|
69744
|
+
* Authenticate a request for asset bytes.
|
|
69745
|
+
*
|
|
69746
|
+
* Ordinary request authentication first, so the web app's cookie keeps working
|
|
69747
|
+
* exactly as it did and nothing about these routes changes for it. An asset
|
|
69748
|
+
* token is the fallback, for the clients that render these bytes through an
|
|
69749
|
+
* image loader with no way to attach a credential. See `auth/assetUrlToken.ts`
|
|
69750
|
+
* for why the token is scoped to one resource.
|
|
69751
|
+
*/
|
|
69752
|
+
const requireAssetAccess = (resourceKey) => gen(function* () {
|
|
69753
|
+
const request = yield* HttpServerRequest;
|
|
69754
|
+
const serverAuth = yield* ServerAuth;
|
|
69755
|
+
const url = toURL(request);
|
|
69756
|
+
const token = isSome(url) ? url.value.searchParams.get(ASSET_URL_TOKEN_QUERY_PARAM) : null;
|
|
69757
|
+
if (token && token.trim().length > 0) {
|
|
69758
|
+
if (yield* verifyAssetUrlToken({
|
|
69759
|
+
token,
|
|
69760
|
+
resourceKey
|
|
69761
|
+
})) return;
|
|
69762
|
+
}
|
|
69763
|
+
yield* serverAuth.authenticateHttpRequest(request);
|
|
69764
|
+
});
|
|
69378
69765
|
const serverEnvironmentRouteLayer = add$1("GET", "/.well-known/forge/environment", gen(function* () {
|
|
69379
69766
|
return jsonUnsafe(yield* service(ServerEnvironment).pipe(flatMap((serverEnvironment) => serverEnvironment.getDescriptor)), { status: 200 });
|
|
69380
69767
|
}));
|
|
@@ -69443,12 +69830,15 @@ const otlpTracesProxyRouteLayer = add$1("POST", OTLP_TRACES_PROXY_PATH, gen(func
|
|
|
69443
69830
|
captureServerError(cause, { route: "/api/observability/v1/traces" });
|
|
69444
69831
|
}).pipe(andThen(() => logError("otlp-traces unhandled cause", { cause }))))));
|
|
69445
69832
|
const attachmentsRouteLayer = add$1("GET", `${ATTACHMENTS_ROUTE_PREFIX}/*`, gen(function* () {
|
|
69446
|
-
yield* requireAuthenticatedRequest$1;
|
|
69447
69833
|
const url = toURL(yield* HttpServerRequest);
|
|
69448
69834
|
if (isNone(url)) return text$2("Bad Request", { status: 400 });
|
|
69449
69835
|
const config = yield* ServerConfig;
|
|
69450
69836
|
const normalizedRelativePath = normalizeAttachmentRelativePath(url.value.pathname.slice(12));
|
|
69451
69837
|
if (!normalizedRelativePath) return text$2("Invalid attachment path", { status: 400 });
|
|
69838
|
+
yield* requireAssetAccess(assetResourceKey({
|
|
69839
|
+
kind: "attachment",
|
|
69840
|
+
urlPathSegment: normalizedRelativePath
|
|
69841
|
+
}));
|
|
69452
69842
|
const isIdLookup = !normalizedRelativePath.includes("/") && !normalizedRelativePath.includes(".");
|
|
69453
69843
|
const filePath = isIdLookup ? resolveAttachmentPathById({
|
|
69454
69844
|
attachmentsDir: config.attachmentsDir,
|
|
@@ -69466,12 +69856,14 @@ const attachmentsRouteLayer = add$1("GET", `${ATTACHMENTS_ROUTE_PREFIX}/*`, gen(
|
|
|
69466
69856
|
}).pipe(catch_(() => succeed(text$2("Internal Server Error", { status: 500 }))));
|
|
69467
69857
|
}).pipe(catchTag("AuthError", respondToAuthError)));
|
|
69468
69858
|
const projectFaviconRouteLayer = add$1("GET", "/api/project-favicon", gen(function* () {
|
|
69469
|
-
const
|
|
69470
|
-
yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
69471
|
-
const url = toURL(request);
|
|
69859
|
+
const url = toURL(yield* HttpServerRequest);
|
|
69472
69860
|
if (isNone(url)) return text$2("Bad Request", { status: 400 });
|
|
69473
69861
|
const projectCwd = url.value.searchParams.get("cwd");
|
|
69474
69862
|
if (!projectCwd) return text$2("Missing cwd parameter", { status: 400 });
|
|
69863
|
+
yield* requireAssetAccess(assetResourceKey({
|
|
69864
|
+
kind: "project-favicon",
|
|
69865
|
+
cwd: projectCwd
|
|
69866
|
+
}));
|
|
69475
69867
|
const faviconFilePath = yield* (yield* ProjectFaviconResolver).resolvePath(projectCwd);
|
|
69476
69868
|
if (!faviconFilePath) return empty$6({
|
|
69477
69869
|
status: 204,
|
|
@@ -74334,7 +74726,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
74334
74726
|
var fs$6 = __require("fs");
|
|
74335
74727
|
var path$5 = __require("path");
|
|
74336
74728
|
var url$1 = __require("url");
|
|
74337
|
-
var os$
|
|
74729
|
+
var os$2 = __require("os");
|
|
74338
74730
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
74339
74731
|
var vars = process.config && process.config.variables || {};
|
|
74340
74732
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -74342,8 +74734,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
74342
74734
|
var abi = versions.modules;
|
|
74343
74735
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
74344
74736
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
74345
|
-
var arch = process.env.npm_config_arch || os$
|
|
74346
|
-
var platform = process.env.npm_config_platform || os$
|
|
74737
|
+
var arch = process.env.npm_config_arch || os$2.arch();
|
|
74738
|
+
var platform = process.env.npm_config_platform || os$2.platform();
|
|
74347
74739
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
74348
74740
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
74349
74741
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -77193,6 +77585,195 @@ succeed$2(TraceDiagnostics, TraceDiagnostics.of({ read: (options) => succeed(mak
|
|
|
77193
77585
|
}
|
|
77194
77586
|
})) }));
|
|
77195
77587
|
//#endregion
|
|
77588
|
+
//#region src/assets/createAssetUrl.ts
|
|
77589
|
+
const PROJECT_FAVICON_ROUTE = "/api/project-favicon";
|
|
77590
|
+
/**
|
|
77591
|
+
* Turn a resource into an address a client can fetch.
|
|
77592
|
+
*
|
|
77593
|
+
* Nothing new is served here. `/attachments/*` and `GET /api/project-favicon`
|
|
77594
|
+
* already return these bytes; what did not exist was the step in between, and
|
|
77595
|
+
* without it a client holding an attachment id or a workspace root has no way
|
|
77596
|
+
* to name the URL. The vendored mobile client asks this for every project on
|
|
77597
|
+
* its thread list, so the gap was not an edge case, it was the most visited
|
|
77598
|
+
* screen.
|
|
77599
|
+
*
|
|
77600
|
+
* The URL is relative so it resolves against whichever base the client is
|
|
77601
|
+
* already talking to, and it carries a token because the clients that render
|
|
77602
|
+
* these bytes hand the URL to an image loader that attaches no credential of
|
|
77603
|
+
* its own. See `auth/assetUrlToken.ts`.
|
|
77604
|
+
*/
|
|
77605
|
+
const createAssetUrl = (sessionId, resource) => gen(function* () {
|
|
77606
|
+
if (resource._tag === "workspace-file") return yield* new AssetWorkspaceResolutionError({
|
|
77607
|
+
resource,
|
|
77608
|
+
cause: "Workspace files are read over projects.readFile, not by URL."
|
|
77609
|
+
});
|
|
77610
|
+
const address = resolveAddress(resource);
|
|
77611
|
+
const issued = yield* issueAssetUrlToken({
|
|
77612
|
+
sessionId,
|
|
77613
|
+
resourceKey: address.resourceKey
|
|
77614
|
+
}).pipe(mapError((cause) => new AssetSigningKeyLoadError({
|
|
77615
|
+
resource,
|
|
77616
|
+
cause
|
|
77617
|
+
})));
|
|
77618
|
+
return {
|
|
77619
|
+
relativeUrl: `${address.path}?${address.query}assetToken=${encodeURIComponent(issued.token)}`,
|
|
77620
|
+
expiresAt: issued.expiresAt,
|
|
77621
|
+
...resource._tag === "project-favicon" && resource.path ? { sourcePath: resource.path } : {}
|
|
77622
|
+
};
|
|
77623
|
+
});
|
|
77624
|
+
function resolveAddress(resource) {
|
|
77625
|
+
if (resource._tag === "attachment") {
|
|
77626
|
+
const urlPathSegment = encodeURIComponent(resource.attachmentId);
|
|
77627
|
+
return {
|
|
77628
|
+
resourceKey: assetResourceKey({
|
|
77629
|
+
kind: "attachment",
|
|
77630
|
+
urlPathSegment
|
|
77631
|
+
}),
|
|
77632
|
+
path: `${ATTACHMENTS_ROUTE_PREFIX}/${urlPathSegment}`,
|
|
77633
|
+
query: ""
|
|
77634
|
+
};
|
|
77635
|
+
}
|
|
77636
|
+
return {
|
|
77637
|
+
resourceKey: assetResourceKey({
|
|
77638
|
+
kind: "project-favicon",
|
|
77639
|
+
cwd: resource.cwd
|
|
77640
|
+
}),
|
|
77641
|
+
path: PROJECT_FAVICON_ROUTE,
|
|
77642
|
+
query: `cwd=${encodeURIComponent(resource.cwd)}&`
|
|
77643
|
+
};
|
|
77644
|
+
}
|
|
77645
|
+
//#endregion
|
|
77646
|
+
//#region src/cmmd/submitFeedback.ts
|
|
77647
|
+
/** The intake the web app's feedback dialog already posts to, reached directly. */
|
|
77648
|
+
const CMMD_FEEDBACK_PATH = "/api/forge/context/feedback";
|
|
77649
|
+
/**
|
|
77650
|
+
* The intake answers with the task it created.
|
|
77651
|
+
*
|
|
77652
|
+
* Web reaches it through the proxy registry, which unwraps `data` before the
|
|
77653
|
+
* caller sees it; this calls the gateway directly and does not, so both shapes
|
|
77654
|
+
* are read here rather than pinning the one that happens to arrive today.
|
|
77655
|
+
*/
|
|
77656
|
+
function readFeedbackId(response) {
|
|
77657
|
+
if (!response || typeof response !== "object") return null;
|
|
77658
|
+
const record = response;
|
|
77659
|
+
const envelope = record["data"];
|
|
77660
|
+
const id = (envelope && typeof envelope === "object" ? envelope : record)["id"];
|
|
77661
|
+
if (typeof id === "number") return String(id);
|
|
77662
|
+
if (typeof id === "string" && id.trim().length > 0) return id.trim();
|
|
77663
|
+
return null;
|
|
77664
|
+
}
|
|
77665
|
+
/**
|
|
77666
|
+
* File feedback against the caller's own CMMD account.
|
|
77667
|
+
*
|
|
77668
|
+
* The session's CMMD JWT is what scopes it. A server with no CMMD connection
|
|
77669
|
+
* has nowhere to send feedback and says so in a sentence, because the caller
|
|
77670
|
+
* draws this text straight into the thread the person is looking at.
|
|
77671
|
+
*/
|
|
77672
|
+
function submitCmmdFeedbackForSession(input) {
|
|
77673
|
+
return gen(function* () {
|
|
77674
|
+
const jwt = yield* resolveCmmdJwtForSession({
|
|
77675
|
+
sessionId: input.sessionId,
|
|
77676
|
+
...input.subject === void 0 ? {} : { subject: input.subject },
|
|
77677
|
+
logPrefix: "cmmd-feedback"
|
|
77678
|
+
}).pipe(orElseSucceed(() => null));
|
|
77679
|
+
if (!jwt) return {
|
|
77680
|
+
ok: false,
|
|
77681
|
+
reason: "This server is not connected to CMMD, so there is nowhere to send feedback."
|
|
77682
|
+
};
|
|
77683
|
+
const body = {
|
|
77684
|
+
type: "bug",
|
|
77685
|
+
title: input.title,
|
|
77686
|
+
source: "forge",
|
|
77687
|
+
priority: "medium",
|
|
77688
|
+
...input.description ? { description: input.description } : {},
|
|
77689
|
+
...input.senderName ? { senderName: input.senderName } : {}
|
|
77690
|
+
};
|
|
77691
|
+
const response = yield* tryPromise(() => cmmdGateway.request({
|
|
77692
|
+
method: "POST",
|
|
77693
|
+
jwt,
|
|
77694
|
+
path: CMMD_FEEDBACK_PATH,
|
|
77695
|
+
body
|
|
77696
|
+
})).pipe(orElseSucceed(() => null));
|
|
77697
|
+
if (response === null) return {
|
|
77698
|
+
ok: false,
|
|
77699
|
+
reason: "The feedback service did not accept the report. Please try again."
|
|
77700
|
+
};
|
|
77701
|
+
const feedbackId = readFeedbackId(response);
|
|
77702
|
+
if (feedbackId === null) return {
|
|
77703
|
+
ok: false,
|
|
77704
|
+
reason: "The feedback service answered without recording a report."
|
|
77705
|
+
};
|
|
77706
|
+
return {
|
|
77707
|
+
ok: true,
|
|
77708
|
+
feedbackId
|
|
77709
|
+
};
|
|
77710
|
+
});
|
|
77711
|
+
}
|
|
77712
|
+
//#endregion
|
|
77713
|
+
//#region src/provider/threadFeedback.ts
|
|
77714
|
+
const FEEDBACK_TITLE_MAX_CHARS = 120;
|
|
77715
|
+
function firstLine(text) {
|
|
77716
|
+
return text.split("\n", 1)[0]?.trim() ?? "";
|
|
77717
|
+
}
|
|
77718
|
+
function truncate$1(text, max) {
|
|
77719
|
+
return text.length <= max ? text : `${text.slice(0, max - 1).trimEnd()}…`;
|
|
77720
|
+
}
|
|
77721
|
+
/**
|
|
77722
|
+
* A title someone triaging the intake can act on.
|
|
77723
|
+
*
|
|
77724
|
+
* What the person typed after `/feedback` first, because it is the only part
|
|
77725
|
+
* they wrote. The thread's title is the fallback, and a bare thread id is the
|
|
77726
|
+
* last resort, since a queue of "Forge feedback" rows tells a triager nothing.
|
|
77727
|
+
*/
|
|
77728
|
+
function feedbackTitle(input) {
|
|
77729
|
+
const reason = input.reason ? firstLine(input.reason) : "";
|
|
77730
|
+
if (reason.length > 0) return truncate$1(reason, FEEDBACK_TITLE_MAX_CHARS);
|
|
77731
|
+
const threadTitle = input.threadTitle?.trim() ?? "";
|
|
77732
|
+
if (threadTitle.length > 0) return truncate$1(`Forge feedback: ${threadTitle}`, FEEDBACK_TITLE_MAX_CHARS);
|
|
77733
|
+
return truncate$1(`Forge feedback: thread ${input.threadId}`, FEEDBACK_TITLE_MAX_CHARS);
|
|
77734
|
+
}
|
|
77735
|
+
/** The body, which always names the thread so the report can be traced back to it. */
|
|
77736
|
+
function feedbackDescription(input) {
|
|
77737
|
+
const lines = [`Filed from Forge thread \`${input.threadId}\`.`];
|
|
77738
|
+
if (input.threadTitle?.trim()) lines.push(`Thread title: ${input.threadTitle.trim()}`);
|
|
77739
|
+
if (input.reason?.trim()) lines.push("", input.reason.trim());
|
|
77740
|
+
return lines.join("\n");
|
|
77741
|
+
}
|
|
77742
|
+
/**
|
|
77743
|
+
* `/feedback`, served.
|
|
77744
|
+
*
|
|
77745
|
+
* The vendored client declared this method and called it; Forge answered
|
|
77746
|
+
* nothing, so the slash command printed the transport's own "unknown request
|
|
77747
|
+
* tag" string into the thread. Routing it to the CMMD intake the web feedback
|
|
77748
|
+
* dialog already uses means one report format and one destination, whichever
|
|
77749
|
+
* surface it came from.
|
|
77750
|
+
*
|
|
77751
|
+
* Every failure carries a sentence rather than a cause, because the client
|
|
77752
|
+
* draws `message` straight into the thread as an assistant reply.
|
|
77753
|
+
*/
|
|
77754
|
+
const uploadThreadFeedback = (orchestrationEngine, sessionId, subject, input) => gen(function* () {
|
|
77755
|
+
const threadTitle = (yield* orchestrationEngine.getReadModel().pipe(orElseSucceed(() => null)))?.threads.find((thread) => thread.id === input.threadId)?.title;
|
|
77756
|
+
const outcome = yield* submitCmmdFeedbackForSession({
|
|
77757
|
+
sessionId,
|
|
77758
|
+
...subject === void 0 ? {} : { subject },
|
|
77759
|
+
title: feedbackTitle({
|
|
77760
|
+
...input,
|
|
77761
|
+
threadId: input.threadId,
|
|
77762
|
+
...threadTitle ? { threadTitle } : {}
|
|
77763
|
+
}),
|
|
77764
|
+
description: feedbackDescription({
|
|
77765
|
+
...input,
|
|
77766
|
+
threadId: input.threadId,
|
|
77767
|
+
...threadTitle ? { threadTitle } : {}
|
|
77768
|
+
})
|
|
77769
|
+
});
|
|
77770
|
+
if (!outcome.ok) return yield* new ProviderUploadFeedbackError({
|
|
77771
|
+
threadId: input.threadId,
|
|
77772
|
+
reason: outcome.reason
|
|
77773
|
+
});
|
|
77774
|
+
return { feedbackId: outcome.feedbackId };
|
|
77775
|
+
});
|
|
77776
|
+
//#endregion
|
|
77196
77777
|
//#region src/cloudRuntime/listCloudRuntimes.ts
|
|
77197
77778
|
/**
|
|
77198
77779
|
* List the caller's Forge Cloud runtimes, through CMMD, as the caller.
|
|
@@ -87222,95 +87803,278 @@ function resolveGitHubCloneDir(baseDir, repoFullName, targetDir) {
|
|
|
87222
87803
|
const repoName = repoFullName.split("/")[1] ?? repoFullName;
|
|
87223
87804
|
return targetDir ?? join(baseDir, "Projects", repoName);
|
|
87224
87805
|
}
|
|
87225
|
-
|
|
87226
|
-
|
|
87227
|
-
|
|
87228
|
-
|
|
87229
|
-
|
|
87230
|
-
|
|
87231
|
-
|
|
87232
|
-
|
|
87233
|
-
|
|
87234
|
-
|
|
87235
|
-
|
|
87236
|
-
|
|
87237
|
-
|
|
87238
|
-
|
|
87239
|
-
|
|
87240
|
-
|
|
87241
|
-
|
|
87242
|
-
|
|
87243
|
-
|
|
87244
|
-
|
|
87245
|
-
|
|
87246
|
-
|
|
87806
|
+
/**
|
|
87807
|
+
* The public clone URLs for a repository.
|
|
87808
|
+
*
|
|
87809
|
+
* Never derived from an authenticated remote: `buildAuthenticatedRemoteUrl`
|
|
87810
|
+
* embeds an installation token in the URL, and a token that reaches a client is
|
|
87811
|
+
* a token that reaches wherever the client writes it down.
|
|
87812
|
+
*/
|
|
87813
|
+
function describeGitHubRepository(nameWithOwner) {
|
|
87814
|
+
return {
|
|
87815
|
+
nameWithOwner,
|
|
87816
|
+
url: `https://github.com/${nameWithOwner}`,
|
|
87817
|
+
sshUrl: `git@github.com:${nameWithOwner}.git`
|
|
87818
|
+
};
|
|
87819
|
+
}
|
|
87820
|
+
/**
|
|
87821
|
+
* Resolve `owner/repo` against the repositories CMMD says this caller may use.
|
|
87822
|
+
*
|
|
87823
|
+
* This asks the same brokered listing the web repository picker is populated
|
|
87824
|
+
* from, rather than github.com directly, so "found" here means the same thing
|
|
87825
|
+
* it means everywhere else in Forge: CMMD will vend this caller a token for it.
|
|
87826
|
+
* A repository that exists but that the caller cannot reach is a 404, which is
|
|
87827
|
+
* the answer they can act on.
|
|
87828
|
+
*/
|
|
87829
|
+
function lookupGitHubRepositoryForSession(input) {
|
|
87830
|
+
return gen(function* () {
|
|
87831
|
+
const requested = input.repository.trim().replace(/^\/+|\/+$/g, "");
|
|
87832
|
+
if (!/^[^/\s]+\/[^/\s]+$/.test(requested)) return {
|
|
87833
|
+
status: 400,
|
|
87834
|
+
repository: null,
|
|
87835
|
+
error: "Enter a repository as owner/name."
|
|
87836
|
+
};
|
|
87837
|
+
const jwt = input.runtimeGrantAuth ? null : yield* resolveJwt(input.sessionId, input.subject);
|
|
87838
|
+
if (!input.runtimeGrantAuth && !jwt) return {
|
|
87839
|
+
status: 401,
|
|
87840
|
+
repository: null,
|
|
87841
|
+
error: "CMMD not connected"
|
|
87842
|
+
};
|
|
87843
|
+
const auth = input.runtimeGrantAuth ?? {
|
|
87247
87844
|
kind: "cmmd-jwt",
|
|
87248
|
-
jwt
|
|
87249
|
-
}
|
|
87250
|
-
|
|
87251
|
-
|
|
87252
|
-
|
|
87253
|
-
|
|
87254
|
-
|
|
87255
|
-
|
|
87256
|
-
|
|
87845
|
+
jwt
|
|
87846
|
+
};
|
|
87847
|
+
const searchTerm = requested.split("/")[1] ?? requested;
|
|
87848
|
+
let result = yield* promise(() => fetchGitHubReposForAuth(auth, {
|
|
87849
|
+
search: searchTerm,
|
|
87850
|
+
organizationId: input.organizationId ?? ""
|
|
87851
|
+
}));
|
|
87852
|
+
if (!input.runtimeGrantAuth && shouldRetryWithRefreshedCmmdJwt(result.status)) {
|
|
87853
|
+
const refreshedJwt = yield* resolveJwt(input.sessionId, input.subject, true);
|
|
87854
|
+
if (refreshedJwt && refreshedJwt !== jwt) result = yield* promise(() => fetchGitHubReposForAuth({
|
|
87855
|
+
kind: "cmmd-jwt",
|
|
87856
|
+
jwt: refreshedJwt
|
|
87857
|
+
}, {
|
|
87858
|
+
search: searchTerm,
|
|
87859
|
+
organizationId: input.organizationId ?? ""
|
|
87860
|
+
}));
|
|
87861
|
+
}
|
|
87862
|
+
if (result.status !== 200) {
|
|
87863
|
+
const body = result.body;
|
|
87864
|
+
return {
|
|
87865
|
+
status: result.status,
|
|
87866
|
+
repository: null,
|
|
87867
|
+
error: typeof body.error === "string" ? body.error : "GitHub repositories are unavailable."
|
|
87868
|
+
};
|
|
87869
|
+
}
|
|
87870
|
+
const match = selectGitHubRepositoryMatch(result.body, requested);
|
|
87871
|
+
if (match === null) return {
|
|
87872
|
+
status: 404,
|
|
87873
|
+
repository: null,
|
|
87874
|
+
error: `Repository ${requested} was not found in the GitHub accounts connected to Forge.`
|
|
87875
|
+
};
|
|
87876
|
+
return {
|
|
87877
|
+
status: 200,
|
|
87878
|
+
repository: describeGitHubRepository(match),
|
|
87879
|
+
error: null
|
|
87880
|
+
};
|
|
87881
|
+
});
|
|
87882
|
+
}
|
|
87883
|
+
/**
|
|
87884
|
+
* Find the one repository in a brokered listing whose full name is the one
|
|
87885
|
+
* asked for.
|
|
87886
|
+
*
|
|
87887
|
+
* Exact and case-insensitive. The listing is a *search*, so it comes back with
|
|
87888
|
+
* near misses in it: asking for `owner/forge` and being handed `someone-else/
|
|
87889
|
+
* forge` because it sorted first is how a person ends up cloning a stranger's
|
|
87890
|
+
* repository, and a prefix match would do exactly that.
|
|
87891
|
+
*/
|
|
87892
|
+
function selectGitHubRepositoryMatch(body, requested) {
|
|
87893
|
+
const repos = body?.repos ?? [];
|
|
87894
|
+
const wanted = requested.trim().toLowerCase();
|
|
87895
|
+
for (const repo of repos) if (typeof repo.full_name === "string" && repo.full_name.toLowerCase() === wanted) return repo.full_name;
|
|
87896
|
+
return null;
|
|
87897
|
+
}
|
|
87898
|
+
/**
|
|
87899
|
+
* The repository a clone request is really for, or `null` if there is not one.
|
|
87900
|
+
*
|
|
87901
|
+
* A caller may name `owner/repo`, or paste a clone URL and let the server work
|
|
87902
|
+
* it out. Anything that does not resolve to a GitHub repository returns `null`
|
|
87903
|
+
* and must be refused rather than cloned: Forge clones through a CMMD-brokered
|
|
87904
|
+
* installation token for a named repository, and "just run `git clone` on this
|
|
87905
|
+
* URL instead" would be a second, unbrokered way to write to disk.
|
|
87906
|
+
*/
|
|
87907
|
+
function resolveGitHubCloneTarget(input) {
|
|
87908
|
+
const named = input.repository?.trim();
|
|
87909
|
+
if (named && /^[^/\s]+\/[^/\s]+$/.test(named)) return named;
|
|
87910
|
+
if (named) return null;
|
|
87911
|
+
const remoteUrl = input.remoteUrl?.trim();
|
|
87912
|
+
return remoteUrl ? parseRepoFullNameFromRemoteUrl(remoteUrl) : null;
|
|
87913
|
+
}
|
|
87914
|
+
/**
|
|
87915
|
+
* Clone `repoFullName` for an authenticated session.
|
|
87916
|
+
*
|
|
87917
|
+
* Authorization is the caller's own CMMD connection: the session's JWT (or a
|
|
87918
|
+
* runtime grant, when this VM is running under one) is exchanged with CMMD for
|
|
87919
|
+
* an installation token scoped to that one repository. A session with no CMMD
|
|
87920
|
+
* connection gets 401 and no clone; a repository CMMD will not issue a token
|
|
87921
|
+
* for gets CMMD's own refusal, not a `git clone` attempt.
|
|
87922
|
+
*/
|
|
87923
|
+
function runGitHubCloneForSession(input) {
|
|
87924
|
+
return gen(function* () {
|
|
87925
|
+
const { config, repoFullName, targetDir } = input;
|
|
87926
|
+
const token = yield* acquireInstallationTokenForSession(input);
|
|
87927
|
+
if (!token.ok) return token.outcome;
|
|
87928
|
+
const cloneDir = resolveGitHubCloneDir(config.baseDir, repoFullName, targetDir);
|
|
87929
|
+
yield* promise(() => mkdir(join(cloneDir, ".."), { recursive: true }).catch(() => void 0));
|
|
87930
|
+
const target = {
|
|
87931
|
+
cloneDir,
|
|
87932
|
+
repoFullName,
|
|
87933
|
+
token: token.token,
|
|
87934
|
+
config
|
|
87935
|
+
};
|
|
87936
|
+
return existsSync(cloneDir) ? yield* adoptExistingGitHubClone(target) : yield* cloneGitHubRepositoryInto(target);
|
|
87937
|
+
});
|
|
87938
|
+
}
|
|
87939
|
+
/**
|
|
87940
|
+
* The installation token for one repository, on the caller's own authority.
|
|
87941
|
+
*
|
|
87942
|
+
* A runtime grant is used as-is. A session resolves its CMMD JWT and retries
|
|
87943
|
+
* once with a refreshed one when CMMD answers 401 or 403, because the cached
|
|
87944
|
+
* JWT may simply have expired. The failure branch is already the HTTP outcome,
|
|
87945
|
+
* so a caller returns it rather than translating it.
|
|
87946
|
+
*/
|
|
87947
|
+
function acquireInstallationTokenForSession(input) {
|
|
87948
|
+
return gen(function* () {
|
|
87949
|
+
const { runtimeGrantAuth, repoFullName } = input;
|
|
87950
|
+
const jwt = runtimeGrantAuth ? null : yield* resolveJwt(input.sessionId, input.subject);
|
|
87951
|
+
if (!runtimeGrantAuth && !jwt) return {
|
|
87952
|
+
ok: false,
|
|
87953
|
+
outcome: {
|
|
87954
|
+
status: 401,
|
|
87955
|
+
body: { error: "CMMD not connected" }
|
|
87956
|
+
}
|
|
87957
|
+
};
|
|
87958
|
+
let token = yield* fetchInstallationTokenForAuth(runtimeGrantAuth ?? {
|
|
87959
|
+
kind: "cmmd-jwt",
|
|
87960
|
+
jwt
|
|
87961
|
+
}, repoFullName);
|
|
87962
|
+
if (!runtimeGrantAuth && !token.ok && shouldRetryWithRefreshedCmmdJwt(token.status)) {
|
|
87963
|
+
const refreshedJwt = yield* resolveJwt(input.sessionId, input.subject, true);
|
|
87964
|
+
if (refreshedJwt && refreshedJwt !== jwt) token = yield* fetchInstallationTokenForAuth({
|
|
87965
|
+
kind: "cmmd-jwt",
|
|
87966
|
+
jwt: refreshedJwt
|
|
87967
|
+
}, repoFullName);
|
|
87968
|
+
}
|
|
87969
|
+
if (!token.ok) return {
|
|
87970
|
+
ok: false,
|
|
87971
|
+
outcome: {
|
|
87972
|
+
status: token.status,
|
|
87973
|
+
body: gitHubTokenFailureBody(token.status, token.error)
|
|
87974
|
+
}
|
|
87975
|
+
};
|
|
87976
|
+
return {
|
|
87977
|
+
ok: true,
|
|
87978
|
+
token: token.token
|
|
87979
|
+
};
|
|
87980
|
+
});
|
|
87981
|
+
}
|
|
87982
|
+
/**
|
|
87983
|
+
* A directory already sits where the clone would go. Adopt it when it is a
|
|
87984
|
+
* checkout of the same repository, so a second "add project" is a no-op with
|
|
87985
|
+
* fresh credentials rather than a failure; refuse otherwise, naming the
|
|
87986
|
+
* folder, because overwriting it would destroy something the person made.
|
|
87987
|
+
*/
|
|
87988
|
+
function adoptExistingGitHubClone(target) {
|
|
87989
|
+
return gen(function* () {
|
|
87990
|
+
const { cloneDir, repoFullName } = target;
|
|
87991
|
+
const git = (args) => promise(() => runProcess("git", [
|
|
87257
87992
|
"-C",
|
|
87258
87993
|
cloneDir,
|
|
87259
|
-
|
|
87260
|
-
"--is-inside-work-tree"
|
|
87994
|
+
...args
|
|
87261
87995
|
], {
|
|
87262
87996
|
timeoutMs: 1e4,
|
|
87263
87997
|
allowNonZeroExit: true,
|
|
87264
87998
|
env: process.env
|
|
87265
87999
|
}));
|
|
87266
|
-
const
|
|
87267
|
-
|
|
87268
|
-
cloneDir,
|
|
88000
|
+
const workTree = yield* git(["rev-parse", "--is-inside-work-tree"]);
|
|
88001
|
+
const remote = yield* git([
|
|
87269
88002
|
"remote",
|
|
87270
88003
|
"get-url",
|
|
87271
88004
|
"origin"
|
|
87272
|
-
]
|
|
87273
|
-
|
|
87274
|
-
|
|
87275
|
-
|
|
87276
|
-
|
|
87277
|
-
|
|
87278
|
-
|
|
87279
|
-
|
|
87280
|
-
|
|
87281
|
-
|
|
87282
|
-
|
|
87283
|
-
|
|
87284
|
-
return json$6({
|
|
88005
|
+
]);
|
|
88006
|
+
if (!(workTree.code === 0 && workTree.stdout.trim() === "true" && remote.code === 0 && isGitHubRemoteForRepo(remote.stdout.trim(), repoFullName))) return {
|
|
88007
|
+
status: 409,
|
|
88008
|
+
body: {
|
|
88009
|
+
error: "A project folder with that name already exists, but it is not the selected GitHub repository. Rename the import, remove the VM folder, or choose a different repository.",
|
|
88010
|
+
local_path: cloneDir
|
|
88011
|
+
}
|
|
88012
|
+
};
|
|
88013
|
+
yield* applyGitCredentialsFor(target);
|
|
88014
|
+
return {
|
|
88015
|
+
status: 200,
|
|
88016
|
+
body: {
|
|
87285
88017
|
local_path: cloneDir,
|
|
87286
88018
|
existing: true
|
|
87287
|
-
}
|
|
87288
|
-
}
|
|
87289
|
-
|
|
87290
|
-
|
|
87291
|
-
|
|
87292
|
-
|
|
87293
|
-
|
|
87294
|
-
|
|
87295
|
-
|
|
87296
|
-
|
|
87297
|
-
|
|
87298
|
-
|
|
87299
|
-
|
|
87300
|
-
|
|
88019
|
+
}
|
|
88020
|
+
};
|
|
88021
|
+
});
|
|
88022
|
+
}
|
|
88023
|
+
function cloneGitHubRepositoryInto(target) {
|
|
88024
|
+
return gen(function* () {
|
|
88025
|
+
const { cloneDir, repoFullName, token } = target;
|
|
88026
|
+
const result = yield* promise(() => runProcess("git", buildAuthenticatedGitCloneArgs(repoFullName, cloneDir), {
|
|
88027
|
+
timeoutMs: 12e4,
|
|
88028
|
+
allowNonZeroExit: true,
|
|
88029
|
+
env: {
|
|
88030
|
+
...process.env,
|
|
88031
|
+
CMMD_FORGE_GIT_TOKEN: token,
|
|
88032
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
88033
|
+
}
|
|
88034
|
+
}));
|
|
88035
|
+
if (result.code !== 0) {
|
|
88036
|
+
const stderr = sanitizeGitCredentialText(result.stderr).trim().slice(0, 500);
|
|
88037
|
+
return {
|
|
88038
|
+
status: 500,
|
|
88039
|
+
body: { error: `git clone failed${stderr.length > 0 ? `: ${stderr}` : ""}` }
|
|
88040
|
+
};
|
|
87301
88041
|
}
|
|
87302
|
-
|
|
87303
|
-
|
|
87304
|
-
|
|
87305
|
-
|
|
88042
|
+
yield* applyGitCredentialsFor(target);
|
|
88043
|
+
return {
|
|
88044
|
+
status: 200,
|
|
88045
|
+
body: { local_path: cloneDir }
|
|
88046
|
+
};
|
|
88047
|
+
});
|
|
88048
|
+
}
|
|
88049
|
+
function applyGitCredentialsFor(target) {
|
|
88050
|
+
return applyGitCredentials({
|
|
88051
|
+
cloneDir: target.cloneDir,
|
|
88052
|
+
repoFullName: target.repoFullName,
|
|
88053
|
+
token: target.token,
|
|
88054
|
+
mode: target.config.forgeGitCredentialCache ? "cache" : "embed"
|
|
88055
|
+
});
|
|
88056
|
+
}
|
|
88057
|
+
const githubCloneRouteLayer = add$1("POST", "/.well-known/forge/github/clone", gen(function* () {
|
|
88058
|
+
const request = yield* HttpServerRequest;
|
|
88059
|
+
const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
88060
|
+
const config = yield* ServerConfig;
|
|
88061
|
+
if (session.method === "proxy-asserted") {
|
|
88062
|
+
const forwardedJwt = normalizeForwardedCmmdJwt(request.headers);
|
|
88063
|
+
if (forwardedJwt !== void 0) yield* setCommandJwtForSession(session.sessionId, forwardedJwt).pipe(ignore({ log: true }));
|
|
87306
88064
|
}
|
|
87307
|
-
yield*
|
|
87308
|
-
|
|
88065
|
+
const rawBody = yield* request.json;
|
|
88066
|
+
const parsed = decodeUnknownExit(CloneBodySchema)(rawBody);
|
|
88067
|
+
if (parsed._tag === "Failure") return json$6({ error: "repo_full_name is required" }, 400);
|
|
88068
|
+
const { repo_full_name, target_dir } = parsed.value;
|
|
88069
|
+
const outcome = yield* runGitHubCloneForSession({
|
|
88070
|
+
config,
|
|
88071
|
+
sessionId: session.sessionId,
|
|
88072
|
+
subject: session.subject,
|
|
88073
|
+
runtimeGrantAuth: resolveRuntimeGitHubGrantAuth(config, request.headers),
|
|
87309
88074
|
repoFullName: repo_full_name,
|
|
87310
|
-
|
|
87311
|
-
mode: config.forgeGitCredentialCache ? "cache" : "embed"
|
|
88075
|
+
targetDir: target_dir
|
|
87312
88076
|
});
|
|
87313
|
-
return json$6(
|
|
88077
|
+
return json$6(outcome.body, outcome.status);
|
|
87314
88078
|
}).pipe(catchTag("AuthError", respondToAuthError)));
|
|
87315
88079
|
const githubCloneJobStartRouteLayer = add$1("POST", "/.well-known/forge/github/clone-jobs", gen(function* () {
|
|
87316
88080
|
const request = yield* HttpServerRequest;
|
|
@@ -92073,7 +92837,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
92073
92837
|
});
|
|
92074
92838
|
const OpenLive = effect(Open, gen(function* () {
|
|
92075
92839
|
const open = yield* tryPromise({
|
|
92076
|
-
try: () => import("./open-
|
|
92840
|
+
try: () => import("./open-D8mGyWmt.mjs"),
|
|
92077
92841
|
catch: (cause) => new OpenError$1({
|
|
92078
92842
|
message: "failed to load browser opener",
|
|
92079
92843
|
cause
|
|
@@ -104084,7 +104848,9 @@ const REJECT_UNCERTAIN_METHODS = new Set([
|
|
|
104084
104848
|
WS_METHODS.pullRequestsComment,
|
|
104085
104849
|
WS_METHODS.pullRequestsSubmitReview,
|
|
104086
104850
|
WS_METHODS.pullRequestsReplyToThread,
|
|
104087
|
-
WS_METHODS.projectCheckoutDeletionExecute
|
|
104851
|
+
WS_METHODS.projectCheckoutDeletionExecute,
|
|
104852
|
+
WS_METHODS.providerUploadFeedback,
|
|
104853
|
+
WS_METHODS.sourceControlCloneRepository
|
|
104088
104854
|
]);
|
|
104089
104855
|
function classifyInterruptedRelayCommand(input) {
|
|
104090
104856
|
if ((input.method === WS_METHODS.gitCreateBranch || input.method === WS_METHODS.vcsCreateRef) && input.deliveryClass === "create-command") return { kind: "reconcile-git-create-branch" };
|
|
@@ -105014,7 +105780,77 @@ const makeWsRpcLayer = (currentSessionId, currentUserId) => WsRpcGroup.toLayer(g
|
|
|
105014
105780
|
payload: initialSnapshot
|
|
105015
105781
|
}), liveEvents);
|
|
105016
105782
|
}), { "rpc.aggregate": "auth" }),
|
|
105017
|
-
[WS_METHODS.subscribeWorkspaceReadiness]: (_input) => currentUserId === void 0 ? empty$5 : workspaceReadinessState.subscribe(currentUserId)
|
|
105783
|
+
[WS_METHODS.subscribeWorkspaceReadiness]: (_input) => currentUserId === void 0 ? empty$5 : workspaceReadinessState.subscribe(currentUserId),
|
|
105784
|
+
[WS_METHODS.assetsCreateUrl]: (input) => observeRpcEffect(WS_METHODS.assetsCreateUrl, createAssetUrl(currentSessionId, input.resource), { "rpc.aggregate": "assets" }),
|
|
105785
|
+
[WS_METHODS.providerUploadFeedback]: (input) => observeRpcEffect(WS_METHODS.providerUploadFeedback, uploadThreadFeedback(orchestrationEngine, currentSessionId, currentUserId, input), { "rpc.aggregate": "provider" }),
|
|
105786
|
+
[ORCHESTRATION_WS_METHODS.searchThreads]: (input) => observeRpcEffect(ORCHESTRATION_WS_METHODS.searchThreads, gen(function* () {
|
|
105787
|
+
yield* startup.awaitCommandReady;
|
|
105788
|
+
return yield* projectionSnapshotQuery.searchThreads(input);
|
|
105789
|
+
}).pipe(mapError((cause) => new OrchestrationSearchThreadsError({
|
|
105790
|
+
message: "Failed to search threads",
|
|
105791
|
+
cause
|
|
105792
|
+
}))), { "rpc.aggregate": "orchestration" }),
|
|
105793
|
+
[WS_METHODS.sourceControlLookupRepository]: (input) => observeRpcEffect(WS_METHODS.sourceControlLookupRepository, gen(function* () {
|
|
105794
|
+
if (input.provider !== "github") return yield* new SourceControlRepositoryError({
|
|
105795
|
+
provider: input.provider,
|
|
105796
|
+
operation: "lookupRepository",
|
|
105797
|
+
detail: `Forge can only look up GitHub repositories. ${input.provider} is not connected.`
|
|
105798
|
+
});
|
|
105799
|
+
if (currentUserId === void 0) return yield* new SourceControlRepositoryError({
|
|
105800
|
+
provider: "github",
|
|
105801
|
+
operation: "lookupRepository",
|
|
105802
|
+
detail: "Sign in to Forge before looking up a repository."
|
|
105803
|
+
});
|
|
105804
|
+
const outcome = yield* lookupGitHubRepositoryForSession({
|
|
105805
|
+
sessionId: currentSessionId,
|
|
105806
|
+
subject: currentUserId,
|
|
105807
|
+
runtimeGrantAuth: null,
|
|
105808
|
+
repository: input.repository
|
|
105809
|
+
});
|
|
105810
|
+
if (outcome.repository === null) return yield* new SourceControlRepositoryError({
|
|
105811
|
+
provider: "github",
|
|
105812
|
+
operation: "lookupRepository",
|
|
105813
|
+
detail: outcome.error ?? "Repository lookup failed."
|
|
105814
|
+
});
|
|
105815
|
+
return {
|
|
105816
|
+
provider: "github",
|
|
105817
|
+
...outcome.repository
|
|
105818
|
+
};
|
|
105819
|
+
}), { "rpc.aggregate": "sourceControl" }),
|
|
105820
|
+
[WS_METHODS.sourceControlCloneRepository]: (input) => observeRpcEffect(WS_METHODS.sourceControlCloneRepository, gen(function* () {
|
|
105821
|
+
const provider = input.provider ?? "github";
|
|
105822
|
+
const repoFullName = resolveGitHubCloneTarget(input);
|
|
105823
|
+
const refuse = (detail) => new SourceControlRepositoryError({
|
|
105824
|
+
provider,
|
|
105825
|
+
operation: "cloneRepository",
|
|
105826
|
+
detail
|
|
105827
|
+
});
|
|
105828
|
+
if (provider !== "github") return yield* refuse(`Forge can only clone GitHub repositories. ${provider} is not connected.`);
|
|
105829
|
+
if (currentUserId === void 0) return yield* refuse("Sign in to Forge before cloning a repository.");
|
|
105830
|
+
if (repoFullName === null) return yield* refuse("Name the repository as owner/name, or paste a github.com clone URL.");
|
|
105831
|
+
const outcome = yield* runGitHubCloneForSession({
|
|
105832
|
+
config,
|
|
105833
|
+
sessionId: currentSessionId,
|
|
105834
|
+
subject: currentUserId,
|
|
105835
|
+
runtimeGrantAuth: null,
|
|
105836
|
+
repoFullName,
|
|
105837
|
+
targetDir: input.destinationPath
|
|
105838
|
+
});
|
|
105839
|
+
const localPath = outcome.body.local_path;
|
|
105840
|
+
if (outcome.status !== 200 || typeof localPath !== "string") {
|
|
105841
|
+
const detail = outcome.body.error;
|
|
105842
|
+
return yield* refuse(typeof detail === "string" ? detail : "Cloning the repository failed.");
|
|
105843
|
+
}
|
|
105844
|
+
const repository = describeGitHubRepository(repoFullName);
|
|
105845
|
+
return {
|
|
105846
|
+
cwd: localPath,
|
|
105847
|
+
remoteUrl: repository.url,
|
|
105848
|
+
repository: {
|
|
105849
|
+
provider: "github",
|
|
105850
|
+
...repository
|
|
105851
|
+
}
|
|
105852
|
+
};
|
|
105853
|
+
}), { "rpc.aggregate": "sourceControl" })
|
|
105018
105854
|
});
|
|
105019
105855
|
}));
|
|
105020
105856
|
const websocketRpcRouteLayer = unwrap(succeed(mergeAll(add$1("GET", "/ws", gen(function* () {
|
|
@@ -116091,8 +116927,8 @@ effectDiscard(runMigrations());
|
|
|
116091
116927
|
//#endregion
|
|
116092
116928
|
//#region src/persistence/Layers/Sqlite.ts
|
|
116093
116929
|
const defaultSqliteClientLoaders = {
|
|
116094
|
-
bun: () => import("./SqliteClient-
|
|
116095
|
-
node: () => import("./NodeSqliteClient-
|
|
116930
|
+
bun: () => import("./SqliteClient-DTWCGkrj.mjs"),
|
|
116931
|
+
node: () => import("./NodeSqliteClient-DqFjB3u_.mjs")
|
|
116096
116932
|
};
|
|
116097
116933
|
const makeRuntimeSqliteLayer = fn$1("makeRuntimeSqliteLayer")(function* (config) {
|
|
116098
116934
|
const loader = defaultSqliteClientLoaders[process.versions.bun !== void 0 ? "bun" : "node"];
|
|
@@ -188943,7 +189779,7 @@ var Vce = {
|
|
|
188943
189779
|
function Ve() {
|
|
188944
189780
|
return Vce;
|
|
188945
189781
|
}
|
|
188946
|
-
var Us =
|
|
189782
|
+
var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
188947
189783
|
let t = path.join(Us, "Library");
|
|
188948
189784
|
return {
|
|
188949
189785
|
data: path.join(t, "Application Support", e),
|
|
@@ -199143,12 +199979,12 @@ function qZ(e, t) {
|
|
|
199143
199979
|
}
|
|
199144
199980
|
return n;
|
|
199145
199981
|
}
|
|
199146
|
-
var os$
|
|
199982
|
+
var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
199147
199983
|
{
|
|
199148
199984
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
199149
199985
|
tip: {
|
|
199150
199986
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
199151
|
-
docLink: `${os$
|
|
199987
|
+
docLink: `${os$1}/iam#permission-modes`
|
|
199152
199988
|
}
|
|
199153
199989
|
},
|
|
199154
199990
|
{
|
|
@@ -199163,7 +199999,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
199163
199999
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
199164
200000
|
tip: {
|
|
199165
200001
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
199166
|
-
docLink: `${os$
|
|
200002
|
+
docLink: `${os$1}/settings#environment-variables`
|
|
199167
200003
|
}
|
|
199168
200004
|
},
|
|
199169
200005
|
{
|
|
@@ -199174,14 +200010,14 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
199174
200010
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
199175
200011
|
tip: {
|
|
199176
200012
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
199177
|
-
docLink: `${os$
|
|
200013
|
+
docLink: `${os$1}/hooks`
|
|
199178
200014
|
}
|
|
199179
200015
|
},
|
|
199180
200016
|
{
|
|
199181
200017
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
199182
200018
|
tip: {
|
|
199183
200019
|
suggestion: "Command hooks require `command`. For exec form (no shell), set `command` to the executable and `args` to its arguments: {\"type\": \"command\", \"command\": \"echo\", \"args\": [\"hi\"]}. For shell form, set `command` to the full shell string: {\"type\": \"command\", \"command\": \"echo hi\"}.",
|
|
199184
|
-
docLink: `${os$
|
|
200020
|
+
docLink: `${os$1}/hooks#exec-form-and-shell-form`
|
|
199185
200021
|
}
|
|
199186
200022
|
},
|
|
199187
200023
|
{
|
|
@@ -199196,7 +200032,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
199196
200032
|
matches: (e) => e.code === "unrecognized_keys",
|
|
199197
200033
|
tip: {
|
|
199198
200034
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
199199
|
-
docLink: `${os$
|
|
200035
|
+
docLink: `${os$1}/settings`
|
|
199200
200036
|
}
|
|
199201
200037
|
},
|
|
199202
200038
|
{
|
|
@@ -199211,13 +200047,13 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
199211
200047
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
199212
200048
|
tip: {
|
|
199213
200049
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
199214
|
-
docLink: `${os$
|
|
200050
|
+
docLink: `${os$1}/iam#working-directories`
|
|
199215
200051
|
}
|
|
199216
200052
|
}
|
|
199217
200053
|
], AKe = {
|
|
199218
|
-
permissions: `${os$
|
|
199219
|
-
env: `${os$
|
|
199220
|
-
hooks: `${os$
|
|
200054
|
+
permissions: `${os$1}/iam#configuring-permissions`,
|
|
200055
|
+
env: `${os$1}/settings#environment-variables`,
|
|
200056
|
+
hooks: `${os$1}/hooks`
|
|
199221
200057
|
};
|
|
199222
200058
|
function GZ(e) {
|
|
199223
200059
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -265914,7 +266750,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
265914
266750
|
var dgram = __require("dgram");
|
|
265915
266751
|
var thunky = require_thunky();
|
|
265916
266752
|
var events = __require("events");
|
|
265917
|
-
var os
|
|
266753
|
+
var os = __require("os");
|
|
265918
266754
|
var noop = function() {};
|
|
265919
266755
|
module.exports = function(opts) {
|
|
265920
266756
|
if (!opts) opts = {};
|
|
@@ -266045,14 +266881,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
266045
266881
|
return that;
|
|
266046
266882
|
};
|
|
266047
266883
|
function defaultInterface() {
|
|
266048
|
-
var networks = os
|
|
266884
|
+
var networks = os.networkInterfaces();
|
|
266049
266885
|
var names = Object.keys(networks);
|
|
266050
266886
|
for (var i = 0; i < names.length; i++) {
|
|
266051
266887
|
var net = networks[names[i]];
|
|
266052
266888
|
for (var j = 0; j < net.length; j++) {
|
|
266053
266889
|
var iface = net[j];
|
|
266054
266890
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
266055
|
-
if (os
|
|
266891
|
+
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
266056
266892
|
return "0.0.0.0";
|
|
266057
266893
|
}
|
|
266058
266894
|
}
|
|
@@ -266060,7 +266896,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
266060
266896
|
return "127.0.0.1";
|
|
266061
266897
|
}
|
|
266062
266898
|
function allInterfaces() {
|
|
266063
|
-
var networks = os
|
|
266899
|
+
var networks = os.networkInterfaces();
|
|
266064
266900
|
var names = Object.keys(networks);
|
|
266065
266901
|
var res = [];
|
|
266066
266902
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -286952,6 +287788,7 @@ function taskStartedToActivities(event) {
|
|
|
286952
287788
|
summary: taskStartedSummary(event.payload.taskType),
|
|
286953
287789
|
payload: {
|
|
286954
287790
|
taskId: event.payload.taskId,
|
|
287791
|
+
agentKind: classifyTaskAgentKind({ taskType: event.payload.taskType }),
|
|
286955
287792
|
...event.payload.taskType ? { taskType: event.payload.taskType } : {},
|
|
286956
287793
|
...event.payload.description ? { detail: truncateDetail(event.payload.description) } : {}
|
|
286957
287794
|
}
|
|
@@ -294759,7 +295596,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
294759
295596
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
294760
295597
|
*/
|
|
294761
295598
|
function readBakedBuildCommit() {
|
|
294762
|
-
return "
|
|
295599
|
+
return "c220fa73834b4651c7fc65f272c171028edc3e81";
|
|
294763
295600
|
}
|
|
294764
295601
|
async function resolveServerBuildCommit(input) {
|
|
294765
295602
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -294876,6 +295713,7 @@ function executionEnvironmentCapabilities(serverConfig) {
|
|
|
294876
295713
|
pullRequests: isExecutionPlane,
|
|
294877
295714
|
threadPullRequestLinking: isExecutionPlane,
|
|
294878
295715
|
threadSettlement: isExecutionPlane,
|
|
295716
|
+
threadTitleRegeneration: isExecutionPlane,
|
|
294879
295717
|
cloudMode: serverConfig.forgeCmmdRuntimeMode === true || isCloudShell,
|
|
294880
295718
|
runtime: {
|
|
294881
295719
|
topology: runtimeTopology(serverConfig),
|
|
@@ -295154,10 +295992,6 @@ const pulseSignalStateUpsertRouteLayer = add$1("POST", "/api/pulse/signals/state
|
|
|
295154
295992
|
});
|
|
295155
295993
|
}).pipe(catchTag("AuthError", respondToAuthError)));
|
|
295156
295994
|
//#endregion
|
|
295157
|
-
//#region src/auth/Services/ServerSecretStore.ts
|
|
295158
|
-
var SecretStoreError = class extends TaggedError("SecretStoreError") {};
|
|
295159
|
-
var ServerSecretStore = class extends Service$1()("forge/auth/Services/ServerSecretStore") {};
|
|
295160
|
-
//#endregion
|
|
295161
295995
|
//#region src/auth/Layers/ServerSecretStore.ts
|
|
295162
295996
|
const OWNED_FILE_RECEIPT_PREFIX = "forge-owned-secret-receipt:v1:";
|
|
295163
295997
|
const LEGACY_FILE_SECRET_NAMESPACE_PREFIX = "forge-secret-namespace:v1:";
|
|
@@ -301496,6 +302330,55 @@ const ProjectionCountsRowSchema = Struct({
|
|
|
301496
302330
|
const WorkspaceRootLookupInput = Struct({ workspaceRoot: String$1 });
|
|
301497
302331
|
const ProjectIdLookupInput = Struct({ projectId: ProjectId });
|
|
301498
302332
|
const ThreadIdLookupInput = Struct({ threadId: ThreadId });
|
|
302333
|
+
const ThreadSearchQueryInput = Struct({
|
|
302334
|
+
pattern: String$1,
|
|
302335
|
+
limit: Number$1
|
|
302336
|
+
});
|
|
302337
|
+
const ThreadSearchMessageRowSchema = Struct({
|
|
302338
|
+
threadId: ThreadId,
|
|
302339
|
+
projectId: ProjectId,
|
|
302340
|
+
role: String$1,
|
|
302341
|
+
text: String$1,
|
|
302342
|
+
createdAt: IsoDateTime
|
|
302343
|
+
});
|
|
302344
|
+
const ThreadSearchMetadataRowSchema = Struct({
|
|
302345
|
+
threadId: ThreadId,
|
|
302346
|
+
projectId: ProjectId,
|
|
302347
|
+
title: String$1,
|
|
302348
|
+
branch: NullOr(String$1)
|
|
302349
|
+
});
|
|
302350
|
+
/** The contract caps a snippet at this length, so the server must too. */
|
|
302351
|
+
const THREAD_SEARCH_SNIPPET_LIMIT = 240;
|
|
302352
|
+
/** How many matches a search returns when the caller does not say. */
|
|
302353
|
+
const THREAD_SEARCH_DEFAULT_LIMIT = 20;
|
|
302354
|
+
/**
|
|
302355
|
+
* `LIKE` treats `%` and `_` as wildcards, so a person searching for a literal
|
|
302356
|
+
* underscore (every other identifier in a codebase) would otherwise match any
|
|
302357
|
+
* character. Escaped with a backslash, declared to SQL as `ESCAPE '\'`, and
|
|
302358
|
+
* lowercased on both sides because Postgres `LIKE` is case-sensitive where
|
|
302359
|
+
* SQLite's is not, and Forge runs on both.
|
|
302360
|
+
*/
|
|
302361
|
+
function toThreadSearchPattern(query) {
|
|
302362
|
+
return `%${query.toLowerCase().replace(/[\\%_]/g, (character) => `\\${character}`)}%`;
|
|
302363
|
+
}
|
|
302364
|
+
/**
|
|
302365
|
+
* A window of the text around the first hit, not the head of it.
|
|
302366
|
+
*
|
|
302367
|
+
* A match 4000 characters into an assistant message is invisible in a snippet
|
|
302368
|
+
* that always starts at character zero, which is the difference between a
|
|
302369
|
+
* result a person can recognize and a result they have to open to understand.
|
|
302370
|
+
*/
|
|
302371
|
+
function buildThreadSearchSnippet(text, lowerQuery) {
|
|
302372
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
302373
|
+
if (collapsed.length <= THREAD_SEARCH_SNIPPET_LIMIT) return collapsed;
|
|
302374
|
+
const matchIndex = collapsed.toLowerCase().indexOf(lowerQuery);
|
|
302375
|
+
if (matchIndex < 0) return `${collapsed.slice(0, THREAD_SEARCH_SNIPPET_LIMIT - 1)}…`;
|
|
302376
|
+
const leading = Math.floor((THREAD_SEARCH_SNIPPET_LIMIT - lowerQuery.length) / 2);
|
|
302377
|
+
const start = Math.max(0, matchIndex - Math.max(leading, 0));
|
|
302378
|
+
const windowed = collapsed.slice(start, start + THREAD_SEARCH_SNIPPET_LIMIT);
|
|
302379
|
+
const prefixed = start > 0 ? `…${windowed}` : windowed;
|
|
302380
|
+
return prefixed.length > THREAD_SEARCH_SNIPPET_LIMIT ? prefixed.slice(0, THREAD_SEARCH_SNIPPET_LIMIT) : prefixed;
|
|
302381
|
+
}
|
|
301499
302382
|
const ProjectionProjectLookupRowSchema = ProjectionProjectDbRowSchema;
|
|
301500
302383
|
const ProjectionThreadIdLookupRowSchema = Struct({ threadId: ThreadId });
|
|
301501
302384
|
const ProjectionThreadCheckpointContextThreadRowSchema = Struct({
|
|
@@ -301741,6 +302624,61 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
|
|
|
301741
302624
|
AND deleted_at IS NULL
|
|
301742
302625
|
AND archived_at IS NULL
|
|
301743
302626
|
ORDER BY created_at ASC, thread_id ASC
|
|
302627
|
+
`
|
|
302628
|
+
});
|
|
302629
|
+
/**
|
|
302630
|
+
* Message bodies containing the query.
|
|
302631
|
+
*
|
|
302632
|
+
* `role IN ('user', 'assistant')` is not a filter for tidiness: the match
|
|
302633
|
+
* shape on the wire names one of those two as the side the hit came from,
|
|
302634
|
+
* and a system message has no side to report. Ordered newest first because a
|
|
302635
|
+
* capped search should keep what the person is most likely still thinking
|
|
302636
|
+
* about.
|
|
302637
|
+
*/
|
|
302638
|
+
const searchThreadMessageRows = findAll({
|
|
302639
|
+
Request: ThreadSearchQueryInput,
|
|
302640
|
+
Result: ThreadSearchMessageRowSchema,
|
|
302641
|
+
execute: ({ pattern, limit }) => sql`
|
|
302642
|
+
SELECT
|
|
302643
|
+
m.thread_id AS "threadId",
|
|
302644
|
+
t.project_id AS "projectId",
|
|
302645
|
+
m.role AS "role",
|
|
302646
|
+
m.text AS "text",
|
|
302647
|
+
m.created_at AS "createdAt"
|
|
302648
|
+
FROM projection_thread_messages AS m
|
|
302649
|
+
JOIN projection_threads AS t ON t.thread_id = m.thread_id
|
|
302650
|
+
WHERE t.deleted_at IS NULL
|
|
302651
|
+
AND m.role IN ('user', 'assistant')
|
|
302652
|
+
AND LOWER(m.text) LIKE ${pattern} ESCAPE '\\'
|
|
302653
|
+
ORDER BY m.created_at DESC, m.message_id ASC
|
|
302654
|
+
LIMIT ${limit}
|
|
302655
|
+
`
|
|
302656
|
+
});
|
|
302657
|
+
/**
|
|
302658
|
+
* Threads whose own metadata contains the query.
|
|
302659
|
+
*
|
|
302660
|
+
* Title and branch, which is what the web command palette matches on. Title
|
|
302661
|
+
* is duplicated work for a client that already filters its in-memory list,
|
|
302662
|
+
* and harmless because matches are deduplicated by thread; branch is not,
|
|
302663
|
+
* because no client holds every branch.
|
|
302664
|
+
*/
|
|
302665
|
+
const searchThreadMetadataRows = findAll({
|
|
302666
|
+
Request: ThreadSearchQueryInput,
|
|
302667
|
+
Result: ThreadSearchMetadataRowSchema,
|
|
302668
|
+
execute: ({ pattern, limit }) => sql`
|
|
302669
|
+
SELECT
|
|
302670
|
+
thread_id AS "threadId",
|
|
302671
|
+
project_id AS "projectId",
|
|
302672
|
+
title,
|
|
302673
|
+
branch
|
|
302674
|
+
FROM projection_threads
|
|
302675
|
+
WHERE deleted_at IS NULL
|
|
302676
|
+
AND (
|
|
302677
|
+
LOWER(title) LIKE ${pattern} ESCAPE '\\'
|
|
302678
|
+
OR LOWER(branch) LIKE ${pattern} ESCAPE '\\'
|
|
302679
|
+
)
|
|
302680
|
+
ORDER BY updated_at DESC, thread_id ASC
|
|
302681
|
+
LIMIT ${limit}
|
|
301744
302682
|
`
|
|
301745
302683
|
});
|
|
301746
302684
|
/**
|
|
@@ -302487,6 +303425,40 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
|
|
|
302487
303425
|
};
|
|
302488
303426
|
const getShellSnapshot = () => readShellSnapshot("getShellSnapshot", listThreadRows);
|
|
302489
303427
|
const getArchivedShellSnapshot = () => readShellSnapshot("getArchivedShellSnapshot", listArchivedThreadRows);
|
|
303428
|
+
const searchThreads = (input) => {
|
|
303429
|
+
const limit = input.limit ?? THREAD_SEARCH_DEFAULT_LIMIT;
|
|
303430
|
+
const lowerQuery = input.query.toLowerCase();
|
|
303431
|
+
const request = {
|
|
303432
|
+
pattern: toThreadSearchPattern(input.query),
|
|
303433
|
+
limit
|
|
303434
|
+
};
|
|
303435
|
+
return all([searchThreadMessageRows(request).pipe(mapError(toPersistenceSqlOrDecodeError("ProjectionSnapshotQuery.searchThreads:messages:query", "ProjectionSnapshotQuery.searchThreads:messages:decodeRows"))), searchThreadMetadataRows(request).pipe(mapError(toPersistenceSqlOrDecodeError("ProjectionSnapshotQuery.searchThreads:metadata:query", "ProjectionSnapshotQuery.searchThreads:metadata:decodeRows")))]).pipe(map$3(([messageRows, metadataRows]) => {
|
|
303436
|
+
const byThread = /* @__PURE__ */ new Map();
|
|
303437
|
+
for (const row of messageRows) {
|
|
303438
|
+
if (byThread.has(row.threadId)) continue;
|
|
303439
|
+
byThread.set(row.threadId, {
|
|
303440
|
+
threadId: row.threadId,
|
|
303441
|
+
projectId: row.projectId,
|
|
303442
|
+
source: row.role === "assistant" ? "assistant" : "user",
|
|
303443
|
+
snippet: buildThreadSearchSnippet(row.text, lowerQuery),
|
|
303444
|
+
messageCreatedAt: row.createdAt
|
|
303445
|
+
});
|
|
303446
|
+
}
|
|
303447
|
+
for (const row of metadataRows) {
|
|
303448
|
+
if (byThread.has(row.threadId)) continue;
|
|
303449
|
+
const branchMatched = row.branch?.toLowerCase().includes(lowerQuery) === true;
|
|
303450
|
+
const titleMatched = row.title.toLowerCase().includes(lowerQuery);
|
|
303451
|
+
byThread.set(row.threadId, {
|
|
303452
|
+
threadId: row.threadId,
|
|
303453
|
+
projectId: row.projectId,
|
|
303454
|
+
source: "user",
|
|
303455
|
+
snippet: buildThreadSearchSnippet(titleMatched || !branchMatched ? row.title : row.branch ?? row.title, lowerQuery),
|
|
303456
|
+
messageCreatedAt: null
|
|
303457
|
+
});
|
|
303458
|
+
}
|
|
303459
|
+
return { matches: [...byThread.values()].slice(0, limit) };
|
|
303460
|
+
}));
|
|
303461
|
+
};
|
|
302490
303462
|
const listActiveWorkerShells = () => sql.withTransaction(all([
|
|
302491
303463
|
listActiveWorkerThreadRows(void 0).pipe(mapError(toPersistenceSqlOrDecodeError("ProjectionSnapshotQuery.listActiveWorkerShells:listThreads:query", "ProjectionSnapshotQuery.listActiveWorkerShells:listThreads:decodeRows"))),
|
|
302492
303464
|
listActiveWorkerSessionRows(void 0).pipe(mapError(toPersistenceSqlOrDecodeError("ProjectionSnapshotQuery.listActiveWorkerShells:listThreadSessions:query", "ProjectionSnapshotQuery.listActiveWorkerShells:listThreadSessions:decodeRows"))),
|
|
@@ -302654,6 +303626,7 @@ const OrchestrationInfrastructureLayerLive = mergeAll(effect(ProjectionSnapshotQ
|
|
|
302654
303626
|
getSnapshot,
|
|
302655
303627
|
getShellSnapshot,
|
|
302656
303628
|
getArchivedShellSnapshot,
|
|
303629
|
+
searchThreads,
|
|
302657
303630
|
listActiveWorkerShells,
|
|
302658
303631
|
listStaleRunningSessionShells,
|
|
302659
303632
|
getCounts,
|
|
@@ -317836,13 +318809,13 @@ const gitUrlCloneRouteLayer = add$1("POST", "/api/cloud/git/clone-url", gen(func
|
|
|
317836
318809
|
//#endregion
|
|
317837
318810
|
//#region src/server.ts
|
|
317838
318811
|
const PtyAdapterLive = unwrap(gen(function* () {
|
|
317839
|
-
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunPTY-
|
|
317840
|
-
else return (yield* promise(() => import("./NodePTY-
|
|
318812
|
+
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunPTY-DkAIzLIx.mjs"))).layer;
|
|
318813
|
+
else return (yield* promise(() => import("./NodePTY-loxi8Vku.mjs"))).layer;
|
|
317841
318814
|
}));
|
|
317842
318815
|
const HttpServerLive = unwrap(gen(function* () {
|
|
317843
318816
|
const config = yield* ServerConfig;
|
|
317844
|
-
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunHttpServer-
|
|
317845
|
-
const [NodeHttpServer, NodeHttp] = yield* all([promise(() => import("./NodeHttpServer-
|
|
318817
|
+
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunHttpServer-CDh4Vioe.mjs"))).layer(bunHttpServerOptions(config));
|
|
318818
|
+
const [NodeHttpServer, NodeHttp] = yield* all([promise(() => import("./NodeHttpServer-DT0TF8s4.mjs")), promise(() => import("node:http"))]);
|
|
317846
318819
|
return NodeHttpServer.layer(NodeHttp.createServer, {
|
|
317847
318820
|
host: config.host,
|
|
317848
318821
|
port: config.port
|
|
@@ -317850,10 +318823,10 @@ const HttpServerLive = unwrap(gen(function* () {
|
|
|
317850
318823
|
}));
|
|
317851
318824
|
const PlatformServicesLive = unwrap(gen(function* () {
|
|
317852
318825
|
if (typeof Bun !== "undefined") {
|
|
317853
|
-
const { layer } = yield* promise(() => import("./BunServices-
|
|
318826
|
+
const { layer } = yield* promise(() => import("./BunServices-D6PAheqS.mjs"));
|
|
317854
318827
|
return layer;
|
|
317855
318828
|
} else {
|
|
317856
|
-
const { layer } = yield* promise(() => import("./NodeServices-
|
|
318829
|
+
const { layer } = yield* promise(() => import("./NodeServices-BahzLhbo.mjs").then((n) => n.t));
|
|
317857
318830
|
return layer;
|
|
317858
318831
|
}
|
|
317859
318832
|
}));
|
|
@@ -318848,7 +319821,7 @@ const connectLoginCommand = make$34("login", {
|
|
|
318848
319821
|
})).json();
|
|
318849
319822
|
},
|
|
318850
319823
|
openBrowser: async (url) => {
|
|
318851
|
-
const open = (await import("./open-
|
|
319824
|
+
const open = (await import("./open-D8mGyWmt.mjs")).default;
|
|
318852
319825
|
await open(url);
|
|
318853
319826
|
return true;
|
|
318854
319827
|
},
|