akanjs 3.1.0-rc.0 → 3.1.0-rc.1
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/client/csrTypes.ts +4 -0
- package/dictionary/base.dictionary.ts +4 -0
- package/package.json +1 -1
- package/service/adapt.ts +1 -1
- package/store/action.ts +17 -19
- package/types/client/csrTypes.d.ts +3 -0
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictionary.d.ts +3 -3
- package/types/service/adapt.d.ts +1 -1
- package/types/ui/Layout/BottomInset.d.ts +1 -1
- package/types/ui/Layout/Navbar.d.ts +1 -1
- package/types/ui/Layout/TopInset.d.ts +2 -2
- package/types/ui/Layout/index.d.ts +4 -4
- package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +5 -4
- package/types/vendor/@akanjs/native/packages/desktop/src/dispatcher.d.ts +6 -0
- package/types/vendor/@akanjs/native/plugins/single-instance/src/socket.d.ts +1 -1
- package/types/vendor/use-agentic/AgentActivity.d.ts +3 -1
- package/types/vendor/use-agentic/AgenticSurface.d.ts +2 -2
- package/types/webkit/EmbeddedLayout.d.ts +10 -0
- package/types/webkit/RenderLayer.d.ts +3 -1
- package/ui/Layout/BottomInset.tsx +12 -2
- package/ui/Layout/Navbar.tsx +22 -7
- package/ui/Layout/TopInset.tsx +7 -3
- package/ui/Model/ViewEditModal.tsx +16 -10
- package/ui/Select.tsx +12 -7
- package/ui/System/CSR.tsx +7 -1
- package/ui/System/Client.tsx +1 -0
- package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +35 -10
- package/vendor/@akanjs/native/packages/desktop/src/dispatcher.ts +13 -5
- package/vendor/@akanjs/native/plugins/single-instance/src/desktop.ts +4 -0
- package/vendor/@akanjs/native/plugins/single-instance/src/socket.ts +12 -5
- package/vendor/use-agentic/AgentActivity.tsx +4 -2
- package/vendor/use-agentic/AgenticSurface.ts +3 -3
- package/webkit/CsrRouteTable.ts +8 -1
- package/webkit/EmbeddedLayout.tsx +77 -0
- package/webkit/RenderLayer.tsx +20 -5
package/client/csrTypes.ts
CHANGED
|
@@ -364,6 +364,10 @@ export const usePathCtx = () => {
|
|
|
364
364
|
return contextValues;
|
|
365
365
|
};
|
|
366
366
|
|
|
367
|
+
/** Inside a layout's own markup that an MCP view hides while the page is drawn on its own: frame chrome draws nothing. */
|
|
368
|
+
export const hiddenLayoutContext = sharedContext<boolean>("hiddenLayout", false);
|
|
369
|
+
export const useInHiddenLayout = () => useContext(hiddenLayoutContext);
|
|
370
|
+
|
|
367
371
|
export type PageActivity = "current" | "prev" | "pending" | "hidden";
|
|
368
372
|
export interface PageActivityState {
|
|
369
373
|
activity: PageActivity;
|
|
@@ -57,6 +57,10 @@ export const baseDictionary = serviceDictionary(["en", "ko"])
|
|
|
57
57
|
"The same request is still being handled. Please try again in a moment.",
|
|
58
58
|
"같은 요청을 아직 처리하고 있습니다. 잠시 후 다시 시도해주세요.",
|
|
59
59
|
],
|
|
60
|
+
endpointClosed: [
|
|
61
|
+
"{endpoint} is closed: the slice's guards name none that allows it.",
|
|
62
|
+
"{endpoint}이(가) 닫혀 있습니다. 슬라이스 guards에 이 동작을 허용하는 guard를 지정해야 합니다.",
|
|
63
|
+
],
|
|
60
64
|
})
|
|
61
65
|
.translate({
|
|
62
66
|
somethingWrong: ["Something's wrong!", "문제가 생겼어요!"],
|
package/package.json
CHANGED
package/service/adapt.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type AdaptorCls<Methods = any, InjectMap extends Record<string, InjectInf
|
|
|
13
13
|
{ readonly [INJECT_META]: InjectMap; readonly refName: string }
|
|
14
14
|
>;
|
|
15
15
|
|
|
16
|
-
export function adapt<Name extends string>(name: Name): AdaptorCls
|
|
16
|
+
export function adapt<Name extends string>(name: Name): AdaptorCls<{}>;
|
|
17
17
|
|
|
18
18
|
export function adapt<Name extends string, Injection extends InjectBuilder<"use" | "env" | "memory" | "plug">>(
|
|
19
19
|
name: Name,
|
package/store/action.ts
CHANGED
|
@@ -510,6 +510,15 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
510
510
|
const updatedAt = (model as unknown as { updatedAt?: { toISOString?: () => string } }).updatedAt;
|
|
511
511
|
return typeof updatedAt?.toISOString === "function" ? updatedAt.toISOString() : null;
|
|
512
512
|
};
|
|
513
|
+
|
|
514
|
+
const servedFetch = <T>(key: string) => {
|
|
515
|
+
const fn = fetch[key] as ((...args: any[]) => Promise<T>) | undefined;
|
|
516
|
+
if (typeof fn === "function") return fn;
|
|
517
|
+
throw Object.assign(new Error(`${key} is closed: the slice's guards name none that allows it`), {
|
|
518
|
+
error: "base.error.endpointClosed",
|
|
519
|
+
data: { endpoint: key },
|
|
520
|
+
});
|
|
521
|
+
};
|
|
513
522
|
function armDraft(this: SetGet, draftScope: string | undefined, form: object, baseUpdatedAt: string | null) {
|
|
514
523
|
openFormBase = draftScope ? form : null;
|
|
515
524
|
if (!draftScope) return null;
|
|
@@ -598,7 +607,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
598
607
|
|
|
599
608
|
if (!modelInput) return;
|
|
600
609
|
this.set({ [names.modelLoading]: true });
|
|
601
|
-
const model = await (
|
|
610
|
+
const model = await servedFetch<Full>(names.createModel)(modelInput, { onError });
|
|
602
611
|
this.set({
|
|
603
612
|
[names.modelForm]: immerify(modelRef, defaultModel),
|
|
604
613
|
[names.modelDraft]: clearDraft(currentState[names.modelDraft] as DraftState | null),
|
|
@@ -623,11 +632,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
623
632
|
const modelInput = (cnst.input.purify as (form: any) => DefaultOf<Input> | null)(modelForm);
|
|
624
633
|
if (!modelInput) return;
|
|
625
634
|
if (model?.id === modelForm.id) this.set({ [names.modelLoading]: modelForm.id });
|
|
626
|
-
const updatedModel = await (
|
|
627
|
-
modelForm.id,
|
|
628
|
-
modelInput,
|
|
629
|
-
{ onError },
|
|
630
|
-
);
|
|
635
|
+
const updatedModel = await servedFetch<Full>(names.updateModel)(modelForm.id, modelInput, { onError });
|
|
631
636
|
this.set({
|
|
632
637
|
...(model?.id === updatedModel.id
|
|
633
638
|
? { [names.model]: updatedModel, [names.modelLoading]: false, [names.modelViewAt]: new Date() }
|
|
@@ -650,7 +655,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
650
655
|
const modelInput = (cnst.input.purify as (data: any) => Input | null)(data);
|
|
651
656
|
if (!modelInput) return;
|
|
652
657
|
this.set({ [names.modelLoading]: true });
|
|
653
|
-
const model = await (
|
|
658
|
+
const model = await servedFetch<Full>(names.createModel)(modelInput, { onError });
|
|
654
659
|
this.set({
|
|
655
660
|
[names.model]: model,
|
|
656
661
|
[names.modelLoading]: false,
|
|
@@ -673,7 +678,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
673
678
|
const modelInput = (cnst.input.purify as (data: any) => DefaultOf<Input> | null)(data);
|
|
674
679
|
if (!modelInput) return;
|
|
675
680
|
if (model?.id === id) this.set({ [names.modelLoading]: id });
|
|
676
|
-
const updatedModel = await (
|
|
681
|
+
const updatedModel = await servedFetch<Full>(names.updateModel)(id, modelInput, {
|
|
677
682
|
onError,
|
|
678
683
|
});
|
|
679
684
|
this.set({
|
|
@@ -689,10 +694,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
689
694
|
},
|
|
690
695
|
[names.removeModel]: async function (this: SetGet, id: string, options?: FetchPolicy & { modal?: string | null }) {
|
|
691
696
|
const { modal, ...fetchPolicyOptions } = options ?? {};
|
|
692
|
-
const model = await
|
|
693
|
-
id,
|
|
694
|
-
fetchPolicyOptions,
|
|
695
|
-
);
|
|
697
|
+
const model = await servedFetch<Full & { removedAt: Dayjs | null }>(names.removeModel)(id, fetchPolicyOptions);
|
|
696
698
|
const lightModel = new cnst.light().set(model) as unknown as Light;
|
|
697
699
|
slices.forEach(({ keys: { state: namesOfSlice } }) => {
|
|
698
700
|
const currentState = this.get() as { [key: string]: any };
|
|
@@ -776,7 +778,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
776
778
|
) {
|
|
777
779
|
const id = typeof modelOrId === "string" ? modelOrId : modelOrId.id;
|
|
778
780
|
this.set({ [names.modelFormLoading]: id, [names.modelModal]: modal ?? "edit" });
|
|
779
|
-
const model = await (
|
|
781
|
+
const model = await servedFetch<Full>(names.model)(id, { onError });
|
|
780
782
|
const modelForm = immerify(modelRef, deepObjectify<Input>(model as unknown as Input) as object) as Input;
|
|
781
783
|
this.set({
|
|
782
784
|
[names.model]: model,
|
|
@@ -798,11 +800,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
798
800
|
const currentState = this.get() as { [key: string]: any };
|
|
799
801
|
const model = currentState[names.model] as Full | null;
|
|
800
802
|
if (id === model?.id) this.set({ modelLoading: id });
|
|
801
|
-
const updatedModel = await (
|
|
802
|
-
modelOrId,
|
|
803
|
-
data,
|
|
804
|
-
options,
|
|
805
|
-
);
|
|
803
|
+
const updatedModel = await servedFetch<Full>(names.mergeModel)(modelOrId, data, options);
|
|
806
804
|
this.set({
|
|
807
805
|
[names.model]: id === model?.id ? updatedModel : model,
|
|
808
806
|
[names.modelLoading]: false,
|
|
@@ -817,7 +815,7 @@ export const makeActions = (refName: string, slice: { [key: string]: SerializedS
|
|
|
817
815
|
) {
|
|
818
816
|
const id = typeof modelOrId === "string" ? modelOrId : modelOrId.id;
|
|
819
817
|
this.set({ [names.modelModal]: modal ?? "view", [names.modelLoading]: id });
|
|
820
|
-
const model = await (
|
|
818
|
+
const model = await servedFetch<Full>(names.model)(id, { onError });
|
|
821
819
|
this.set({ [names.model]: model, [names.modelViewAt]: new Date(), [names.modelLoading]: false });
|
|
822
820
|
},
|
|
823
821
|
[names.setModel]: function (this: SetGet, ...fullOrLightModels: Full[]) {
|
|
@@ -348,6 +348,9 @@ export interface PathContextType {
|
|
|
348
348
|
}
|
|
349
349
|
export declare const pathContext: import("react").Context<PathContextType>;
|
|
350
350
|
export declare const usePathCtx: () => PathContextType;
|
|
351
|
+
/** Inside a layout's own markup that an MCP view hides while the page is drawn on its own: frame chrome draws nothing. */
|
|
352
|
+
export declare const hiddenLayoutContext: import("react").Context<boolean>;
|
|
353
|
+
export declare const useInHiddenLayout: () => boolean;
|
|
351
354
|
export type PageActivity = "current" | "prev" | "pending" | "hidden";
|
|
352
355
|
export interface PageActivityState {
|
|
353
356
|
activity: PageActivity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const baseDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "ping" | "pingBody" | "pingParam" | "pingQuery" | "wsPing" | "pubsubPing", "serverUnreachable" | "serverUnavailable" | "gatewayTimeout" | "tooManyRequests" | "unexpectedResponse" | "immutableField" | "relationNotFound" | "idempotencyInFlight", "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view">;
|
|
1
|
+
export declare const baseDictionary: import("./dictInfo.d.ts").ServiceDictInfo<[string, string], "ping" | "pingBody" | "pingParam" | "pingQuery" | "wsPing" | "pubsubPing", "serverUnreachable" | "serverUnavailable" | "gatewayTimeout" | "tooManyRequests" | "unexpectedResponse" | "immutableField" | "relationNotFound" | "idempotencyInFlight" | "endpointClosed", "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view">;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { AgentEndpoint, AgentTurn, BaseEndpoint } from "akanjs/signal";
|
|
2
2
|
export declare const dictionary: {
|
|
3
|
-
base: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view">, "base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound">;
|
|
3
|
+
base: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view">, "base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound" | "base.error.endpointClosed">;
|
|
4
4
|
agentTurn: import("./locale.d.ts").DictModule<import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc`, never>;
|
|
5
5
|
agent: import("./locale.d.ts").DictModule<import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, "agent.error.llmUnavailable" | "agent.error.llmRequestFailed" | "agent.error.contextOverflow" | "agent.error.quotaExceeded">;
|
|
6
6
|
};
|
|
7
|
-
export declare const Err: import("./trans.d.ts").ErrConstructor<"base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed" | "agent.error.contextOverflow" | "agent.error.quotaExceeded">, translate: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja", key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, data?: import("./trans.d.ts").TranslationData) => string, msg: {
|
|
7
|
+
export declare const Err: import("./trans.d.ts").ErrConstructor<"base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound" | "base.error.endpointClosed" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed" | "agent.error.contextOverflow" | "agent.error.quotaExceeded">, translate: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja", key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, data?: import("./trans.d.ts").TranslationData) => string, msg: {
|
|
8
8
|
error: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
9
9
|
info: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
10
10
|
warning: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
11
11
|
success: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
12
12
|
loading: (key: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, option?: import("./trans.d.ts").TransMessageOption) => void;
|
|
13
|
-
}, getDictionary: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed" | "agent.error.contextOverflow" | "agent.error.quotaExceeded";
|
|
13
|
+
}, getDictionary: (lang: "en" | "ko" | (string & {}) | "zhChs" | "zhCht" | "ja") => object, getAllDictionary: () => import("./trans.d.ts").RootDictionary, __Dict_Key__: import("./locale.d.ts").ServiceTranslatorKey<"base", BaseEndpoint, "edit" | "error" | "ok" | "retry" | "approve" | "remove" | "skip" | "success" | "unauthorized" | "save" | "refresh" | "password" | "agent" | "stop" | "connecting" | "send" | "somethingWrong" | "connected" | "serverDisconnected" | "refreshing" | "tryReconnecting" | "serverHasProblem" | "checkServerStatus" | "cameraPromptHeader" | "cameraPromptPhoto" | "cameraPromptPicture" | "cameraPromptCancel" | "failed" | "processing" | "processed" | "noData" | "invalidValueError" | "emailInvalidError" | "phoneInvalidError" | "cancel" | "pageLoadFailed" | "agentIntro" | "agentPlaceholder" | "agentClear" | "agentQuestion" | "agentToolCard" | "agentAnswer" | "agentListen" | "agentVoiceFailed" | "agentAttach" | "agentAttachRemove" | "agentAttachReading" | "agentReferenceRemove" | "agentReferenceFailed" | "agentAttachTooLarge" | "agentAttachUnsupported" | "agentAttachDuplicate" | "agentAttachTooMany" | "agentAttachTooMuch" | "agentAnswerNeeded" | "agentQueue" | "agentQueuePlaceholder" | "agentQueued" | "agentQueueEdit" | "agentQueueCancel" | "agentToolDone" | "agentToolFailed" | "agentToolRunning" | "agentToolResult" | "agentTokens" | "agentTokensOf" | "agentCompactsAt" | "agentSummarizing" | "agentContinue" | "agentKeepGoing" | "agentCmdNew" | "agentCmdRetry" | "agentCmdCompact" | "agentCmdCopy" | "agentCmdHelp" | "agentCmdTools" | "agentHelpIntro" | "agentHelpNote" | "agentNothingToRetry" | "agentNothingToCompact" | "agentCompacted" | "agentSummary" | "agentBusy" | "agentCopied" | "agentCopyFailed" | "agentToolsHead" | "agentToolsState" | "decline" | "confirmClose" | "textTooShortError" | "textTooLongError" | "selectTooShortError" | "selectTooLongError" | "numberTooSmallError" | "numberTooBigError" | "passwordNotMatchError" | "selectDateError" | "priceUnit" | "passwordConfirm" | "noOptions" | "noSelection" | "addModel" | "createModel" | "createSuccess" | "updateModel" | "removeModel" | "updateSuccess" | "removeSuccess" | "sureToRemove" | "irreversibleOps" | "typeNameToRemove" | "yesRemove" | "removeMsg" | "confirmMsg" | "perPage" | "cardView" | "tableView" | "exportCsv" | "exportJson" | "actions" | "draftConflict" | "draftApplied" | "draftRestore" | "draftDiscard" | "draftStartOver" | "new" | "view"> | import("./locale.d.ts").ScalarTranslatorKey<"agentTurn", AgentTurn, never> | `agentStop.${string}` | `agentStop.${string}.desc` | import("./locale.d.ts").ServiceTranslatorKey<"agent", AgentEndpoint, never>, __Error_Key__: "base.error.gatewayTimeout" | "base.error.tooManyRequests" | "base.error.serverUnavailable" | "base.error.serverUnreachable" | "base.error.idempotencyInFlight" | "base.error.unexpectedResponse" | "base.error.immutableField" | "base.error.relationNotFound" | "base.error.endpointClosed" | "agent.error.llmUnavailable" | "agent.error.llmRequestFailed" | "agent.error.contextOverflow" | "agent.error.quotaExceeded";
|
package/types/service/adapt.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export type AdaptorCls<Methods = any, InjectMap extends Record<string, InjectInf
|
|
|
10
10
|
readonly [INJECT_META]: InjectMap;
|
|
11
11
|
readonly refName: string;
|
|
12
12
|
}>;
|
|
13
|
-
export declare function adapt<Name extends string>(name: Name): AdaptorCls
|
|
13
|
+
export declare function adapt<Name extends string>(name: Name): AdaptorCls<{}>;
|
|
14
14
|
export declare function adapt<Name extends string, Injection extends InjectBuilder<"use" | "env" | "memory" | "plug">>(name: Name, injectBuilder: Injection): AdaptorCls<{}, ReturnType<Injection>>;
|
|
15
15
|
export declare function dangerouslyAdapt<Name extends string, Injection extends InjectBuilder>(name: Name, injectBuilder: Injection): AdaptorCls<{}, ReturnType<Injection>>;
|
|
@@ -11,4 +11,4 @@ export interface BottomInsetProps {
|
|
|
11
11
|
frameSource?: FrameSlotRegistration["source"];
|
|
12
12
|
frameCache?: boolean;
|
|
13
13
|
}
|
|
14
|
-
export declare const BottomInset: ({ className, children, keyboardSticky, contentAnchor, role, estimatedHeight, frameScope, frameSource, frameCache, }: BottomInsetProps) => import("react").JSX.Element;
|
|
14
|
+
export declare const BottomInset: ({ className, children, keyboardSticky, contentAnchor, role, estimatedHeight, frameScope, frameSource, frameCache, }: BottomInsetProps) => import("react").JSX.Element | null;
|
|
@@ -11,4 +11,4 @@ export interface NavbarProps {
|
|
|
11
11
|
left?: ReactNode;
|
|
12
12
|
right?: ReactNode;
|
|
13
13
|
}
|
|
14
|
-
export declare const Navbar: ({ back, backFallback, className, height, children, title, left, right, }: NavbarProps) => import("react").JSX.Element;
|
|
14
|
+
export declare const Navbar: ({ back, backFallback, className, height, children, title, left, right, }: NavbarProps) => import("react").JSX.Element | null;
|
|
@@ -4,9 +4,9 @@ export interface TopInsetProps {
|
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
estimatedHeight?: number;
|
|
6
6
|
}
|
|
7
|
-
export declare const TopInset: ({ className, children, estimatedHeight }: TopInsetProps) => import("react").JSX.Element;
|
|
7
|
+
export declare const TopInset: ({ className, children, estimatedHeight }: TopInsetProps) => import("react").JSX.Element | null;
|
|
8
8
|
export interface TopLeftActionProps {
|
|
9
9
|
className?: string;
|
|
10
10
|
children: ReactNode;
|
|
11
11
|
}
|
|
12
|
-
export declare const TopLeftAction: ({ className, children }: TopLeftActionProps) => import("react").JSX.Element;
|
|
12
|
+
export declare const TopLeftAction: ({ className, children }: TopLeftActionProps) => import("react").JSX.Element | null;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export declare const Layout: {
|
|
2
2
|
Header: ({ className, type, children, height }: import("./Header.d.ts").HeaderProps) => import("react").JSX.Element;
|
|
3
3
|
Sider: ({ className, bgClassName, trigger, header, close, children }: import("./Sider.d.ts").SiderProps) => import("react").JSX.Element;
|
|
4
|
-
Navbar: ({ back, backFallback, className, height, children, title, left, right, }: import("./Navbar.d.ts").NavbarProps) => import("react").JSX.Element;
|
|
5
|
-
TopInset: ({ className, children, estimatedHeight }: import("./TopInset.d.ts").TopInsetProps) => import("react").JSX.Element;
|
|
4
|
+
Navbar: ({ back, backFallback, className, height, children, title, left, right, }: import("./Navbar.d.ts").NavbarProps) => import("react").JSX.Element | null;
|
|
5
|
+
TopInset: ({ className, children, estimatedHeight }: import("./TopInset.d.ts").TopInsetProps) => import("react").JSX.Element | null;
|
|
6
6
|
BottomTab: ({ className, tabs, height, label, renderTab }: import("./BottomTab.d.ts").BottomTabProps) => import("react").JSX.Element;
|
|
7
|
-
BottomInset: ({ className, children, keyboardSticky, contentAnchor, role, estimatedHeight, frameScope, frameSource, frameCache, }: import("./BottomInset.d.ts").BottomInsetProps) => import("react").JSX.Element;
|
|
7
|
+
BottomInset: ({ className, children, keyboardSticky, contentAnchor, role, estimatedHeight, frameScope, frameSource, frameCache, }: import("./BottomInset.d.ts").BottomInsetProps) => import("react").JSX.Element | null;
|
|
8
8
|
Template: ({ className, children }: import("./Role.d.ts").TemplateProps) => import("react").JSX.Element;
|
|
9
9
|
Unit: ({ className, children, href }: import("./Role.d.ts").UnitProps) => import("react").JSX.Element;
|
|
10
10
|
View: ({ className, children }: import("./Role.d.ts").ViewProps) => import("react").JSX.Element;
|
|
11
11
|
Zone: ({ className, children }: import("./Role.d.ts").ZoneProps) => import("react").JSX.Element;
|
|
12
|
-
TopLeftAction: ({ className, children }: import("./TopInset.d.ts").TopLeftActionProps) => import("react").JSX.Element;
|
|
12
|
+
TopLeftAction: ({ className, children }: import("./TopInset.d.ts").TopLeftActionProps) => import("react").JSX.Element | null;
|
|
13
13
|
LeftSider: ({ className, children, open, width, close, onCancel }: import("./Sider.d.ts").LeftSiderProps) => import("react").JSX.Element;
|
|
14
14
|
RightSider: ({ className, children, open, title, width, close, onCancel }: import("./Sider.d.ts").RightSiderProps) => import("react").JSX.Element;
|
|
15
15
|
};
|
|
@@ -39,11 +39,12 @@ export interface InstallerInput {
|
|
|
39
39
|
}
|
|
40
40
|
export declare function installerScript(input: InstallerInput): string;
|
|
41
41
|
/**
|
|
42
|
-
* Stops every process running from the install folder,
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* Stops every process running from the install folder, again for one started meanwhile, until none is left (up to
|
|
43
|
+
* 10 s); given the app's exe, deletes it in the pass that finds none, so nothing can start it again. Exits 1 when a
|
|
44
|
+
* process (or the exe) is left or cannot be seen. Through WMI: the installer is a 32-bit program, so its PowerShell
|
|
45
|
+
* is too, and a 32-bit process cannot read a 64-bit one's path (Get-Process's Path comes back empty).
|
|
45
46
|
*/
|
|
46
|
-
export declare const STOP_SCRIPT = "param([string]$Dir)\n$ErrorActionPreference = 'Stop'\n$prefix = [IO.Path]::GetFullPath($Dir).TrimEnd('\\') + '\\'\n$running = { Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase) } }\n& $running
|
|
47
|
+
export declare const STOP_SCRIPT = "param([string]$Dir, [string]$Exe = '')\n$ErrorActionPreference = 'Stop'\n$prefix = [IO.Path]::GetFullPath($Dir).TrimEnd('\\') + '\\'\n$running = { Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase) } }\nfor ($i = 0; $i -lt 50; $i++) {\n $left = @(& $running)\n if ($left.Count -eq 0) {\n if (-not $Exe) { exit 0 }\n Remove-Item -LiteralPath $Exe -Force -ErrorAction SilentlyContinue\n if (-not (Test-Path -LiteralPath $Exe)) { exit 0 }\n }\n $left | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }\n Start-Sleep -Milliseconds 200\n}\nif ((& $running) -or ($Exe -and (Test-Path -LiteralPath $Exe))) { exit 1 }\n";
|
|
47
48
|
/** The longest path under `folder`, relative and with Windows separators. Links are not followed. */
|
|
48
49
|
export declare function deepestPath(folder: string): string;
|
|
49
50
|
/** The bytes of the files under `folder`, and what they take on disk. Links are not followed. */
|
|
@@ -4,6 +4,11 @@ import type { Lifecycle } from "./lifecycle.ts";
|
|
|
4
4
|
import type { DesktopPlugin, DesktopServerStatus, Launch, NativeEvent } from "./plugin.ts";
|
|
5
5
|
/** How long the window waits for one plugin's setup. */
|
|
6
6
|
export declare const SETUP_TIMEOUT_MS = 3000;
|
|
7
|
+
/**
|
|
8
|
+
* How long the launch waits for a gate plugin's setup. A gate decides whether this launch runs at all, so passing it
|
|
9
|
+
* by on time starts what the losing launch must not: a second app's server on the same data (single-instance).
|
|
10
|
+
*/
|
|
11
|
+
export declare const GATE_TIMEOUT_MS = 30000;
|
|
7
12
|
/**
|
|
8
13
|
* How long a page's call to a plugin whose setup is still running (it outlasted SETUP_TIMEOUT_MS)
|
|
9
14
|
* waits for it before it is answered INTERNAL with `retryable`.
|
|
@@ -90,6 +95,7 @@ export declare class CallIds {
|
|
|
90
95
|
export declare const COALESCE_MS = 100;
|
|
91
96
|
export interface DispatcherOptions {
|
|
92
97
|
setupTimeoutMs?: number;
|
|
98
|
+
gateTimeoutMs?: number;
|
|
93
99
|
setupWaitMs?: number;
|
|
94
100
|
/** The app's resolved capabilities from boot.json (PL-11). Absent: everything is allowed. */
|
|
95
101
|
acl?: ResolvedAcl | null;
|
|
@@ -4,7 +4,7 @@ import type { SecondInstance } from "./index.ts";
|
|
|
4
4
|
* are one namespace for the whole PC, so the user is part of the hash there; other users cannot
|
|
5
5
|
* write to a pipe they did not create (its default security), so they cannot pose as it either.
|
|
6
6
|
*/
|
|
7
|
-
export declare function socketPath(appId: string, env?: Record<string, string | undefined>, platform?: NodeJS.Platform): string;
|
|
7
|
+
export declare function socketPath(appId: string, env?: Record<string, string | undefined>, platform?: NodeJS.Platform, profile?: string): string;
|
|
8
8
|
export declare function encodeMessage(message: SecondInstance): string;
|
|
9
9
|
export declare function decodeMessage(line: string): SecondInstance | null;
|
|
10
10
|
export type Claim = {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
export interface AgentActivityProps {
|
|
3
3
|
active: boolean;
|
|
4
|
+
/** Guidance stays published while inactive: the subtree is off screen, but what it says about the route holds. */
|
|
5
|
+
keepGuides?: boolean;
|
|
4
6
|
children: ReactNode;
|
|
5
7
|
}
|
|
6
8
|
/**
|
|
@@ -8,4 +10,4 @@ export interface AgentActivityProps {
|
|
|
8
10
|
* it, like the page under the one on screen. Registrations stay in place, so turning it back on re-publishes them
|
|
9
11
|
* without a remount. A registry that lives outside the surface reads the same gate through `useAgentGate()`.
|
|
10
12
|
*/
|
|
11
|
-
export declare const AgentActivity: ({ active, children }: AgentActivityProps) => import("react").JSX.Element;
|
|
13
|
+
export declare const AgentActivity: ({ active, keepGuides, children }: AgentActivityProps) => import("react").JSX.Element;
|
|
@@ -38,9 +38,9 @@ export declare class AgenticSurface {
|
|
|
38
38
|
/**
|
|
39
39
|
* This surface for a subtree behind `gate`: what registers through it is published only while the gate is active,
|
|
40
40
|
* and every other call reaches this surface untouched. A proxy rather than a wrapper class, so a method added to the
|
|
41
|
-
* surface later is forwarded instead of missing.
|
|
41
|
+
* surface later is forwarded instead of missing. Guidance follows `guideGate` instead when one is named.
|
|
42
42
|
*/
|
|
43
|
-
gated(gate: AgentGate): AgenticSurface;
|
|
43
|
+
gated(gate: AgentGate, guideGate?: AgentGate | null): AgenticSurface;
|
|
44
44
|
snapshot(view?: string[]): SurfaceSnapshot;
|
|
45
45
|
/**
|
|
46
46
|
* A zone session's reading half: the same registry filtered to one scope subtree. Hook entries filter by their
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
interface EmbeddedLayoutProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
}
|
|
5
|
+
export declare const EmbeddedLayout: ({ children }: EmbeddedLayoutProps) => import("react").JSX.Element;
|
|
6
|
+
interface LayoutOutletProps {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare const LayoutOutlet: ({ children }: LayoutOutletProps) => import("react").ReactPortal | null;
|
|
10
|
+
export {};
|
|
@@ -6,6 +6,8 @@ interface RenderLayerProps {
|
|
|
6
6
|
params: Record<string, string>;
|
|
7
7
|
searchParams: Record<string, string | string[]>;
|
|
8
8
|
leaf?: ReactNode;
|
|
9
|
+
/** A page in an MCP view: every layout above it runs, and only the page is shown. */
|
|
10
|
+
isEmbedded?: boolean;
|
|
9
11
|
}
|
|
10
|
-
export declare const RenderLayer: import("react").MemoExoticComponent<(
|
|
12
|
+
export declare const RenderLayer: import("react").MemoExoticComponent<(props: RenderLayerProps) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined>;
|
|
11
13
|
export {};
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getEnv } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
cn,
|
|
5
|
+
DEFAULT_BOTTOM_INSET,
|
|
6
|
+
debugFrame,
|
|
7
|
+
type FrameSlotRegistration,
|
|
8
|
+
useInHiddenLayout,
|
|
9
|
+
usePathCtx,
|
|
10
|
+
} from "akanjs/client";
|
|
4
11
|
import { type ReactNode, useLayoutEffect, useState } from "react";
|
|
5
12
|
|
|
6
13
|
import { Portal } from "../Portal";
|
|
@@ -33,6 +40,7 @@ export const BottomInset = ({
|
|
|
33
40
|
|
|
34
41
|
const [contentElement, setContentElement] = useState<HTMLDivElement | null>(null);
|
|
35
42
|
const pathCtx = usePathCtx();
|
|
43
|
+
const isHidden = useInHiddenLayout();
|
|
36
44
|
const pathRoute = pathCtx.location?.pathRoute;
|
|
37
45
|
const path = pathCtx.location?.pathRoute?.path;
|
|
38
46
|
const registerFrameSlot = pathCtx.registerFrameSlot ?? (() => () => undefined);
|
|
@@ -61,7 +69,7 @@ export const BottomInset = ({
|
|
|
61
69
|
return () => debugFrame("bottomInset.unmount", { path, frameSource });
|
|
62
70
|
}, [path, keyboardSticky, contentAnchor, frameRole, frameScope, frameSource]);
|
|
63
71
|
useLayoutEffect(() => {
|
|
64
|
-
if (!path) return;
|
|
72
|
+
if (!path || isHidden) return;
|
|
65
73
|
const height = useDeclaredHeight ? resolvedEstimatedHeight : (measuredHeight ?? readContentHeight());
|
|
66
74
|
return registerFrameSlot({
|
|
67
75
|
type: "bottomInset",
|
|
@@ -84,6 +92,7 @@ export const BottomInset = ({
|
|
|
84
92
|
frameCache,
|
|
85
93
|
path,
|
|
86
94
|
useDeclaredHeight,
|
|
95
|
+
isHidden,
|
|
87
96
|
]);
|
|
88
97
|
useLayoutEffect(() => {
|
|
89
98
|
const element = contentElement;
|
|
@@ -102,6 +111,7 @@ export const BottomInset = ({
|
|
|
102
111
|
observer.observe(element);
|
|
103
112
|
return () => observer.disconnect();
|
|
104
113
|
}, [contentElement]);
|
|
114
|
+
if (isHidden) return null;
|
|
105
115
|
|
|
106
116
|
const content = (
|
|
107
117
|
<div
|
package/ui/Layout/Navbar.tsx
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getEnv } from "akanjs/base";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
cn,
|
|
5
|
+
DEFAULT_TOP_INSET,
|
|
6
|
+
debugFrame,
|
|
7
|
+
type TransitionType,
|
|
8
|
+
useCsr,
|
|
9
|
+
useInHiddenLayout,
|
|
10
|
+
usePathCtx,
|
|
11
|
+
} from "akanjs/client";
|
|
4
12
|
import { type ReactNode, useLayoutEffect } from "react";
|
|
5
13
|
import { BiChevronLeft, BiX } from "react-icons/bi";
|
|
6
14
|
|
|
@@ -34,8 +42,14 @@ export const Navbar = ({
|
|
|
34
42
|
right,
|
|
35
43
|
}: NavbarProps) => {
|
|
36
44
|
const pathCtx = usePathCtx();
|
|
45
|
+
const { history } = useCsr();
|
|
46
|
+
const isHidden = useInHiddenLayout();
|
|
37
47
|
const pathRoute = pathCtx.location?.pathRoute;
|
|
38
48
|
const path = pathRoute?.path;
|
|
49
|
+
const entryId = pathCtx.location?.entryId;
|
|
50
|
+
|
|
51
|
+
const isViewStart = !!globalThis.__AKAN_EMBED__ && !!entryId && history.current?.locations[0]?.entryId === entryId;
|
|
52
|
+
const shownBack = isViewStart ? false : back;
|
|
39
53
|
const BackIcon = closeIconTransitions.has(pathRoute?.pageState.transition ?? "none") ? BiX : BiChevronLeft;
|
|
40
54
|
const registerFrameSlot = pathCtx.registerFrameSlot ?? (() => () => undefined);
|
|
41
55
|
const suffix = getEnv().renderMode === "csr" && path ? `-${pathCtx.pageKey ?? path}` : "";
|
|
@@ -45,7 +59,7 @@ export const Navbar = ({
|
|
|
45
59
|
return () => debugFrame("navbar.unmount", { path, height });
|
|
46
60
|
}, [path, height]);
|
|
47
61
|
useLayoutEffect(() => {
|
|
48
|
-
if (!path) return;
|
|
62
|
+
if (!path || isHidden) return;
|
|
49
63
|
return registerFrameSlot({
|
|
50
64
|
type: "topInset",
|
|
51
65
|
scope: "page",
|
|
@@ -53,9 +67,10 @@ export const Navbar = ({
|
|
|
53
67
|
estimatedHeight: height ?? DEFAULT_TOP_INSET,
|
|
54
68
|
height,
|
|
55
69
|
});
|
|
56
|
-
}, [registerFrameSlot, height, path]);
|
|
70
|
+
}, [registerFrameSlot, height, path, isHidden]);
|
|
71
|
+
if (isHidden) return null;
|
|
57
72
|
const bar = (
|
|
58
|
-
<div className={cn("flex size-full items-center gap-2 px-5",
|
|
73
|
+
<div className={cn("flex size-full items-center gap-2 px-5", shownBack && "pl-14", className)}>
|
|
59
74
|
{left ? <div className="flex shrink-0 items-center gap-1">{left}</div> : null}
|
|
60
75
|
{title ? <div className="min-w-0 flex-1 truncate font-semibold text-base">{title}</div> : null}
|
|
61
76
|
{children}
|
|
@@ -63,19 +78,19 @@ export const Navbar = ({
|
|
|
63
78
|
</div>
|
|
64
79
|
);
|
|
65
80
|
const backButton =
|
|
66
|
-
|
|
81
|
+
shownBack === true ? (
|
|
67
82
|
<Link.Back className="text-4xl" fallback={backFallback}>
|
|
68
83
|
<BackIcon />
|
|
69
84
|
</Link.Back>
|
|
70
85
|
) : (
|
|
71
|
-
|
|
86
|
+
shownBack
|
|
72
87
|
);
|
|
73
88
|
return (
|
|
74
89
|
<>
|
|
75
90
|
<Portal id={`topInsetContent${suffix}`} fallback={<FrameSlotFallback slot="topInset">{bar}</FrameSlotFallback>}>
|
|
76
91
|
{bar}
|
|
77
92
|
</Portal>
|
|
78
|
-
{
|
|
93
|
+
{shownBack ? (
|
|
79
94
|
<Portal
|
|
80
95
|
id={`topLeftActionContent${suffix}`}
|
|
81
96
|
fallback={<FrameSlotFallback slot="topLeftAction">{backButton}</FrameSlotFallback>}
|
package/ui/Layout/TopInset.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getEnv } from "akanjs/base";
|
|
3
|
-
import { cn, DEFAULT_TOP_INSET, debugFrame, usePathCtx } from "akanjs/client";
|
|
3
|
+
import { cn, DEFAULT_TOP_INSET, debugFrame, useInHiddenLayout, usePathCtx } from "akanjs/client";
|
|
4
4
|
import { type ReactNode, useLayoutEffect } from "react";
|
|
5
5
|
|
|
6
6
|
import { Portal } from "../Portal";
|
|
@@ -14,6 +14,7 @@ export interface TopInsetProps {
|
|
|
14
14
|
|
|
15
15
|
export const TopInset = ({ className, children, estimatedHeight = DEFAULT_TOP_INSET }: TopInsetProps) => {
|
|
16
16
|
const pathCtx = usePathCtx();
|
|
17
|
+
const isHidden = useInHiddenLayout();
|
|
17
18
|
const path = pathCtx.location?.pathRoute?.path;
|
|
18
19
|
const registerFrameSlot = pathCtx.registerFrameSlot ?? (() => () => undefined);
|
|
19
20
|
const suffix = getEnv().renderMode === "csr" && path ? `-${pathCtx.pageKey ?? path}` : "";
|
|
@@ -24,14 +25,15 @@ export const TopInset = ({ className, children, estimatedHeight = DEFAULT_TOP_IN
|
|
|
24
25
|
return () => debugFrame("topInset.unmount", { path, estimatedHeight });
|
|
25
26
|
}, [path, estimatedHeight]);
|
|
26
27
|
useLayoutEffect(() => {
|
|
27
|
-
if (!path) return;
|
|
28
|
+
if (!path || isHidden) return;
|
|
28
29
|
return registerFrameSlot({
|
|
29
30
|
type: "topInset",
|
|
30
31
|
scope: "page",
|
|
31
32
|
source: "topInset",
|
|
32
33
|
estimatedHeight,
|
|
33
34
|
});
|
|
34
|
-
}, [registerFrameSlot, estimatedHeight, path]);
|
|
35
|
+
}, [registerFrameSlot, estimatedHeight, path, isHidden]);
|
|
36
|
+
if (isHidden) return null;
|
|
35
37
|
|
|
36
38
|
const content = (
|
|
37
39
|
<div data-akan-frame-slot="topInset" data-akan-frame-role="topChrome" className={cn("size-full", className)}>
|
|
@@ -52,6 +54,8 @@ export interface TopLeftActionProps {
|
|
|
52
54
|
|
|
53
55
|
export const TopLeftAction = ({ className, children }: TopLeftActionProps) => {
|
|
54
56
|
const pathCtx = usePathCtx();
|
|
57
|
+
const isHidden = useInHiddenLayout();
|
|
58
|
+
if (isHidden) return null;
|
|
55
59
|
const path = pathCtx.location?.pathRoute?.path;
|
|
56
60
|
const suffix = getEnv().renderMode === "csr" && path ? `-${pathCtx.pageKey ?? path}` : "";
|
|
57
61
|
const content = <div className={className}>{children}</div>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { usePage } from "akanjs/client";
|
|
2
|
+
import { fetch, usePage } from "akanjs/client";
|
|
3
3
|
import { capitalize } from "akanjs/common";
|
|
4
4
|
import type { SliceMeta } from "akanjs/fetch";
|
|
5
5
|
import { st } from "akanjs/store";
|
|
@@ -110,6 +110,10 @@ export default function ViewEditModal({
|
|
|
110
110
|
const modelLoading = storeUse[names.modelLoading]() as string | boolean;
|
|
111
111
|
const modelFormLoading = storeUse[names.modelFormLoading]() as string | boolean;
|
|
112
112
|
const modelFormId = storeSel<string, { id: string }>((state) => state[names.modelForm].id);
|
|
113
|
+
|
|
114
|
+
const servedFetch = fetch as unknown as { [key: string]: unknown };
|
|
115
|
+
const canUpdate = typeof servedFetch[`update${ModelName}`] === "function";
|
|
116
|
+
const canRemove = typeof servedFetch[`remove${ModelName}`] === "function";
|
|
113
117
|
const isModalOpen = modelModal === "view" || (modelModal === "edit" && (!!modelFormLoading || !!modelFormId));
|
|
114
118
|
const Title = () => {
|
|
115
119
|
if (!model || modelLoading || !renderTitle) return <></>;
|
|
@@ -133,7 +137,7 @@ export default function ViewEditModal({
|
|
|
133
137
|
title={
|
|
134
138
|
<div className="flex w-full items-center justify-between">
|
|
135
139
|
<Title />
|
|
136
|
-
{menu === false
|
|
140
|
+
{menu === false || (menu === undefined && !canRemove)
|
|
137
141
|
? null
|
|
138
142
|
: (menu ?? (
|
|
139
143
|
<Dropdown
|
|
@@ -159,14 +163,16 @@ export default function ViewEditModal({
|
|
|
159
163
|
}
|
|
160
164
|
action={
|
|
161
165
|
modelModal === "view" ? (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
canUpdate ? (
|
|
167
|
+
<EditAction
|
|
168
|
+
modelName={modelName}
|
|
169
|
+
label={editLabel ?? l("base.edit")}
|
|
170
|
+
closeView={closeView}
|
|
171
|
+
onAct={() => {
|
|
172
|
+
if (model) storeDo[names.editModel](model.id);
|
|
173
|
+
}}
|
|
174
|
+
/>
|
|
175
|
+
) : null
|
|
170
176
|
) : (
|
|
171
177
|
<SaveAction
|
|
172
178
|
modelName={modelName}
|
package/ui/Select.tsx
CHANGED
|
@@ -95,14 +95,19 @@ const DefaultSelect = <
|
|
|
95
95
|
renderSelected,
|
|
96
96
|
}: SelectProps<T, Multiple, Searchable, Option>) => {
|
|
97
97
|
useFieldTool(onChange, { disabled });
|
|
98
|
-
const { l } = usePage();
|
|
98
|
+
const { l, lang } = usePage();
|
|
99
99
|
const [isOpen, setIsOpen] = useState(false);
|
|
100
100
|
const labeledOptions: LabelOption<T>[] = useMemo(() => {
|
|
101
|
-
if (isEnum(options as Cls))
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
value: v
|
|
105
|
-
|
|
101
|
+
if (isEnum(options as Cls)) {
|
|
102
|
+
const { refName, values } = options as EnumInstance<string, T>;
|
|
103
|
+
return values.map((v) => {
|
|
104
|
+
if (typeof v === "object") return { label: JSON.stringify(v), value: v };
|
|
105
|
+
const key = `${refName}.${String(v)}`;
|
|
106
|
+
const label = l._(key);
|
|
107
|
+
|
|
108
|
+
return { label: label === key ? String(v) : label, value: v };
|
|
109
|
+
});
|
|
110
|
+
}
|
|
106
111
|
const list = options as (T | LabelOption<T>)[];
|
|
107
112
|
const first = list[0];
|
|
108
113
|
|
|
@@ -110,7 +115,7 @@ const DefaultSelect = <
|
|
|
110
115
|
return isLabeled
|
|
111
116
|
? (list as LabelOption<T>[])
|
|
112
117
|
: (list as T[]).map((v) => ({ label: v as string | boolean | number, value: v }));
|
|
113
|
-
}, [options]);
|
|
118
|
+
}, [options, lang]);
|
|
114
119
|
|
|
115
120
|
const [searchText, setSearchText] = useState("");
|
|
116
121
|
const portal = useOverlayPortal();
|
package/ui/System/CSR.tsx
CHANGED
|
@@ -483,7 +483,13 @@ const CSRPageContainer = ({ entry, prefix, layoutStyle }: CSRPageContainerProps)
|
|
|
483
483
|
location={location}
|
|
484
484
|
prefix={prefix}
|
|
485
485
|
>
|
|
486
|
-
<RenderLayer
|
|
486
|
+
<RenderLayer
|
|
487
|
+
renders={renders}
|
|
488
|
+
index={0}
|
|
489
|
+
params={location.params}
|
|
490
|
+
searchParams={location.searchParams}
|
|
491
|
+
isEmbedded={Boolean(globalThis.__AKAN_EMBED__)}
|
|
492
|
+
/>
|
|
487
493
|
</ClientPathWrapper>
|
|
488
494
|
</animated.div>,
|
|
489
495
|
pageContainers,
|
package/ui/System/Client.tsx
CHANGED
|
@@ -87,6 +87,9 @@ ManifestDPIAware true
|
|
|
87
87
|
ManifestLongPathAware true
|
|
88
88
|
SetCompressor /SOLID lzma
|
|
89
89
|
RequestExecutionLevel user
|
|
90
|
+
; /S does not hide NSIS's "Verifying installer" window (only a script's SilentInstall does), and a large setup takes
|
|
91
|
+
; over a second to verify, so the window painted over a kiosk. A truncated setup still fails to unpack into .setup-new.
|
|
92
|
+
CRCCheck off
|
|
90
93
|
|
|
91
94
|
!include "MUI2.nsh"
|
|
92
95
|
!include "FileFunc.nsh"
|
|
@@ -188,8 +191,9 @@ FunctionEnd
|
|
|
188
191
|
${removal(input.entries)}
|
|
189
192
|
!macroend
|
|
190
193
|
|
|
194
|
+
; $R6 is 1 when the folder held the app's exe before the uninstall stopped the app and deleted it.
|
|
191
195
|
!macro RemoveApp
|
|
192
|
-
\${If}
|
|
196
|
+
\${If} $R6 == 1
|
|
193
197
|
!insertmacro RemoveTree "$INSTDIR"
|
|
194
198
|
\${Else}
|
|
195
199
|
!insertmacro RemoveEntries
|
|
@@ -358,7 +362,9 @@ Section "Install"
|
|
|
358
362
|
!insertmacro Fail "The uninstaller could not be written to $INSTDIR.setup-uninstall.exe. \${APP_NAME} is left as it was."
|
|
359
363
|
\${EndIf}
|
|
360
364
|
File "/oname=$PLUGINSDIR\\stop-app.ps1" "${nsis(input.stopScript)}"
|
|
361
|
-
nsExec
|
|
365
|
+
; nsExec waits forever by default: a stop script that hung once kept a setup waiting 16 minutes. Past the deadline it
|
|
366
|
+
; is ended and answers "timeout", which counts as a failed stop.
|
|
367
|
+
nsExec::Exec /TIMEOUT=60000 'powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\\stop-app.ps1" "$INSTDIR"'
|
|
362
368
|
Pop $0
|
|
363
369
|
\${If} $0 == 0
|
|
364
370
|
StrCpy $AppStopped 1
|
|
@@ -438,9 +444,19 @@ FunctionEnd
|
|
|
438
444
|
|
|
439
445
|
Section "Uninstall"
|
|
440
446
|
InitPluginsDir
|
|
447
|
+
StrCpy $R6 0
|
|
448
|
+
\${If} \${FileExists} "$INSTDIR\\\${EXE}"
|
|
449
|
+
StrCpy $R6 1
|
|
450
|
+
\${EndIf}
|
|
441
451
|
File "/oname=$PLUGINSDIR\\stop-app.ps1" "${nsis(input.stopScript)}"
|
|
442
|
-
|
|
452
|
+
; With the exe named, the script deletes it in the pass that finds nothing running: a watchdog that starts the app
|
|
453
|
+
; again between a stop and a later delete kept the exe, and Delete /REBOOTOK needs an administrator.
|
|
454
|
+
nsExec::Exec /TIMEOUT=60000 'powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\\stop-app.ps1" "$INSTDIR" "$INSTDIR\\\${EXE}"'
|
|
443
455
|
Pop $0
|
|
456
|
+
\${If} $0 != 0
|
|
457
|
+
DetailPrint "$INSTDIR\\\${EXE} is still running and stays behind."
|
|
458
|
+
SetErrorLevel 2
|
|
459
|
+
\${EndIf}
|
|
444
460
|
Delete "$SMPROGRAMS\\\${APP_NAME}.lnk"
|
|
445
461
|
!insertmacro RemoveTree "$INSTDIR.previous"
|
|
446
462
|
!insertmacro RemoveSiblings "update-"
|
|
@@ -465,17 +481,26 @@ SectionEnd
|
|
|
465
481
|
}
|
|
466
482
|
|
|
467
483
|
/**
|
|
468
|
-
* Stops every process running from the install folder,
|
|
469
|
-
*
|
|
470
|
-
*
|
|
484
|
+
* Stops every process running from the install folder, again for one started meanwhile, until none is left (up to
|
|
485
|
+
* 10 s); given the app's exe, deletes it in the pass that finds none, so nothing can start it again. Exits 1 when a
|
|
486
|
+
* process (or the exe) is left or cannot be seen. Through WMI: the installer is a 32-bit program, so its PowerShell
|
|
487
|
+
* is too, and a 32-bit process cannot read a 64-bit one's path (Get-Process's Path comes back empty).
|
|
471
488
|
*/
|
|
472
|
-
export const STOP_SCRIPT = `param([string]$Dir)
|
|
489
|
+
export const STOP_SCRIPT = `param([string]$Dir, [string]$Exe = '')
|
|
473
490
|
$ErrorActionPreference = 'Stop'
|
|
474
491
|
$prefix = [IO.Path]::GetFullPath($Dir).TrimEnd('\\') + '\\'
|
|
475
492
|
$running = { Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase) } }
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (
|
|
493
|
+
for ($i = 0; $i -lt 50; $i++) {
|
|
494
|
+
$left = @(& $running)
|
|
495
|
+
if ($left.Count -eq 0) {
|
|
496
|
+
if (-not $Exe) { exit 0 }
|
|
497
|
+
Remove-Item -LiteralPath $Exe -Force -ErrorAction SilentlyContinue
|
|
498
|
+
if (-not (Test-Path -LiteralPath $Exe)) { exit 0 }
|
|
499
|
+
}
|
|
500
|
+
$left | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
|
|
501
|
+
Start-Sleep -Milliseconds 200
|
|
502
|
+
}
|
|
503
|
+
if ((& $running) -or ($Exe -and (Test-Path -LiteralPath $Exe))) { exit 1 }
|
|
479
504
|
`;
|
|
480
505
|
|
|
481
506
|
/** The longest path under `folder`, relative and with Windows separators. Links are not followed. */
|
|
@@ -33,6 +33,12 @@ import type {
|
|
|
33
33
|
/** How long the window waits for one plugin's setup. */
|
|
34
34
|
export const SETUP_TIMEOUT_MS = 3000;
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* How long the launch waits for a gate plugin's setup. A gate decides whether this launch runs at all, so passing it
|
|
38
|
+
* by on time starts what the losing launch must not: a second app's server on the same data (single-instance).
|
|
39
|
+
*/
|
|
40
|
+
export const GATE_TIMEOUT_MS = 30_000;
|
|
41
|
+
|
|
36
42
|
/**
|
|
37
43
|
* How long a page's call to a plugin whose setup is still running (it outlasted SETUP_TIMEOUT_MS)
|
|
38
44
|
* waits for it before it is answered INTERNAL with `retryable`.
|
|
@@ -189,6 +195,7 @@ export const COALESCE_MS = 100;
|
|
|
189
195
|
|
|
190
196
|
export interface DispatcherOptions {
|
|
191
197
|
setupTimeoutMs?: number;
|
|
198
|
+
gateTimeoutMs?: number;
|
|
192
199
|
setupWaitMs?: number;
|
|
193
200
|
/** The app's resolved capabilities from boot.json (PL-11). Absent: everything is allowed. */
|
|
194
201
|
acl?: ResolvedAcl | null;
|
|
@@ -301,18 +308,19 @@ export function createDispatcher(
|
|
|
301
308
|
};
|
|
302
309
|
|
|
303
310
|
const timeout = options.setupTimeoutMs ?? SETUP_TIMEOUT_MS;
|
|
311
|
+
const gateTimeout = options.gateTimeoutMs ?? GATE_TIMEOUT_MS;
|
|
304
312
|
/** Setups still running (plugin lifecycle rule: calls and $listen wait for them). */
|
|
305
313
|
const settingUp = new Map<string, Promise<unknown>>();
|
|
306
|
-
const setUp = async (plugin: DesktopPlugin) => {
|
|
314
|
+
const setUp = async (plugin: DesktopPlugin, limit = timeout) => {
|
|
307
315
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
308
316
|
try {
|
|
309
317
|
const done = Promise.resolve(plugin.setup?.(context(plugin)));
|
|
310
318
|
settingUp.set(plugin.id, done);
|
|
311
319
|
const forget = () => void settingUp.delete(plugin.id);
|
|
312
320
|
done.then(forget, forget);
|
|
313
|
-
const late = new Promise<"late">((resolve) => (timer = setTimeout(() => resolve("late"),
|
|
321
|
+
const late = new Promise<"late">((resolve) => (timer = setTimeout(() => resolve("late"), limit)));
|
|
314
322
|
if ((await Promise.race([done, late])) === "late")
|
|
315
|
-
console.warn(`[akan-native] ${plugin.id} setup took over ${
|
|
323
|
+
console.warn(`[akan-native] ${plugin.id} setup took over ${limit} ms; creating the window anyway`);
|
|
316
324
|
} catch (error) {
|
|
317
325
|
console.error(`[akan-native] ${plugin.id} setup failed`, error);
|
|
318
326
|
} finally {
|
|
@@ -322,10 +330,10 @@ export function createDispatcher(
|
|
|
322
330
|
|
|
323
331
|
const setups = (async () => {
|
|
324
332
|
for (const plugin of plugins.filter((p) => p.launchPhase === "gate")) {
|
|
325
|
-
await setUp(plugin);
|
|
333
|
+
await setUp(plugin, gateTimeout);
|
|
326
334
|
if (launch.exit !== undefined) return;
|
|
327
335
|
}
|
|
328
|
-
await Promise.all(plugins.filter((p) => p.launchPhase !== "gate").map(setUp));
|
|
336
|
+
await Promise.all(plugins.filter((p) => p.launchPhase !== "gate").map((plugin) => setUp(plugin)));
|
|
329
337
|
})();
|
|
330
338
|
const launched = setups.then(() => {
|
|
331
339
|
launching = false;
|
|
@@ -20,6 +20,10 @@ export function createDesktopSingleInstance(
|
|
|
20
20
|
let listens = 0;
|
|
21
21
|
|
|
22
22
|
const received = (ctx: DesktopContext, message: SecondInstance) => {
|
|
23
|
+
|
|
24
|
+
console.info(
|
|
25
|
+
`[akan-native] single-instance: a second launch handed over to this one (${message.args.length} arguments)`,
|
|
26
|
+
);
|
|
23
27
|
bringToFront(ctx).catch((error) => console.error("[akan-native] single-instance: cannot focus the window", error));
|
|
24
28
|
|
|
25
29
|
ctx.openLinks(message.args);
|
|
@@ -4,7 +4,7 @@ import { dlopen, FFIType } from "bun:ffi";
|
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { chmodSync, closeSync, constants, openSync, rmSync } from "node:fs";
|
|
6
6
|
import { connect, createServer, type Server, type Socket } from "node:net";
|
|
7
|
-
import { tmpdir } from "node:os";
|
|
7
|
+
import { tmpdir, userInfo } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import type { SecondInstance } from "./index.ts";
|
|
10
10
|
|
|
@@ -13,6 +13,14 @@ const ACK = "ok\n";
|
|
|
13
13
|
/** One message is a few KiB of arguments; anything larger is not from us. */
|
|
14
14
|
const MAX_MESSAGE = 256 * 1024;
|
|
15
15
|
|
|
16
|
+
const profileFolder = (env: Record<string, string | undefined>) => {
|
|
17
|
+
try {
|
|
18
|
+
return userInfo().homedir;
|
|
19
|
+
} catch {
|
|
20
|
+
return env.USERPROFILE ?? env.USERNAME ?? "";
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
16
24
|
/**
|
|
17
25
|
* sun_path is 104 bytes on macOS, so the name is a short hash, not the app id. Windows pipe names
|
|
18
26
|
* are one namespace for the whole PC, so the user is part of the hash there; other users cannot
|
|
@@ -22,12 +30,11 @@ export function socketPath(
|
|
|
22
30
|
appId: string,
|
|
23
31
|
env: Record<string, string | undefined> = process.env,
|
|
24
32
|
platform: NodeJS.Platform = process.platform,
|
|
33
|
+
profile = platform === "win32" ? profileFolder(env) : "",
|
|
25
34
|
): string {
|
|
26
35
|
if (platform === "win32") {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.digest("hex")
|
|
30
|
-
.slice(0, 16);
|
|
36
|
+
|
|
37
|
+
const hash = createHash("sha256").update(`${profile.toLowerCase()}\0${appId}`).digest("hex").slice(0, 16);
|
|
31
38
|
return `\\\\.\\pipe\\akan-native-${hash}`;
|
|
32
39
|
}
|
|
33
40
|
const dir = env.XDG_RUNTIME_DIR || env.TMPDIR || tmpdir();
|
|
@@ -4,6 +4,8 @@ import { GateContext, SurfaceContext, useAgentGate, useSurface } from "./surface
|
|
|
4
4
|
|
|
5
5
|
export interface AgentActivityProps {
|
|
6
6
|
active: boolean;
|
|
7
|
+
/** Guidance stays published while inactive: the subtree is off screen, but what it says about the route holds. */
|
|
8
|
+
keepGuides?: boolean;
|
|
7
9
|
children: ReactNode;
|
|
8
10
|
}
|
|
9
11
|
|
|
@@ -12,11 +14,11 @@ export interface AgentActivityProps {
|
|
|
12
14
|
* it, like the page under the one on screen. Registrations stay in place, so turning it back on re-publishes them
|
|
13
15
|
* without a remount. A registry that lives outside the surface reads the same gate through `useAgentGate()`.
|
|
14
16
|
*/
|
|
15
|
-
export const AgentActivity = ({ active, children }: AgentActivityProps) => {
|
|
17
|
+
export const AgentActivity = ({ active, keepGuides = false, children }: AgentActivityProps) => {
|
|
16
18
|
const surface = useSurface();
|
|
17
19
|
const parent = useAgentGate();
|
|
18
20
|
const gate = useMemo(() => surface.gate(active, parent), [surface, parent]);
|
|
19
|
-
const gated = useMemo(() => surface.gated(gate), [surface, gate]);
|
|
21
|
+
const gated = useMemo(() => surface.gated(gate, keepGuides ? parent : gate), [surface, gate, parent, keepGuides]);
|
|
20
22
|
useLayoutEffect(() => gate.set(active), [gate, active]);
|
|
21
23
|
return (
|
|
22
24
|
<SurfaceContext.Provider value={gated}>
|
|
@@ -127,14 +127,14 @@ export class AgenticSurface {
|
|
|
127
127
|
/**
|
|
128
128
|
* This surface for a subtree behind `gate`: what registers through it is published only while the gate is active,
|
|
129
129
|
* and every other call reaches this surface untouched. A proxy rather than a wrapper class, so a method added to the
|
|
130
|
-
* surface later is forwarded instead of missing.
|
|
130
|
+
* surface later is forwarded instead of missing. Guidance follows `guideGate` instead when one is named.
|
|
131
131
|
*/
|
|
132
|
-
gated(gate: AgentGate): AgenticSurface {
|
|
132
|
+
gated(gate: AgentGate, guideGate: AgentGate | null = gate): AgenticSurface {
|
|
133
133
|
const registrations: Partial<Record<PropertyKey, unknown>> = {
|
|
134
134
|
registerTool: (scope: string[], entry: ToolEntry) => this.registerTool(scope, entry, gate),
|
|
135
135
|
registerResource: (scope: string[], entry: ResourceEntry) => this.registerResource(scope, entry, gate),
|
|
136
136
|
openScope: (parent: string[], scope: ScopeEntry) => this.openScope(parent, scope, gate),
|
|
137
|
-
registerGuide: (scope: string[], text: string) => this.registerGuide(scope, text,
|
|
137
|
+
registerGuide: (scope: string[], text: string) => this.registerGuide(scope, text, guideGate),
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
const bound = new Map<PropertyKey, unknown>();
|
package/webkit/CsrRouteTable.ts
CHANGED
|
@@ -190,7 +190,8 @@ export class CsrRouteTable {
|
|
|
190
190
|
): PathRoute[] => {
|
|
191
191
|
const layer = RouteLayering.of(route, parent);
|
|
192
192
|
const { path, pathSegments } = layer;
|
|
193
|
-
const currentLayoutConfig =
|
|
193
|
+
const currentLayoutConfig =
|
|
194
|
+
route.renderLayout && route.layoutPageConfig ? CsrRouteTable.#layoutConfigOf(route.layoutPageConfig) : null;
|
|
194
195
|
const pageConfigChain = [...parentPageConfigChain, ...(currentLayoutConfig ? [currentLayoutConfig] : [])];
|
|
195
196
|
const pageRenderConfigChain =
|
|
196
197
|
route.pageIncludesOwnLayout === false && route.renderLayout ? parentPageConfigChain : pageConfigChain;
|
|
@@ -250,6 +251,12 @@ export class CsrRouteTable {
|
|
|
250
251
|
return Object.keys(context).sort();
|
|
251
252
|
}
|
|
252
253
|
|
|
254
|
+
static #layoutConfigOf(config: PageConfig): PageConfig {
|
|
255
|
+
if (!globalThis.__AKAN_EMBED__) return config;
|
|
256
|
+
const { topInset: _top, bottomInset: _bottom, ...rest } = config;
|
|
257
|
+
return rest;
|
|
258
|
+
}
|
|
259
|
+
|
|
253
260
|
static #paramNamesOf(pattern: string) {
|
|
254
261
|
return pattern
|
|
255
262
|
.split("/")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { hiddenLayoutContext } from "akanjs/client";
|
|
3
|
+
import {
|
|
4
|
+
type ContextType,
|
|
5
|
+
createContext,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
useCallback,
|
|
8
|
+
useContext,
|
|
9
|
+
useLayoutEffect,
|
|
10
|
+
useMemo,
|
|
11
|
+
useRef,
|
|
12
|
+
useState,
|
|
13
|
+
} from "react";
|
|
14
|
+
import { createPortal } from "react-dom";
|
|
15
|
+
import { AgentActivity, GateContext, SurfaceContext } from "../vendor/use-agentic";
|
|
16
|
+
|
|
17
|
+
interface EmbeddedLayoutValue {
|
|
18
|
+
target: HTMLElement | null;
|
|
19
|
+
onOutlet: (mounted: boolean) => void;
|
|
20
|
+
surface: ContextType<typeof SurfaceContext>;
|
|
21
|
+
gate: ContextType<typeof GateContext>;
|
|
22
|
+
}
|
|
23
|
+
const embeddedLayoutContext = createContext<EmbeddedLayoutValue | null>(null);
|
|
24
|
+
|
|
25
|
+
interface EmbeddedLayoutProps {
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export const EmbeddedLayout = ({ children }: EmbeddedLayoutProps) => {
|
|
29
|
+
const surface = useContext(SurfaceContext);
|
|
30
|
+
const gate = useContext(GateContext);
|
|
31
|
+
const [target, setTarget] = useState<HTMLDivElement | null>(null);
|
|
32
|
+
const [drawsPage, setDrawsPage] = useState(true);
|
|
33
|
+
const outletRef = useRef(false);
|
|
34
|
+
const onOutlet = useCallback((mounted: boolean) => {
|
|
35
|
+
outletRef.current = mounted;
|
|
36
|
+
setDrawsPage(mounted);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
useLayoutEffect(() => {
|
|
40
|
+
if (!outletRef.current) setDrawsPage(false);
|
|
41
|
+
});
|
|
42
|
+
const value = useMemo(() => ({ target, onOutlet, surface, gate }), [target, onOutlet, surface, gate]);
|
|
43
|
+
return (
|
|
44
|
+
<embeddedLayoutContext.Provider value={value}>
|
|
45
|
+
<div hidden={drawsPage}>
|
|
46
|
+
<hiddenLayoutContext.Provider value={drawsPage}>
|
|
47
|
+
<AgentActivity active={!drawsPage} keepGuides>
|
|
48
|
+
{children}
|
|
49
|
+
</AgentActivity>
|
|
50
|
+
</hiddenLayoutContext.Provider>
|
|
51
|
+
</div>
|
|
52
|
+
<div ref={setTarget} className="contents" />
|
|
53
|
+
</embeddedLayoutContext.Provider>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
interface LayoutOutletProps {
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
}
|
|
60
|
+
export const LayoutOutlet = ({ children }: LayoutOutletProps) => {
|
|
61
|
+
const embedded = useContext(embeddedLayoutContext);
|
|
62
|
+
const onOutlet = embedded?.onOutlet;
|
|
63
|
+
useLayoutEffect(() => {
|
|
64
|
+
if (!onOutlet) return;
|
|
65
|
+
onOutlet(true);
|
|
66
|
+
return () => onOutlet(false);
|
|
67
|
+
}, [onOutlet]);
|
|
68
|
+
if (!embedded?.target) return null;
|
|
69
|
+
return createPortal(
|
|
70
|
+
<SurfaceContext.Provider value={embedded.surface}>
|
|
71
|
+
<GateContext.Provider value={embedded.gate}>
|
|
72
|
+
<hiddenLayoutContext.Provider value={false}>{children}</hiddenLayoutContext.Provider>
|
|
73
|
+
</GateContext.Provider>
|
|
74
|
+
</SurfaceContext.Provider>,
|
|
75
|
+
embedded.target,
|
|
76
|
+
);
|
|
77
|
+
};
|
package/webkit/RenderLayer.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { debugFrame, RouteDefinition, type RouteRender, router, usePathCtx } fro
|
|
|
3
3
|
import { isThenable, Logger } from "akanjs/common";
|
|
4
4
|
import { createContext, createElement, memo, type ReactNode, useContext, useEffect, useRef, useState } from "react";
|
|
5
5
|
import { CsrFrameDump } from "./csrFrameDump";
|
|
6
|
+
import { EmbeddedLayout, LayoutOutlet } from "./EmbeddedLayout";
|
|
6
7
|
import { RenderFailure } from "./RenderFailure";
|
|
7
8
|
import { useFetch } from "./useFetch";
|
|
8
9
|
import { usePageActivity } from "./usePageActivity";
|
|
@@ -28,15 +29,28 @@ interface RenderLayerProps {
|
|
|
28
29
|
params: Record<string, string>;
|
|
29
30
|
searchParams: Record<string, string | string[]>;
|
|
30
31
|
leaf?: ReactNode;
|
|
32
|
+
/** A page in an MCP view: every layout above it runs, and only the page is shown. */
|
|
33
|
+
isEmbedded?: boolean;
|
|
31
34
|
}
|
|
32
|
-
export const RenderLayer = memo((
|
|
35
|
+
export const RenderLayer = memo((props: RenderLayerProps) => {
|
|
36
|
+
const { renders, index, params, searchParams, leaf = null, isEmbedded = false } = props;
|
|
33
37
|
const isLast = index >= renders.length - 1;
|
|
34
|
-
const
|
|
38
|
+
const below = isLast ? (
|
|
35
39
|
leaf
|
|
36
40
|
) : (
|
|
37
|
-
<RenderLayer
|
|
41
|
+
<RenderLayer
|
|
42
|
+
renders={renders}
|
|
43
|
+
index={index + 1}
|
|
44
|
+
params={params}
|
|
45
|
+
searchParams={searchParams}
|
|
46
|
+
leaf={leaf}
|
|
47
|
+
isEmbedded={isEmbedded}
|
|
48
|
+
/>
|
|
38
49
|
);
|
|
39
50
|
const routeRender = renders[index];
|
|
51
|
+
const isEmbeddedLayout = isEmbedded && routeRender?.kind === "layout";
|
|
52
|
+
const children = isEmbeddedLayout ? <LayoutOutlet>{below}</LayoutOutlet> : below;
|
|
53
|
+
const frame = (drawn: ReactNode) => (isEmbeddedLayout ? <EmbeddedLayout>{drawn}</EmbeddedLayout> : drawn);
|
|
40
54
|
const isAsyncRender = isAsyncRouteRender(routeRender);
|
|
41
55
|
const renderedRef = useRef<RenderedRoute | null>(null);
|
|
42
56
|
const [, setFailures] = useState(0);
|
|
@@ -106,7 +120,8 @@ export const RenderLayer = memo(({ renders, index, params, searchParams, leaf =
|
|
|
106
120
|
};
|
|
107
121
|
}, [record]);
|
|
108
122
|
if (!routeRender) return null;
|
|
109
|
-
if (!isAsyncRender)
|
|
123
|
+
if (!isAsyncRender)
|
|
124
|
+
return frame(createElement(routeRender.render as never, { children, params, searchParams } as never));
|
|
110
125
|
const failure = renderedRef.current?.failure;
|
|
111
126
|
if (failure)
|
|
112
127
|
return (
|
|
@@ -119,7 +134,7 @@ export const RenderLayer = memo(({ renders, index, params, searchParams, leaf =
|
|
|
119
134
|
/>
|
|
120
135
|
);
|
|
121
136
|
if (!value) return <>{composeLoadingFallback(renders.slice(index), params)}</>;
|
|
122
|
-
return <layerChildContext.Provider value={children}>{value}</layerChildContext.Provider
|
|
137
|
+
return frame(<layerChildContext.Provider value={children}>{value}</layerChildContext.Provider>);
|
|
123
138
|
});
|
|
124
139
|
|
|
125
140
|
function reportFailure(result: ReactNode | Promise<ReactNode>, layer: string): ReactNode | Promise<ReactNode> {
|