@celestea/studio 2.7.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/LICENSE +21 -0
- package/dist/app.d.ts +111 -0
- package/dist/app.js +219 -0
- package/dist/auth/api-token.d.ts +76 -0
- package/dist/auth/api-token.js +172 -0
- package/dist/auth/htpasswd.d.ts +22 -0
- package/dist/auth/htpasswd.js +61 -0
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/page.d.ts +19 -0
- package/dist/auth/page.js +73 -0
- package/dist/auth/rate-limit.d.ts +27 -0
- package/dist/auth/rate-limit.js +47 -0
- package/dist/auth/token.d.ts +49 -0
- package/dist/auth/token.js +112 -0
- package/dist/config.d.ts +78 -0
- package/dist/config.js +72 -0
- package/dist/deployment.d.ts +92 -0
- package/dist/deployment.js +154 -0
- package/dist/fake-runtime-adapter.d.ts +37 -0
- package/dist/fake-runtime-adapter.js +276 -0
- package/dist/handlers/auth.d.ts +24 -0
- package/dist/handlers/auth.js +155 -0
- package/dist/handlers/common.d.ts +76 -0
- package/dist/handlers/common.js +127 -0
- package/dist/handlers/config-shape.d.ts +76 -0
- package/dist/handlers/config-shape.js +227 -0
- package/dist/handlers/config.d.ts +26 -0
- package/dist/handlers/config.js +161 -0
- package/dist/handlers/context-shape.d.ts +33 -0
- package/dist/handlers/context-shape.js +59 -0
- package/dist/handlers/dialog.d.ts +22 -0
- package/dist/handlers/dialog.js +292 -0
- package/dist/handlers/exec.d.ts +22 -0
- package/dist/handlers/exec.js +131 -0
- package/dist/handlers/fs-read.d.ts +63 -0
- package/dist/handlers/fs-read.js +159 -0
- package/dist/handlers/fs.d.ts +57 -0
- package/dist/handlers/fs.js +153 -0
- package/dist/handlers/grants-shape.d.ts +45 -0
- package/dist/handlers/grants-shape.js +130 -0
- package/dist/handlers/grants.d.ts +21 -0
- package/dist/handlers/grants.js +267 -0
- package/dist/handlers/health.d.ts +37 -0
- package/dist/handlers/health.js +139 -0
- package/dist/handlers/index.d.ts +40 -0
- package/dist/handlers/index.js +85 -0
- package/dist/handlers/permissions.d.ts +9 -0
- package/dist/handlers/permissions.js +183 -0
- package/dist/handlers/plugins.d.ts +18 -0
- package/dist/handlers/plugins.js +23 -0
- package/dist/handlers/prompts.d.ts +12 -0
- package/dist/handlers/prompts.js +120 -0
- package/dist/handlers/providers.d.ts +12 -0
- package/dist/handlers/providers.js +178 -0
- package/dist/handlers/questions.d.ts +23 -0
- package/dist/handlers/questions.js +115 -0
- package/dist/handlers/session-model.d.ts +38 -0
- package/dist/handlers/session-model.js +105 -0
- package/dist/handlers/session-move.d.ts +22 -0
- package/dist/handlers/session-move.js +188 -0
- package/dist/handlers/session-tools.d.ts +19 -0
- package/dist/handlers/session-tools.js +75 -0
- package/dist/handlers/sessions.d.ts +32 -0
- package/dist/handlers/sessions.js +242 -0
- package/dist/handlers/usage.d.ts +26 -0
- package/dist/handlers/usage.js +77 -0
- package/dist/handlers/worker.d.ts +12 -0
- package/dist/handlers/worker.js +82 -0
- package/dist/handlers/workspaces.d.ts +12 -0
- package/dist/handlers/workspaces.js +88 -0
- package/dist/harness.test-util.d.ts +101 -0
- package/dist/harness.test-util.js +176 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +33 -0
- package/dist/main.d.ts +13 -0
- package/dist/main.js +35 -0
- package/dist/plugins.d.ts +105 -0
- package/dist/plugins.js +97 -0
- package/dist/question-registry.d.ts +124 -0
- package/dist/question-registry.js +212 -0
- package/dist/question-rows.d.ts +32 -0
- package/dist/question-rows.js +43 -0
- package/dist/replay/compare.d.ts +47 -0
- package/dist/replay/compare.js +89 -0
- package/dist/replay/e2e-replay.d.ts +46 -0
- package/dist/replay/e2e-replay.js +91 -0
- package/dist/replay/expect-compact.d.ts +31 -0
- package/dist/replay/expect-compact.js +92 -0
- package/dist/replay/fixtures.d.ts +52 -0
- package/dist/replay/fixtures.js +53 -0
- package/dist/replay/host.d.ts +32 -0
- package/dist/replay/host.js +62 -0
- package/dist/replay/index.d.ts +16 -0
- package/dist/replay/index.js +16 -0
- package/dist/replay/probes.d.ts +55 -0
- package/dist/replay/probes.js +225 -0
- package/dist/replay/report.d.ts +13 -0
- package/dist/replay/report.js +103 -0
- package/dist/replay/session-e2e.d.ts +44 -0
- package/dist/replay/session-e2e.js +91 -0
- package/dist/routes.d.ts +47 -0
- package/dist/routes.js +59 -0
- package/dist/runtime/attachments-llm.d.ts +13 -0
- package/dist/runtime/attachments-llm.js +37 -0
- package/dist/runtime/boot-recovery.d.ts +32 -0
- package/dist/runtime/boot-recovery.js +71 -0
- package/dist/runtime/context-snapshot.d.ts +59 -0
- package/dist/runtime/context-snapshot.js +113 -0
- package/dist/runtime/engine-grants.d.ts +121 -0
- package/dist/runtime/engine-grants.js +338 -0
- package/dist/runtime/engine-permissions.d.ts +29 -0
- package/dist/runtime/engine-permissions.js +92 -0
- package/dist/runtime/engine-plugins.d.ts +189 -0
- package/dist/runtime/engine-plugins.js +292 -0
- package/dist/runtime/engine-profile.d.ts +28 -0
- package/dist/runtime/engine-profile.js +88 -0
- package/dist/runtime/engine-session.d.ts +9 -0
- package/dist/runtime/engine-session.js +9 -0
- package/dist/runtime/fallback-contract.d.ts +32 -0
- package/dist/runtime/fallback-contract.js +10 -0
- package/dist/runtime/fallback-host.d.ts +134 -0
- package/dist/runtime/fallback-host.js +299 -0
- package/dist/runtime/host-autowake.d.ts +79 -0
- package/dist/runtime/host-autowake.js +86 -0
- package/dist/runtime/image-downgrade.d.ts +49 -0
- package/dist/runtime/image-downgrade.js +90 -0
- package/dist/runtime/inbox-message.d.ts +11 -0
- package/dist/runtime/inbox-message.js +20 -0
- package/dist/runtime/index.d.ts +17 -0
- package/dist/runtime/index.js +17 -0
- package/dist/runtime/ledger-view.d.ts +40 -0
- package/dist/runtime/ledger-view.js +56 -0
- package/dist/runtime/llm-assembly.d.ts +66 -0
- package/dist/runtime/llm-assembly.js +114 -0
- package/dist/runtime/offline-llm.d.ts +71 -0
- package/dist/runtime/offline-llm.js +132 -0
- package/dist/runtime/provider-target.d.ts +10 -0
- package/dist/runtime/provider-target.js +10 -0
- package/dist/runtime/question-host.d.ts +33 -0
- package/dist/runtime/question-host.js +41 -0
- package/dist/runtime/question-view.d.ts +48 -0
- package/dist/runtime/question-view.js +76 -0
- package/dist/runtime/real-runtime-adapter.d.ts +95 -0
- package/dist/runtime/real-runtime-adapter.js +553 -0
- package/dist/runtime/recovery-audit.d.ts +81 -0
- package/dist/runtime/recovery-audit.js +95 -0
- package/dist/runtime/recovery-view.d.ts +36 -0
- package/dist/runtime/recovery-view.js +63 -0
- package/dist/runtime/session-compose.d.ts +235 -0
- package/dist/runtime/session-compose.js +350 -0
- package/dist/runtime/session-grants.d.ts +36 -0
- package/dist/runtime/session-grants.js +69 -0
- package/dist/runtime/session-lifecycle.d.ts +40 -0
- package/dist/runtime/session-lifecycle.js +86 -0
- package/dist/runtime/session-publisher.d.ts +40 -0
- package/dist/runtime/session-publisher.js +48 -0
- package/dist/runtime/session-release.d.ts +53 -0
- package/dist/runtime/session-release.js +80 -0
- package/dist/runtime/test-util.d.ts +78 -0
- package/dist/runtime/test-util.js +162 -0
- package/dist/runtime/watchdog-view.d.ts +33 -0
- package/dist/runtime/watchdog-view.js +45 -0
- package/dist/runtime/worker-bridge.d.ts +76 -0
- package/dist/runtime/worker-bridge.js +156 -0
- package/dist/runtime/worker-live.d.ts +22 -0
- package/dist/runtime/worker-live.js +25 -0
- package/dist/runtime/worker-recovery.d.ts +35 -0
- package/dist/runtime/worker-recovery.js +64 -0
- package/dist/runtime/worker-table.d.ts +58 -0
- package/dist/runtime/worker-table.js +70 -0
- package/dist/runtime-adapter.d.ts +421 -0
- package/dist/runtime-adapter.js +76 -0
- package/dist/serial-queue.d.ts +16 -0
- package/dist/serial-queue.js +22 -0
- package/dist/server.d.ts +44 -0
- package/dist/server.js +119 -0
- package/dist/settings.d.ts +23 -0
- package/dist/settings.js +31 -0
- package/dist/sse.d.ts +67 -0
- package/dist/sse.js +186 -0
- package/dist/static.d.ts +20 -0
- package/dist/static.js +120 -0
- package/dist/store/builtin-sections.d.ts +52 -0
- package/dist/store/builtin-sections.js +118 -0
- package/dist/store/celestea-home.d.ts +12 -0
- package/dist/store/celestea-home.js +11 -0
- package/dist/store/fs-json.d.ts +51 -0
- package/dist/store/fs-json.js +119 -0
- package/dist/store/grants-audit.d.ts +84 -0
- package/dist/store/grants-audit.js +109 -0
- package/dist/store/grants-service.d.ts +44 -0
- package/dist/store/grants-service.js +41 -0
- package/dist/store/grants-tokens.d.ts +62 -0
- package/dist/store/grants-tokens.js +105 -0
- package/dist/store/grants.d.ts +113 -0
- package/dist/store/grants.js +238 -0
- package/dist/store/index.d.ts +36 -0
- package/dist/store/index.js +36 -0
- package/dist/store/mode.d.ts +35 -0
- package/dist/store/mode.js +41 -0
- package/dist/store/permissions.d.ts +61 -0
- package/dist/store/permissions.js +139 -0
- package/dist/store/prompts-compose.d.ts +56 -0
- package/dist/store/prompts-compose.js +62 -0
- package/dist/store/prompts-template.d.ts +26 -0
- package/dist/store/prompts-template.js +99 -0
- package/dist/store/prompts.d.ts +142 -0
- package/dist/store/prompts.js +273 -0
- package/dist/store/provider-probe.d.ts +81 -0
- package/dist/store/provider-probe.js +154 -0
- package/dist/store/providers.d.ts +97 -0
- package/dist/store/providers.js +219 -0
- package/dist/store/result.d.ts +29 -0
- package/dist/store/result.js +30 -0
- package/dist/store/session-id.d.ts +119 -0
- package/dist/store/session-id.js +220 -0
- package/dist/store/session-meta.d.ts +41 -0
- package/dist/store/session-meta.js +66 -0
- package/dist/store/session-ops.d.ts +109 -0
- package/dist/store/session-ops.js +264 -0
- package/dist/store/session-tools.d.ts +42 -0
- package/dist/store/session-tools.js +69 -0
- package/dist/store/sessions.d.ts +162 -0
- package/dist/store/sessions.js +307 -0
- package/dist/store/validate.d.ts +13 -0
- package/dist/store/validate.js +38 -0
- package/dist/store/workspaces.d.ts +67 -0
- package/dist/store/workspaces.js +228 -0
- package/dist/user-questions.d.ts +58 -0
- package/dist/user-questions.js +157 -0
- package/dist/version.d.ts +14 -0
- package/dist/version.js +52 -0
- package/package.json +38 -0
- package/webdist/assets/index-Bngs7gUm.js +98 -0
- package/webdist/assets/index-Bu6ci_rN.css +1 -0
- package/webdist/assets/katex-CCbS2qAY.js +257 -0
- package/webdist/assets/mhchem-CnUN8HwY.js +1 -0
- package/webdist/build-meta.json +7 -0
- package/webdist/index.html +261 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W782 — the deployment facts the system prompt is allowed to state, and the
|
|
3
|
+
* ONE place each of them is written down.
|
|
4
|
+
*
|
|
5
|
+
* Why this module exists. The `environment` prompt section (order 200) used to
|
|
6
|
+
* spell out this checkout's absolute paths BY HAND:
|
|
7
|
+
*
|
|
8
|
+
* "…the TypeScript service in /src/celestea_studio-ts (Hono, systemd unit
|
|
9
|
+
* celestea-studio-ts on 127.0.0.1:3777; public site https://studio.celestea.top).
|
|
10
|
+
* … the frontend is /src/celestea_studio-ts/apps/web …"
|
|
11
|
+
*
|
|
12
|
+
* The same fact therefore existed TWICE and independently: once in the real
|
|
13
|
+
* deployment (the systemd unit, the config, this checkout) and once as prose in
|
|
14
|
+
* a prompt template. Nothing tied them together, so when the repo moved
|
|
15
|
+
* (`celestea_studio` -> `celestea_studio-ts`), when the frontend was merged in
|
|
16
|
+
* (`frontend/` -> `apps/web`) and when the data dir moved out of the tree
|
|
17
|
+
* (W781), the template had to be edited by hand each time — and a forgotten edit
|
|
18
|
+
* makes the agent confidently describe a layout that no longer exists. W768 was
|
|
19
|
+
* exactly that failure (`pwd` was one workspace while the prompt named another).
|
|
20
|
+
*
|
|
21
|
+
* The rule this module enforces: **derive what can be derived, and keep the one
|
|
22
|
+
* irreducible literal in a single named constant.** The template may only
|
|
23
|
+
* reference `{{...}}` variables; `apps/studio/src/store/prompts.test.ts` fails
|
|
24
|
+
* the build if an absolute path literal ever reappears in a template string.
|
|
25
|
+
*
|
|
26
|
+
* Derivation precedence, per fact:
|
|
27
|
+
* repo root <- this file's own location, walked up to the workspace marker
|
|
28
|
+
* (never the cwd, never an env var, never a literal)
|
|
29
|
+
* frontend <- repo root + apps/web
|
|
30
|
+
* static root <- `config.paths.staticRoot` (already an operator setting)
|
|
31
|
+
* bind <- `config.bind` (already an operator setting)
|
|
32
|
+
* unit name <- CELESTEA_SERVICE_NAME ?? /proc/self/cgroup ?? [SERVICE_FALLBACK]
|
|
33
|
+
* public site <- [PUBLIC_SITE] (irreducible: nothing in this process knows
|
|
34
|
+
* which DNS name the tunnel/Nginx answers on)
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Operator override for the systemd unit name stated in the prompt. Set it in
|
|
38
|
+
* the unit (`Environment=CELESTEA_SERVICE_NAME=…`) when the unit is renamed;
|
|
39
|
+
* this beats both the cgroup guess and [SERVICE_FALLBACK].
|
|
40
|
+
*/
|
|
41
|
+
export declare const ENV_SERVICE_NAME = "CELESTEA_SERVICE_NAME";
|
|
42
|
+
/**
|
|
43
|
+
* The ONLY hand-written copy of this deployment's unit name. Used when neither
|
|
44
|
+
* `CELESTEA_SERVICE_NAME` nor `/proc/self/cgroup` yields one (e.g. a bare
|
|
45
|
+
* `tsx src/main.ts` outside systemd). If you rename the unit, either set the env
|
|
46
|
+
* var or update this line — it must never be repeated anywhere else.
|
|
47
|
+
*/
|
|
48
|
+
export declare const SERVICE_FALLBACK = "celestea-studio-ts.service";
|
|
49
|
+
/**
|
|
50
|
+
* The public site. Irreducible from inside this process: it is a DNS/tunnel
|
|
51
|
+
* fact, not a fact about this checkout. The ONLY copy; templates reference
|
|
52
|
+
* `{{studio_site}}`.
|
|
53
|
+
*/
|
|
54
|
+
export declare const PUBLIC_SITE = "https://studio.celestea.top";
|
|
55
|
+
/** Parse a systemd unit out of `/proc/self/cgroup` text (pure, testable). */
|
|
56
|
+
export declare function systemdUnitNameFromCgroup(text: string): string | null;
|
|
57
|
+
export declare function studioRepoRoot(): string;
|
|
58
|
+
/** The bundled frontend root (`<package>/webdist`) when the build staged one. */
|
|
59
|
+
export declare function packagedWebDist(): string | null;
|
|
60
|
+
/** What the prompt may say about this deployment — every field derived. */
|
|
61
|
+
export interface DeploymentFacts {
|
|
62
|
+
/** `{{studio_repo}}` — this checkout's root. */
|
|
63
|
+
repo: string;
|
|
64
|
+
/** `{{studio_frontend_dir}}` — where the frontend sources live. */
|
|
65
|
+
frontendDir: string;
|
|
66
|
+
/** `{{studio_static_root}}` — where the built frontend is served from. */
|
|
67
|
+
staticRoot: string;
|
|
68
|
+
/** `{{studio_service}}` — the systemd unit name. */
|
|
69
|
+
service: string;
|
|
70
|
+
/** `{{studio_bind}}` — host:port the backend listens on. */
|
|
71
|
+
bind: string;
|
|
72
|
+
/** `{{studio_site}}` — the public site. */
|
|
73
|
+
publicSite: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The two operator settings this module reads, taken STRUCTURALLY rather than as
|
|
77
|
+
* `StudioConfig`. `config.ts` derives its default static root from
|
|
78
|
+
* `studioRepoRoot()` in this file, so importing `StudioConfig` here would make
|
|
79
|
+
* the two modules depend on each other (`no-circular`). A structural parameter
|
|
80
|
+
* keeps the edge one-way.
|
|
81
|
+
*/
|
|
82
|
+
export interface DeploymentConfigInput {
|
|
83
|
+
bind: string;
|
|
84
|
+
paths: {
|
|
85
|
+
staticRoot: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve every fact the `environment` section states. `env` is read for the
|
|
90
|
+
* unit-name override only; `config` supplies the two operator settings.
|
|
91
|
+
*/
|
|
92
|
+
export declare function deploymentFacts(config: DeploymentConfigInput, env?: NodeJS.ProcessEnv): DeploymentFacts;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W782 — the deployment facts the system prompt is allowed to state, and the
|
|
3
|
+
* ONE place each of them is written down.
|
|
4
|
+
*
|
|
5
|
+
* Why this module exists. The `environment` prompt section (order 200) used to
|
|
6
|
+
* spell out this checkout's absolute paths BY HAND:
|
|
7
|
+
*
|
|
8
|
+
* "…the TypeScript service in /src/celestea_studio-ts (Hono, systemd unit
|
|
9
|
+
* celestea-studio-ts on 127.0.0.1:3777; public site https://studio.celestea.top).
|
|
10
|
+
* … the frontend is /src/celestea_studio-ts/apps/web …"
|
|
11
|
+
*
|
|
12
|
+
* The same fact therefore existed TWICE and independently: once in the real
|
|
13
|
+
* deployment (the systemd unit, the config, this checkout) and once as prose in
|
|
14
|
+
* a prompt template. Nothing tied them together, so when the repo moved
|
|
15
|
+
* (`celestea_studio` -> `celestea_studio-ts`), when the frontend was merged in
|
|
16
|
+
* (`frontend/` -> `apps/web`) and when the data dir moved out of the tree
|
|
17
|
+
* (W781), the template had to be edited by hand each time — and a forgotten edit
|
|
18
|
+
* makes the agent confidently describe a layout that no longer exists. W768 was
|
|
19
|
+
* exactly that failure (`pwd` was one workspace while the prompt named another).
|
|
20
|
+
*
|
|
21
|
+
* The rule this module enforces: **derive what can be derived, and keep the one
|
|
22
|
+
* irreducible literal in a single named constant.** The template may only
|
|
23
|
+
* reference `{{...}}` variables; `apps/studio/src/store/prompts.test.ts` fails
|
|
24
|
+
* the build if an absolute path literal ever reappears in a template string.
|
|
25
|
+
*
|
|
26
|
+
* Derivation precedence, per fact:
|
|
27
|
+
* repo root <- this file's own location, walked up to the workspace marker
|
|
28
|
+
* (never the cwd, never an env var, never a literal)
|
|
29
|
+
* frontend <- repo root + apps/web
|
|
30
|
+
* static root <- `config.paths.staticRoot` (already an operator setting)
|
|
31
|
+
* bind <- `config.bind` (already an operator setting)
|
|
32
|
+
* unit name <- CELESTEA_SERVICE_NAME ?? /proc/self/cgroup ?? [SERVICE_FALLBACK]
|
|
33
|
+
* public site <- [PUBLIC_SITE] (irreducible: nothing in this process knows
|
|
34
|
+
* which DNS name the tunnel/Nginx answers on)
|
|
35
|
+
*/
|
|
36
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
37
|
+
import { dirname, join } from "node:path";
|
|
38
|
+
import { fileURLToPath } from "node:url";
|
|
39
|
+
/** The workspace marker that identifies this repository's root. */
|
|
40
|
+
const REPO_MARKER = "pnpm-workspace.yaml";
|
|
41
|
+
/** `{{studio_frontend_dir}}` is the repo root plus this, and nothing else. */
|
|
42
|
+
const FRONTEND_SUBDIR = ["apps", "web"];
|
|
43
|
+
/**
|
|
44
|
+
* Operator override for the systemd unit name stated in the prompt. Set it in
|
|
45
|
+
* the unit (`Environment=CELESTEA_SERVICE_NAME=…`) when the unit is renamed;
|
|
46
|
+
* this beats both the cgroup guess and [SERVICE_FALLBACK].
|
|
47
|
+
*/
|
|
48
|
+
export const ENV_SERVICE_NAME = "CELESTEA_SERVICE_NAME";
|
|
49
|
+
/**
|
|
50
|
+
* The ONLY hand-written copy of this deployment's unit name. Used when neither
|
|
51
|
+
* `CELESTEA_SERVICE_NAME` nor `/proc/self/cgroup` yields one (e.g. a bare
|
|
52
|
+
* `tsx src/main.ts` outside systemd). If you rename the unit, either set the env
|
|
53
|
+
* var or update this line — it must never be repeated anywhere else.
|
|
54
|
+
*/
|
|
55
|
+
export const SERVICE_FALLBACK = "celestea-studio-ts.service";
|
|
56
|
+
/**
|
|
57
|
+
* The public site. Irreducible from inside this process: it is a DNS/tunnel
|
|
58
|
+
* fact, not a fact about this checkout. The ONLY copy; templates reference
|
|
59
|
+
* `{{studio_site}}`.
|
|
60
|
+
*/
|
|
61
|
+
export const PUBLIC_SITE = "https://studio.celestea.top";
|
|
62
|
+
/** Parse a systemd unit out of `/proc/self/cgroup` text (pure, testable). */
|
|
63
|
+
export function systemdUnitNameFromCgroup(text) {
|
|
64
|
+
// Each line is `hierarchy:controllers:/path`; the unit is the LAST path
|
|
65
|
+
// segment of whichever line names one (`0::/system.slice/foo.service`).
|
|
66
|
+
for (const line of text.split("\n")) {
|
|
67
|
+
const path = line.slice(line.lastIndexOf(":") + 1).trim();
|
|
68
|
+
const segment = path.slice(path.lastIndexOf("/") + 1);
|
|
69
|
+
if (segment.endsWith(".service"))
|
|
70
|
+
return segment;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/** `/proc/self/cgroup` of this process, or null when unreadable. */
|
|
75
|
+
function cgroupUnitName() {
|
|
76
|
+
try {
|
|
77
|
+
return systemdUnitNameFromCgroup(readFileSync("/proc/self/cgroup", "utf8"));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The repository root, derived from THIS file's location: `src/deployment.ts`
|
|
85
|
+
* sits directly under `apps/studio`, so walking up until the workspace marker
|
|
86
|
+
* appears is stable under any cwd, any symlinked launcher and any rename of the
|
|
87
|
+
* checkout directory. Falls back to walking up from the cwd, then throws —
|
|
88
|
+
* a wrong prompt is worse than a loud startup failure.
|
|
89
|
+
*/
|
|
90
|
+
/** The checkout root (marker found), or null when running from an install. */
|
|
91
|
+
function workspaceMarkerRoot() {
|
|
92
|
+
const starts = [dirname(fileURLToPath(import.meta.url)), process.cwd()];
|
|
93
|
+
for (const start of starts) {
|
|
94
|
+
for (let dir = start;;) {
|
|
95
|
+
if (existsSync(join(dir, REPO_MARKER)))
|
|
96
|
+
return dir;
|
|
97
|
+
const parent = dirname(dir);
|
|
98
|
+
if (parent === dir)
|
|
99
|
+
break;
|
|
100
|
+
dir = parent;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* H (packaging): the installed package root. After `npm i -g celestea-agent`
|
|
107
|
+
* there is no `pnpm-workspace.yaml`, so the nearest `package.json` above this
|
|
108
|
+
* module IS the deployment root. Never throws; null when nothing matches.
|
|
109
|
+
*/
|
|
110
|
+
function packageRoot() {
|
|
111
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
112
|
+
for (let i = 0; i < 8; i++) {
|
|
113
|
+
if (existsSync(join(dir, "package.json")))
|
|
114
|
+
return dir;
|
|
115
|
+
const parent = dirname(dir);
|
|
116
|
+
if (parent === dir)
|
|
117
|
+
break;
|
|
118
|
+
dir = parent;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
export function studioRepoRoot() {
|
|
123
|
+
const workspace = workspaceMarkerRoot();
|
|
124
|
+
if (workspace !== null)
|
|
125
|
+
return workspace;
|
|
126
|
+
const packaged = packageRoot();
|
|
127
|
+
if (packaged !== null)
|
|
128
|
+
return packaged;
|
|
129
|
+
throw new Error(`cannot derive the studio repo root: no ${REPO_MARKER} above ${fileURLToPath(import.meta.url)} or ${process.cwd()}`);
|
|
130
|
+
}
|
|
131
|
+
/** The bundled frontend root (`<package>/webdist`) when the build staged one. */
|
|
132
|
+
export function packagedWebDist() {
|
|
133
|
+
const root = packageRoot();
|
|
134
|
+
if (root === null)
|
|
135
|
+
return null;
|
|
136
|
+
const candidate = join(root, "webdist");
|
|
137
|
+
return existsSync(join(candidate, "index.html")) ? candidate : null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Resolve every fact the `environment` section states. `env` is read for the
|
|
141
|
+
* unit-name override only; `config` supplies the two operator settings.
|
|
142
|
+
*/
|
|
143
|
+
export function deploymentFacts(config, env = process.env) {
|
|
144
|
+
const repo = studioRepoRoot();
|
|
145
|
+
const override = env[ENV_SERVICE_NAME];
|
|
146
|
+
return {
|
|
147
|
+
repo,
|
|
148
|
+
frontendDir: join(repo, ...FRONTEND_SUBDIR),
|
|
149
|
+
staticRoot: config.paths.staticRoot,
|
|
150
|
+
service: override !== undefined && override !== "" ? override : (cgroupUnitName() ?? SERVICE_FALLBACK),
|
|
151
|
+
bind: config.bind,
|
|
152
|
+
publicSite: PUBLIC_SITE,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fake `RuntimeAdapter` — the P4 stand-in for the engine.
|
|
3
|
+
*
|
|
4
|
+
* The real runtime arrives on another workstream; until it does, this adapter
|
|
5
|
+
* lets the whole HTTP contract be exercised end to end: it owns the
|
|
6
|
+
* single-concurrency slot, emits the contract SSE events on a scripted turn,
|
|
7
|
+
* and answers the worker/compact/status calls deterministically.
|
|
8
|
+
*
|
|
9
|
+
* W513: the fake models the same SESSION-SCOPED contract as the real adapter —
|
|
10
|
+
* one busy slot per session, `inject()` for a busy session (the interjection is
|
|
11
|
+
* recorded and asserted by the HTTP tests), `ensureSession()` for activate — so
|
|
12
|
+
* the handler tests exercise the real routing rules.
|
|
13
|
+
*
|
|
14
|
+
* It is a *test/development* adapter, never a production engine: the scripted
|
|
15
|
+
* turn is an echo and no model is ever called.
|
|
16
|
+
*/
|
|
17
|
+
import { type ContextMessageView, type EngineProfile, type RuntimeAdapter, type ToolInfo } from "./runtime-adapter.js";
|
|
18
|
+
export interface FakeRuntimeOptions {
|
|
19
|
+
profile?: Partial<EngineProfile>;
|
|
20
|
+
tools?: readonly ToolInfo[];
|
|
21
|
+
/** Yield between scripted frames so a test can observe the stream. */
|
|
22
|
+
stepDelayMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* W725: scripted context snapshot. The fake owns no session log, so the
|
|
25
|
+
* "model-visible context" is whatever the test plants; absent = the profile's
|
|
26
|
+
* system prompt with no history.
|
|
27
|
+
*/
|
|
28
|
+
context?: {
|
|
29
|
+
system?: string;
|
|
30
|
+
messages?: readonly ContextMessageView[];
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** `RuntimeAdapter` plus the test hook that waits for a scripted turn to end. */
|
|
34
|
+
export interface FakeRuntimeAdapter extends RuntimeAdapter {
|
|
35
|
+
whenIdle(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function createFakeRuntimeAdapter(opts?: FakeRuntimeOptions): FakeRuntimeAdapter;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fake `RuntimeAdapter` — the P4 stand-in for the engine.
|
|
3
|
+
*
|
|
4
|
+
* The real runtime arrives on another workstream; until it does, this adapter
|
|
5
|
+
* lets the whole HTTP contract be exercised end to end: it owns the
|
|
6
|
+
* single-concurrency slot, emits the contract SSE events on a scripted turn,
|
|
7
|
+
* and answers the worker/compact/status calls deterministically.
|
|
8
|
+
*
|
|
9
|
+
* W513: the fake models the same SESSION-SCOPED contract as the real adapter —
|
|
10
|
+
* one busy slot per session, `inject()` for a busy session (the interjection is
|
|
11
|
+
* recorded and asserted by the HTTP tests), `ensureSession()` for activate — so
|
|
12
|
+
* the handler tests exercise the real routing rules.
|
|
13
|
+
*
|
|
14
|
+
* It is a *test/development* adapter, never a production engine: the scripted
|
|
15
|
+
* turn is an echo and no model is ever called.
|
|
16
|
+
*/
|
|
17
|
+
import { TurnBusyError, } from "./runtime-adapter.js";
|
|
18
|
+
const DEFAULT_TOOLS = [
|
|
19
|
+
{ name: "http_request", description: "Send an HTTP(S) request and return {status, headers(subset), body, truncated}." },
|
|
20
|
+
{ name: "list_dir", description: "List the entry names in a directory." },
|
|
21
|
+
{ name: "read_file", description: "Read a UTF-8 text file and return its contents as a string." },
|
|
22
|
+
{ name: "write_file", description: "Write a UTF-8 text file." },
|
|
23
|
+
{ name: "run_shell", description: "Run a shell command." },
|
|
24
|
+
];
|
|
25
|
+
function zeroUsage() {
|
|
26
|
+
const block = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, cache_read: 0, cache_hit_ratio: 0, reasoning_tokens: 0 };
|
|
27
|
+
return { ...block, total: { ...block } };
|
|
28
|
+
}
|
|
29
|
+
function defaultProfile(over) {
|
|
30
|
+
return {
|
|
31
|
+
model: "unknown",
|
|
32
|
+
base_url: "http://127.0.0.1:3001/v1",
|
|
33
|
+
reasoning_effort: null,
|
|
34
|
+
max_steps: 4096,
|
|
35
|
+
max_parallel_tool_calls: 4,
|
|
36
|
+
max_output_tokens: null,
|
|
37
|
+
context_window: 1_000_000,
|
|
38
|
+
api_key_env: "CELESTEA_API_KEY",
|
|
39
|
+
system_prompt: "",
|
|
40
|
+
...over,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function countBy(rows, key) {
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const w of rows)
|
|
46
|
+
out[w[key]] = (out[w[key]] ?? 0) + 1;
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
class FakeRuntime {
|
|
50
|
+
name = "fake-runtime-adapter";
|
|
51
|
+
engineProfile;
|
|
52
|
+
toolList;
|
|
53
|
+
workers = new Map();
|
|
54
|
+
transcripts = new Map();
|
|
55
|
+
delay;
|
|
56
|
+
/** W725: the scripted model-visible context of `sessionContext()`. */
|
|
57
|
+
context;
|
|
58
|
+
bus = null;
|
|
59
|
+
busy = false;
|
|
60
|
+
turn = 0;
|
|
61
|
+
idleWaiters = [];
|
|
62
|
+
/** Session -> its own turn counter (W513). */
|
|
63
|
+
turns = new Map();
|
|
64
|
+
/** Session -> messages delivered into a running turn (W513). */
|
|
65
|
+
injected = new Map();
|
|
66
|
+
/** Session -> live runtime (W513 registry stand-in). */
|
|
67
|
+
live = new Set();
|
|
68
|
+
constructor(opts) {
|
|
69
|
+
this.engineProfile = defaultProfile(opts.profile ?? {});
|
|
70
|
+
this.toolList = opts.tools ?? DEFAULT_TOOLS;
|
|
71
|
+
this.delay = opts.stepDelayMs ?? 0;
|
|
72
|
+
this.context = opts.context ?? {};
|
|
73
|
+
}
|
|
74
|
+
attach(next) {
|
|
75
|
+
this.bus = next;
|
|
76
|
+
}
|
|
77
|
+
isBusy(_session) {
|
|
78
|
+
return this.busy;
|
|
79
|
+
}
|
|
80
|
+
/** Same decision table as the real adapter: busy+steer -> steering, else queued. */
|
|
81
|
+
inject(req) {
|
|
82
|
+
const key = req.session ?? "";
|
|
83
|
+
const queued = this.injected.get(key) ?? [];
|
|
84
|
+
queued.push(req.input);
|
|
85
|
+
this.injected.set(key, queued);
|
|
86
|
+
// W847: the same lane split as the real adapter (an explicit "queue" never steers).
|
|
87
|
+
const steering = this.busy && req.mode !== "queue";
|
|
88
|
+
const placement = steering ? "steering" : "queued";
|
|
89
|
+
this.emit("status", { phase: "progress", placement, statusline: this.statusline() }, this.turns.get(key) ?? 0, req.session);
|
|
90
|
+
return { turn: this.turns.get(key) ?? 0, injected: steering, pending: queued.length, placement, duplicate: false };
|
|
91
|
+
}
|
|
92
|
+
/** Messages injected into the given session's turn (test assertion hook). */
|
|
93
|
+
injectedInto(session) {
|
|
94
|
+
return [...(this.injected.get(session ?? "") ?? [])];
|
|
95
|
+
}
|
|
96
|
+
ensureSession(session) {
|
|
97
|
+
const created = !this.live.has(session ?? "");
|
|
98
|
+
this.live.add(session ?? "");
|
|
99
|
+
return { runtime: created ? "created" : "reused", busy: this.busy, rebuilt: false };
|
|
100
|
+
}
|
|
101
|
+
liveSessions() {
|
|
102
|
+
return [...this.live].filter((id) => id !== "");
|
|
103
|
+
}
|
|
104
|
+
busySessions() {
|
|
105
|
+
return this.busy ? this.liveSessions() : [];
|
|
106
|
+
}
|
|
107
|
+
profile() {
|
|
108
|
+
return this.engineProfile;
|
|
109
|
+
}
|
|
110
|
+
async configure(patch) {
|
|
111
|
+
this.engineProfile = { ...this.engineProfile, ...patch };
|
|
112
|
+
return this.engineProfile;
|
|
113
|
+
}
|
|
114
|
+
tools() {
|
|
115
|
+
return [...this.toolList];
|
|
116
|
+
}
|
|
117
|
+
/** W729: the fake owns no per-session generation, so every session sees the
|
|
118
|
+
* same scripted face (P0: identical in both modes, §1.2). */
|
|
119
|
+
sessionTools(_session) {
|
|
120
|
+
return this.tools();
|
|
121
|
+
}
|
|
122
|
+
/** W725: the scripted context snapshot (this fake owns no engine log). */
|
|
123
|
+
sessionContext(_session) {
|
|
124
|
+
return {
|
|
125
|
+
model: this.engineProfile.model,
|
|
126
|
+
system: this.context.system ?? this.engineProfile.system_prompt,
|
|
127
|
+
tools: this.toolList.map(toolView),
|
|
128
|
+
messages: [...(this.context.messages ?? [])],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
statusline() {
|
|
132
|
+
return {
|
|
133
|
+
model: this.engineProfile.model,
|
|
134
|
+
reasoning_effort: this.engineProfile.reasoning_effort,
|
|
135
|
+
steps: 0,
|
|
136
|
+
tokens_per_sec: 0,
|
|
137
|
+
// W755 vocabulary: this double drives no engine loop, so it has neither a
|
|
138
|
+
// provider sample nor an assembly -> `none` ("unknown"), never the retired
|
|
139
|
+
// char-vs-token `session_event_chars`.
|
|
140
|
+
context_usage: contextUsageOf(this.engineProfile.context_window),
|
|
141
|
+
usage: zeroUsage(),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
emit(event, payload, envelopeTurn = this.turn, session = null) {
|
|
145
|
+
this.bus?.emit(event, envelopeTurn, payload, session);
|
|
146
|
+
}
|
|
147
|
+
settle() {
|
|
148
|
+
this.busy = false;
|
|
149
|
+
const waiters = this.idleWaiters;
|
|
150
|
+
this.idleWaiters = [];
|
|
151
|
+
for (const w of waiters)
|
|
152
|
+
w();
|
|
153
|
+
}
|
|
154
|
+
whenIdle() {
|
|
155
|
+
return this.busy ? new Promise((resolve) => this.idleWaiters.push(resolve)) : Promise.resolve();
|
|
156
|
+
}
|
|
157
|
+
async pause() {
|
|
158
|
+
if (this.delay > 0)
|
|
159
|
+
await new Promise((r) => setTimeout(r, this.delay));
|
|
160
|
+
}
|
|
161
|
+
/** Scripted turn: start -> text -> done -> turn_end -> completed. */
|
|
162
|
+
async runTurn(req) {
|
|
163
|
+
const session = req.session;
|
|
164
|
+
try {
|
|
165
|
+
this.emit("text", { delta: `echo: ${req.input}` }, this.turn, session);
|
|
166
|
+
await this.pause();
|
|
167
|
+
this.emit("done", { text: `echo: ${req.input}`, tool_calls: [] }, this.turn, session);
|
|
168
|
+
this.emit("turn_end", { outcome: "completed", error: null }, this.turn, session);
|
|
169
|
+
this.emit("status", { phase: "completed", statusline: this.statusline() }, this.turn, session);
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
this.settle();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async startTurn(req) {
|
|
176
|
+
if (this.busy)
|
|
177
|
+
throw new TurnBusyError();
|
|
178
|
+
this.busy = true;
|
|
179
|
+
const key = req.session ?? "";
|
|
180
|
+
this.live.add(key);
|
|
181
|
+
this.turn += 1;
|
|
182
|
+
this.turns.set(key, this.turn);
|
|
183
|
+
this.emit("status", { phase: "start", statusline: this.statusline() }, this.turn, req.session);
|
|
184
|
+
setTimeout(() => void this.runTurn(req), 0);
|
|
185
|
+
return { turn: this.turn, placement: "context" };
|
|
186
|
+
}
|
|
187
|
+
cancel(_session) {
|
|
188
|
+
if (!this.busy)
|
|
189
|
+
return false;
|
|
190
|
+
this.settle();
|
|
191
|
+
this.emit("status", { phase: "cancelled", statusline: this.statusline() });
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
async clear(_session) {
|
|
195
|
+
return { cleared: true };
|
|
196
|
+
}
|
|
197
|
+
async compact(session) {
|
|
198
|
+
return { compacted: false, note: "历史不足,无需压缩", session, rebound: false };
|
|
199
|
+
}
|
|
200
|
+
workerRows() {
|
|
201
|
+
return [...this.workers.values()].map((w) => ({
|
|
202
|
+
id: `worker:${w.sessionId}`,
|
|
203
|
+
workspace: "engine",
|
|
204
|
+
kind: "worker",
|
|
205
|
+
title: w.title,
|
|
206
|
+
model: null,
|
|
207
|
+
// The fake keeps no session metadata: a scripted worker is `standard`.
|
|
208
|
+
mode: "standard",
|
|
209
|
+
size: this.transcripts.get(w.sessionId)?.length ?? 0,
|
|
210
|
+
modified: 0,
|
|
211
|
+
active: false,
|
|
212
|
+
wid: w.wid,
|
|
213
|
+
status: w.status,
|
|
214
|
+
state: w.state,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
workerSessions() {
|
|
218
|
+
return this.workerRows();
|
|
219
|
+
}
|
|
220
|
+
async workerSpawn(req) {
|
|
221
|
+
const sessionId = `session-${this.workers.size + 1}`;
|
|
222
|
+
const title = req.title !== undefined && req.title !== "" ? req.title : req.brief.slice(0, 40);
|
|
223
|
+
this.workers.set(req.wid, { wid: req.wid, sessionId, title, status: "RUNNING", state: "idle", brief: req.brief });
|
|
224
|
+
this.transcripts.set(sessionId, [{ role: "user", content: req.brief }]);
|
|
225
|
+
return { ok: true, sessionId, title, wid: req.wid };
|
|
226
|
+
}
|
|
227
|
+
async workerSend(req) {
|
|
228
|
+
const hit = [...this.workers.values()].find((w) => w.sessionId === req.target || w.wid === req.target);
|
|
229
|
+
if (hit === undefined)
|
|
230
|
+
return { ok: false, delivered: false, error: `unknown worker target '${req.target}'` };
|
|
231
|
+
const log = this.transcripts.get(hit.sessionId) ?? [];
|
|
232
|
+
log.push({ role: "user", content: req.content });
|
|
233
|
+
this.transcripts.set(hit.sessionId, log);
|
|
234
|
+
return { ok: true, delivered: true, target: req.target, wid: hit.wid };
|
|
235
|
+
}
|
|
236
|
+
workerStatus(wid) {
|
|
237
|
+
const all = [...this.workers.values()];
|
|
238
|
+
const by_status = { DONE: 0, FAILED: 0, RUNNING: 0, ...countBy(all, "status") };
|
|
239
|
+
const by_state = { idle: 0, "in-turn": 0, running: 0, ...countBy(all, "state") };
|
|
240
|
+
if (wid === undefined)
|
|
241
|
+
return { ok: all.length > 0, total: all.length, by_status, by_state, workers: all };
|
|
242
|
+
const hit = all.filter((w) => w.wid === wid);
|
|
243
|
+
if (hit.length === 0)
|
|
244
|
+
return { ok: false, total: 0, by_status, by_state, workers: [], wid, error: `no worker ${wid} in registry` };
|
|
245
|
+
return { ok: true, total: hit.length, by_status, by_state, workers: hit, wid };
|
|
246
|
+
}
|
|
247
|
+
workerMessages(sessionId) {
|
|
248
|
+
const sid = sessionId.startsWith("worker:") ? sessionId.slice("worker:".length) : sessionId;
|
|
249
|
+
return this.transcripts.get(sid) ?? null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* W755: the fake engine measures nothing (no provider frame, no assembly), so
|
|
254
|
+
* its context_usage is the honest "unknown" branch: `used:0`, `method:"none"`,
|
|
255
|
+
* and — W755 Fix C — `window:0` (the profile's 1,000,000 is a DISPLAY default,
|
|
256
|
+
* not a real capacity, so it must never become a denominator).
|
|
257
|
+
*/
|
|
258
|
+
function contextUsageOf(contextWindow) {
|
|
259
|
+
const known = Number.isFinite(contextWindow) && contextWindow > 0;
|
|
260
|
+
return {
|
|
261
|
+
used: 0,
|
|
262
|
+
window: 0,
|
|
263
|
+
ratio: 0,
|
|
264
|
+
estimated: true,
|
|
265
|
+
method: "none",
|
|
266
|
+
projected: false,
|
|
267
|
+
window_source: known ? "fallback" : "unknown",
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/** The five scripted tools carry no schema of their own: an empty object one. */
|
|
271
|
+
function toolView(tool) {
|
|
272
|
+
return { name: tool.name, description: tool.description, parameters: { type: "object", properties: {} } };
|
|
273
|
+
}
|
|
274
|
+
export function createFakeRuntimeAdapter(opts = {}) {
|
|
275
|
+
return new FakeRuntime(opts);
|
|
276
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W767 — the three endpoints of Studio's OWN login-cookie gate.
|
|
3
|
+
*
|
|
4
|
+
* GET /login the self-contained login page (always reachable)
|
|
5
|
+
* POST /auth/login verify against Studio's password file, then Set-Cookie
|
|
6
|
+
* GET /auth/check 200/401 for nginx `auth_request` (the actual gate)
|
|
7
|
+
*
|
|
8
|
+
* nginx asks `/auth/check` for every other path and rewrites a 401 into a
|
|
9
|
+
* redirect to `/login`; these three are the only paths exempted there. The
|
|
10
|
+
* backend therefore stays usable from localhost with no cookie (the engine's own
|
|
11
|
+
* API is unchanged) while the public host is gated by the cookie.
|
|
12
|
+
*
|
|
13
|
+
* Hard rules kept here:
|
|
14
|
+
* - the password is verified through `htpasswd -vbi` (stdin, never argv);
|
|
15
|
+
* - a SUCCESSFUL login answers 200 with `Set-Cookie` AND the navigation in the
|
|
16
|
+
* same response (never a 302 — some mobile clients drop the cookie on a
|
|
17
|
+
* redirect);
|
|
18
|
+
* - the cookie value never reaches a log line, and a wrong password and an
|
|
19
|
+
* unknown user are indistinguishable (401 both ways).
|
|
20
|
+
*/
|
|
21
|
+
import type { Hono } from "hono";
|
|
22
|
+
import type { RouteTable } from "../routes.js";
|
|
23
|
+
import { type Deps } from "./common.js";
|
|
24
|
+
export declare function registerAuth(app: Hono, deps: Deps, table: RouteTable): string[];
|