@treeseed/core 0.10.5 → 0.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/forms/Button.astro +3 -0
- package/dist/components/ui/shell/AppShell.astro +3 -0
- package/dist/components/ui/shell/PublicShell.astro +3 -0
- package/dist/components/ui/theme/ThemeMenu.astro +26 -0
- package/dist/components/ui/theme/ThemeScript.astro +1 -0
- package/dist/components/ui/theme/ThemeSelector.astro +2 -2
- package/dist/dev-watch.js +1 -1
- package/dist/dev.d.ts +10 -4
- package/dist/dev.js +418 -19
- package/dist/layouts/AuthoredEntryLayout.astro +1 -1
- package/dist/layouts/BookLayout.astro +1 -1
- package/dist/layouts/ContentLayout.astro +1 -1
- package/dist/layouts/NoteLayout.astro +1 -1
- package/dist/layouts/ProfileLayout.astro +1 -1
- package/dist/pages/docs-runtime/[...slug].astro +1 -1
- package/dist/pages/docs-runtime/index.astro +1 -1
- package/dist/pages/ui/index.astro +2 -0
- package/dist/scripts/paths.js +2 -1
- package/dist/styles/forms.css +15 -9
- package/dist/styles/prose.css +20 -20
- package/dist/styles/theme.css +18 -4
- package/package.json +2 -2
|
@@ -8,6 +8,7 @@ interface Props {
|
|
|
8
8
|
size?: ButtonSize;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
ariaLabel?: string;
|
|
11
|
+
reload?: boolean;
|
|
11
12
|
class?: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -18,6 +19,7 @@ const {
|
|
|
18
19
|
size = 'md',
|
|
19
20
|
disabled = false,
|
|
20
21
|
ariaLabel,
|
|
22
|
+
reload = false,
|
|
21
23
|
class: className,
|
|
22
24
|
} = Astro.props as Props;
|
|
23
25
|
|
|
@@ -34,6 +36,7 @@ const classes = ['ts-button', className].filter(Boolean).join(' ');
|
|
|
34
36
|
aria-label={ariaLabel}
|
|
35
37
|
aria-disabled={disabled ? 'true' : undefined}
|
|
36
38
|
tabindex={disabled ? -1 : undefined}
|
|
39
|
+
data-astro-reload={reload ? true : undefined}
|
|
37
40
|
>
|
|
38
41
|
<slot />
|
|
39
42
|
</a>
|
|
@@ -4,6 +4,7 @@ import '../../../styles/theme.css';
|
|
|
4
4
|
import '../../../styles/ui.css';
|
|
5
5
|
import '../../../styles/forms.css';
|
|
6
6
|
import '../../../styles/app-shell.css';
|
|
7
|
+
import { ClientRouter } from 'astro:transitions';
|
|
7
8
|
import ThemeScript from '../theme/ThemeScript.astro';
|
|
8
9
|
import ThemeMenu from '../theme/ThemeMenu.astro';
|
|
9
10
|
import RailNav from './RailNav.astro';
|
|
@@ -61,6 +62,7 @@ const {
|
|
|
61
62
|
<title>{title}</title>
|
|
62
63
|
<meta name="description" content={description} />
|
|
63
64
|
<ThemeScript defaultScheme={appearance.scheme} defaultMode={appearance.mode} preferDefaultPreference />
|
|
65
|
+
<ClientRouter />
|
|
64
66
|
</head>
|
|
65
67
|
<body>
|
|
66
68
|
<a class="ts-skip-link" href="#main-content">Skip to content</a>
|
|
@@ -84,6 +86,7 @@ const {
|
|
|
84
86
|
variant={action.variant ?? 'secondary'}
|
|
85
87
|
ariaLabel={action.ariaLabel}
|
|
86
88
|
disabled={action.disabled}
|
|
89
|
+
reload={action.reload}
|
|
87
90
|
size="sm"
|
|
88
91
|
>
|
|
89
92
|
{action.label}
|
|
@@ -4,6 +4,7 @@ import '../../../styles/theme.css';
|
|
|
4
4
|
import '../../../styles/ui.css';
|
|
5
5
|
import '../../../styles/forms.css';
|
|
6
6
|
import '../../../styles/app-shell.css';
|
|
7
|
+
import { ClientRouter } from 'astro:transitions';
|
|
7
8
|
import ThemeScript from '../theme/ThemeScript.astro';
|
|
8
9
|
import ThemeMenu from '../theme/ThemeMenu.astro';
|
|
9
10
|
import TopBar from './TopBar.astro';
|
|
@@ -79,6 +80,7 @@ function isCurrentPath(href: string) {
|
|
|
79
80
|
defaultMode={appearance.mode}
|
|
80
81
|
preferDefaultPreference={preferServerAppearance}
|
|
81
82
|
/>
|
|
83
|
+
<ClientRouter />
|
|
82
84
|
<slot name="head" />
|
|
83
85
|
</head>
|
|
84
86
|
<body>
|
|
@@ -130,6 +132,7 @@ function isCurrentPath(href: string) {
|
|
|
130
132
|
variant={action.variant ?? 'secondary'}
|
|
131
133
|
ariaLabel={action.ariaLabel}
|
|
132
134
|
disabled={action.disabled}
|
|
135
|
+
reload={action.reload}
|
|
133
136
|
size="sm"
|
|
134
137
|
>
|
|
135
138
|
{action.label}
|
|
@@ -30,3 +30,29 @@ const {
|
|
|
30
30
|
/>
|
|
31
31
|
</div>
|
|
32
32
|
</details>
|
|
33
|
+
|
|
34
|
+
<script is:inline>
|
|
35
|
+
(() => {
|
|
36
|
+
const bindingKey = '__treeseedThemeMenuDismissBound';
|
|
37
|
+
if (window[bindingKey]) return;
|
|
38
|
+
window[bindingKey] = true;
|
|
39
|
+
|
|
40
|
+
function themeMenuForTarget(target) {
|
|
41
|
+
return target instanceof Element ? target.closest('[data-ts-theme-menu]') : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function closeOpenMenus(except = null) {
|
|
45
|
+
document.querySelectorAll('[data-ts-theme-menu][open]').forEach((menu) => {
|
|
46
|
+
if (menu !== except) menu.removeAttribute('open');
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
document.addEventListener('pointerdown', (event) => {
|
|
51
|
+
closeOpenMenus(themeMenuForTarget(event.target));
|
|
52
|
+
}, true);
|
|
53
|
+
|
|
54
|
+
document.addEventListener('keydown', (event) => {
|
|
55
|
+
if (event.key === 'Escape') closeOpenMenus();
|
|
56
|
+
});
|
|
57
|
+
})();
|
|
58
|
+
</script>
|
|
@@ -84,7 +84,7 @@ const modes = [
|
|
|
84
84
|
) : null}
|
|
85
85
|
</div>
|
|
86
86
|
|
|
87
|
-
<script is:inline define:vars={{ schemes }}>
|
|
87
|
+
<script is:inline data-astro-rerun define:vars={{ schemes }}>
|
|
88
88
|
(() => {
|
|
89
89
|
const schemeKey = 'treeseed_color_scheme';
|
|
90
90
|
const modeKey = 'treeseed_theme_mode';
|
|
@@ -135,7 +135,7 @@ const modes = [
|
|
|
135
135
|
store(modeKey, safeMode);
|
|
136
136
|
}
|
|
137
137
|
window.dispatchEvent(new CustomEvent('treeseed:theme-change', {
|
|
138
|
-
detail: { scheme: safeScheme, mode: safeMode, renderedMode: renderedMode(safeMode) },
|
|
138
|
+
detail: { scheme: safeScheme, mode: safeMode, renderedMode: renderedMode(safeMode), persist },
|
|
139
139
|
}));
|
|
140
140
|
}
|
|
141
141
|
|
package/dist/dev-watch.js
CHANGED
|
@@ -85,7 +85,7 @@ function classifyChanges(changedPaths, watchEntries) {
|
|
|
85
85
|
}
|
|
86
86
|
function isTenantApiInput(filePath) {
|
|
87
87
|
const normalized = filePath.split(sep).join("/");
|
|
88
|
-
return normalized.endsWith("/treeseed.site.yaml") || normalized.endsWith("/treeseed.config.ts") || normalized.endsWith("/package.json") || normalized.endsWith("/tsconfig.json");
|
|
88
|
+
return normalized.endsWith("/treeseed.site.yaml") || normalized.endsWith("/treeseed.config.ts") || normalized.endsWith("/package.json") || normalized.endsWith("/tsconfig.json") || normalized.includes("/src/api/") || normalized.includes("/src/market-operations-runner/");
|
|
89
89
|
}
|
|
90
90
|
const tenantChanged = changedPaths.some(
|
|
91
91
|
(filePath) => watchEntries.some((entry) => entry.kind === "tenant" && matchesEntry(filePath, entry))
|
package/dist/dev.d.ts
CHANGED
|
@@ -8,13 +8,17 @@ export declare const TREESEED_DEFAULT_API_PORT = 3000;
|
|
|
8
8
|
export declare const TREESEED_DEFAULT_LOCAL_SMTP_HOST = "127.0.0.1";
|
|
9
9
|
export declare const TREESEED_DEFAULT_LOCAL_SMTP_PORT = 1025;
|
|
10
10
|
export declare const TREESEED_DEFAULT_MAILPIT_UI_PORT = 8025;
|
|
11
|
+
export declare const TREESEED_DEFAULT_MARKET_POSTGRES_PORT = 55432;
|
|
12
|
+
export declare const TREESEED_DEFAULT_MARKET_POSTGRES_CONTAINER = "treeseed-market-local-postgres";
|
|
13
|
+
export declare const TREESEED_DEFAULT_MARKET_POSTGRES_VOLUME = "treeseed-market-local-postgres-data";
|
|
14
|
+
export declare const TREESEED_DEFAULT_MARKET_POSTGRES_URL = "postgres://treeseed:treeseed@127.0.0.1:55432/market_local";
|
|
11
15
|
export type TreeseedIntegratedDevSurface = 'integrated' | 'all' | 'web' | 'api' | 'manager' | 'worker' | 'agents' | 'services';
|
|
12
16
|
export type TreeseedIntegratedDevSetupMode = 'auto' | 'check' | 'off';
|
|
13
17
|
export type TreeseedIntegratedDevFeedbackMode = 'live' | 'restart' | 'off';
|
|
14
18
|
export type TreeseedIntegratedDevOpenMode = 'auto' | 'on' | 'off';
|
|
15
19
|
export type TreeseedLocalRuntimeMode = 'auto' | 'provider' | 'local';
|
|
16
20
|
export type TreeseedSelectedLocalRuntime = 'astro-local' | 'cloudflare-wrangler-local' | 'node-local';
|
|
17
|
-
export type TreeseedIntegratedDevCommandId = 'web' | 'api' | 'manager' | 'worker' | 'agents';
|
|
21
|
+
export type TreeseedIntegratedDevCommandId = 'web' | 'api' | 'manager' | 'worker' | 'agents' | 'market-runner';
|
|
18
22
|
export type TreeseedLocalRuntimeSelection = {
|
|
19
23
|
requested: TreeseedLocalRuntimeMode;
|
|
20
24
|
selected: TreeseedSelectedLocalRuntime;
|
|
@@ -74,11 +78,11 @@ export type TreeseedIntegratedDevReadinessCheck = {
|
|
|
74
78
|
url?: string;
|
|
75
79
|
};
|
|
76
80
|
export type TreeseedIntegratedDevResetAction = {
|
|
77
|
-
id: 'd1-state' | 'mailpit' | 'wrangler-tmp' | 'worker-bundle' | 'dev-reload';
|
|
81
|
+
id: 'd1-state' | 'generated-d1-state' | 'generated-wrangler-state' | 'legacy-local-sqlite' | 'mailpit' | 'market-postgres' | 'root-wrangler-state' | 'wrangler-tmp' | 'worker-bundle' | 'dev-reload';
|
|
78
82
|
label: string;
|
|
79
83
|
kind: 'path' | 'service';
|
|
80
84
|
path?: string;
|
|
81
|
-
status: 'planned' | 'removed' | 'skipped' | 'failed';
|
|
85
|
+
status: 'planned' | 'removed' | 'refreshed' | 'skipped' | 'failed';
|
|
82
86
|
detail?: string;
|
|
83
87
|
};
|
|
84
88
|
export type TreeseedIntegratedDevResetPlan = {
|
|
@@ -130,6 +134,8 @@ type TreeseedIntegratedDevDependencies = {
|
|
|
130
134
|
startWatch: WatchStarter;
|
|
131
135
|
removePath: (path: string) => void;
|
|
132
136
|
stopMailpitContainers: () => boolean;
|
|
137
|
+
resetMarketPostgres: () => boolean;
|
|
138
|
+
stopMarketPostgres: () => boolean;
|
|
133
139
|
inspectPortOwners: (ports: readonly number[]) => TreeseedDevPortOwner[];
|
|
134
140
|
};
|
|
135
141
|
export type TreeseedDevPortOwner = {
|
|
@@ -145,7 +151,7 @@ export declare function createTreeseedIntegratedDevResetPlan(options: {
|
|
|
145
151
|
enabled?: boolean;
|
|
146
152
|
}): TreeseedIntegratedDevResetPlan | null;
|
|
147
153
|
export declare function createTreeseedIntegratedDevPlan(options?: TreeseedIntegratedDevOptions): TreeseedIntegratedDevPlan;
|
|
148
|
-
export declare function runTreeseedIntegratedDevReset(reset: TreeseedIntegratedDevResetPlan | null, options: Pick<TreeseedIntegratedDevOptions, 'json'>, deps: Pick<TreeseedIntegratedDevDependencies, 'write' | 'removePath' | 'stopMailpitContainers'>): {
|
|
154
|
+
export declare function runTreeseedIntegratedDevReset(reset: TreeseedIntegratedDevResetPlan | null, options: Pick<TreeseedIntegratedDevOptions, 'json'>, deps: Pick<TreeseedIntegratedDevDependencies, 'write' | 'removePath' | 'stopMailpitContainers' | 'resetMarketPostgres'>): {
|
|
149
155
|
actions: TreeseedIntegratedDevResetAction[];
|
|
150
156
|
enabled: boolean;
|
|
151
157
|
preserved: string[];
|
package/dist/dev.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { setTimeout as delay } from "node:timers/promises";
|
|
7
7
|
import { DatabaseSync } from "node:sqlite";
|
|
@@ -31,6 +31,10 @@ const TREESEED_DEFAULT_API_PORT = 3e3;
|
|
|
31
31
|
const TREESEED_DEFAULT_LOCAL_SMTP_HOST = "127.0.0.1";
|
|
32
32
|
const TREESEED_DEFAULT_LOCAL_SMTP_PORT = 1025;
|
|
33
33
|
const TREESEED_DEFAULT_MAILPIT_UI_PORT = 8025;
|
|
34
|
+
const TREESEED_DEFAULT_MARKET_POSTGRES_PORT = 55432;
|
|
35
|
+
const TREESEED_DEFAULT_MARKET_POSTGRES_CONTAINER = "treeseed-market-local-postgres";
|
|
36
|
+
const TREESEED_DEFAULT_MARKET_POSTGRES_VOLUME = "treeseed-market-local-postgres-data";
|
|
37
|
+
const TREESEED_DEFAULT_MARKET_POSTGRES_URL = `postgres://treeseed:treeseed@127.0.0.1:${TREESEED_DEFAULT_MARKET_POSTGRES_PORT}/market_local`;
|
|
34
38
|
const DEV_RELOAD_FILE = "public/__treeseed/dev-reload.json";
|
|
35
39
|
const DEV_RUNTIME_DIR = ".treeseed/generated/dev";
|
|
36
40
|
const DEV_RUNTIME_LEGACY_FILE = ".treeseed/generated/dev/runtime.json";
|
|
@@ -172,6 +176,15 @@ function webUrlFor(host, port) {
|
|
|
172
176
|
return `http://${browserHost(host)}:${port}`;
|
|
173
177
|
}
|
|
174
178
|
const CANONICAL_COMMAND_IDS = ["web", "api", "manager", "worker", "agents"];
|
|
179
|
+
const MARKET_DEV_COMMAND_IDS = ["web", "api", "market-runner"];
|
|
180
|
+
function isMarketWorkspace(tenantRoot) {
|
|
181
|
+
try {
|
|
182
|
+
const pkg = JSON.parse(readFileSync(resolve(tenantRoot, "package.json"), "utf8"));
|
|
183
|
+
return pkg.name === "@treeseed/market" && existsSync(resolve(tenantRoot, "src/api/server.js")) && existsSync(resolve(tenantRoot, "src/market-operations-runner/entrypoint.js"));
|
|
184
|
+
} catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
175
188
|
function surfaceCommandIds(surface) {
|
|
176
189
|
switch (surface) {
|
|
177
190
|
case "web":
|
|
@@ -226,6 +239,15 @@ function dockerComposeIsAvailable(env) {
|
|
|
226
239
|
});
|
|
227
240
|
return (result.status ?? 1) === 0;
|
|
228
241
|
}
|
|
242
|
+
function dockerIsAvailable(env) {
|
|
243
|
+
const docker = resolveTreeseedToolBinary("docker", { env });
|
|
244
|
+
if (!docker) return false;
|
|
245
|
+
const result = spawnSync(docker, ["info"], {
|
|
246
|
+
encoding: "utf8",
|
|
247
|
+
env
|
|
248
|
+
});
|
|
249
|
+
return (result.status ?? 1) === 0;
|
|
250
|
+
}
|
|
229
251
|
function resetActionForPath(id, label, path) {
|
|
230
252
|
return {
|
|
231
253
|
id,
|
|
@@ -236,6 +258,58 @@ function resetActionForPath(id, label, path) {
|
|
|
236
258
|
detail: existsSync(path) ? void 0 : "Path does not exist."
|
|
237
259
|
};
|
|
238
260
|
}
|
|
261
|
+
function uniqueResetActions(actions) {
|
|
262
|
+
const seen = /* @__PURE__ */ new Set();
|
|
263
|
+
return actions.filter((action) => {
|
|
264
|
+
const key = action.kind === "path" ? `${action.kind}:${action.path}` : `${action.kind}:${action.id}`;
|
|
265
|
+
if (seen.has(key)) return false;
|
|
266
|
+
seen.add(key);
|
|
267
|
+
return true;
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function optionalResetActionForPath(id, label, path) {
|
|
271
|
+
return existsSync(path) ? resetActionForPath(id, label, path) : null;
|
|
272
|
+
}
|
|
273
|
+
function pathContains(parent, child) {
|
|
274
|
+
const diff = relative(parent, child);
|
|
275
|
+
return diff === "" || diff.length > 0 && !diff.startsWith("..") && !isAbsolute(diff);
|
|
276
|
+
}
|
|
277
|
+
function knownLocalRuntimeStateResetActions(tenantRoot, activePersistTo) {
|
|
278
|
+
const localGeneratedWranglerState = resolve(tenantRoot, ".treeseed", "generated", "environments", "local", ".wrangler", "state", "v3");
|
|
279
|
+
const rootWranglerState = resolve(tenantRoot, ".wrangler", "state", "v3");
|
|
280
|
+
const stateRoots = [
|
|
281
|
+
optionalResetActionForPath(
|
|
282
|
+
"generated-wrangler-state",
|
|
283
|
+
"Remove generated local Wrangler runtime state",
|
|
284
|
+
localGeneratedWranglerState
|
|
285
|
+
),
|
|
286
|
+
optionalResetActionForPath(
|
|
287
|
+
"root-wrangler-state",
|
|
288
|
+
"Remove root Wrangler runtime state",
|
|
289
|
+
rootWranglerState
|
|
290
|
+
)
|
|
291
|
+
].filter((action) => Boolean(action));
|
|
292
|
+
const coveredByStateRoot = stateRoots.some((action) => action.path && pathContains(action.path, activePersistTo));
|
|
293
|
+
return uniqueResetActions([
|
|
294
|
+
...coveredByStateRoot ? [] : [resetActionForPath("d1-state", "Remove active local D1 state", activePersistTo)],
|
|
295
|
+
...stateRoots,
|
|
296
|
+
optionalResetActionForPath(
|
|
297
|
+
"legacy-local-sqlite",
|
|
298
|
+
"Remove legacy local SQLite state",
|
|
299
|
+
resolve(tenantRoot, ".treeseed", "generated", "environments", "local", "site-data.sqlite")
|
|
300
|
+
)
|
|
301
|
+
].filter((action) => Boolean(action)));
|
|
302
|
+
}
|
|
303
|
+
function isTreeseedManagedMarketPostgresUrl(value) {
|
|
304
|
+
if (!value?.trim()) return true;
|
|
305
|
+
try {
|
|
306
|
+
const url = new URL(value);
|
|
307
|
+
const port = url.port || (url.protocol === "postgres:" || url.protocol === "postgresql:" ? "5432" : "");
|
|
308
|
+
return ["postgres:", "postgresql:"].includes(url.protocol) && ["127.0.0.1", "localhost"].includes(url.hostname) && port === String(TREESEED_DEFAULT_MARKET_POSTGRES_PORT) && url.pathname === "/market_local" && decodeURIComponent(url.username) === "treeseed";
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
239
313
|
function resolveLocalD1SqlitePath(persistTo) {
|
|
240
314
|
if (/\.sqlite$/u.test(persistTo) && existsSync(persistTo)) {
|
|
241
315
|
return persistTo;
|
|
@@ -302,10 +376,12 @@ function createTreeseedIntegratedDevResetPlan(options) {
|
|
|
302
376
|
}
|
|
303
377
|
const tenantRoot = options.tenantRoot;
|
|
304
378
|
const d1PersistTo = options.env.TREESEED_API_D1_LOCAL_PERSIST_TO?.trim() || resolve(tenantRoot, ".wrangler", "state", "v3", "d1");
|
|
379
|
+
const marketWorkspace = isMarketWorkspace(tenantRoot);
|
|
380
|
+
const managedMarketPostgres = options.env.TREESEED_MARKET_LOCAL_POSTGRES_MANAGED === "true";
|
|
305
381
|
return {
|
|
306
382
|
enabled: true,
|
|
307
383
|
actions: [
|
|
308
|
-
|
|
384
|
+
...knownLocalRuntimeStateResetActions(tenantRoot, d1PersistTo),
|
|
309
385
|
{
|
|
310
386
|
id: "mailpit",
|
|
311
387
|
label: options.mailpitEnabled ? "Reset Mailpit email runtime" : "Skip Mailpit email runtime",
|
|
@@ -313,9 +389,23 @@ function createTreeseedIntegratedDevResetPlan(options) {
|
|
|
313
389
|
status: options.mailpitEnabled ? "planned" : "skipped",
|
|
314
390
|
detail: options.mailpitEnabled ? "The Treeseed-managed Mailpit container and inbox will be stopped and removed." : "Docker Compose is unavailable, so Mailpit is disabled for this local dev run."
|
|
315
391
|
},
|
|
392
|
+
...marketWorkspace ? [{
|
|
393
|
+
id: "market-postgres",
|
|
394
|
+
label: managedMarketPostgres ? "Reset local Market PostgreSQL" : "Skip external Market PostgreSQL",
|
|
395
|
+
kind: "service",
|
|
396
|
+
status: managedMarketPostgres ? "planned" : "skipped",
|
|
397
|
+
detail: managedMarketPostgres ? "The Treeseed-managed Market PostgreSQL container, database, and volume will be removed and recreated on the next dev run." : "TREESEED_MARKET_DATABASE_URL points at an external database, so dev reset will not drop it."
|
|
398
|
+
}] : [],
|
|
316
399
|
resetActionForPath("wrangler-tmp", "Remove Wrangler temporary output", resolve(tenantRoot, ".wrangler", "tmp")),
|
|
317
400
|
resetActionForPath("worker-bundle", "Remove generated local worker bundle", resolve(tenantRoot, ".treeseed", "generated", "worker")),
|
|
318
|
-
|
|
401
|
+
{
|
|
402
|
+
id: "dev-reload",
|
|
403
|
+
label: "Refresh browser reload marker",
|
|
404
|
+
kind: "path",
|
|
405
|
+
path: resolve(tenantRoot, DEV_RELOAD_FILE),
|
|
406
|
+
status: "planned",
|
|
407
|
+
detail: "The browser reload marker will be recreated so open tabs do not poll a missing file after reset."
|
|
408
|
+
}
|
|
319
409
|
],
|
|
320
410
|
preserved: [
|
|
321
411
|
".env*",
|
|
@@ -327,7 +417,8 @@ function createTreeseedIntegratedDevResetPlan(options) {
|
|
|
327
417
|
".treeseed/workflow",
|
|
328
418
|
".treeseed/workspace-links.json",
|
|
329
419
|
"migrations",
|
|
330
|
-
"node_modules"
|
|
420
|
+
"node_modules",
|
|
421
|
+
"Treeseed-managed local service containers"
|
|
331
422
|
]
|
|
332
423
|
};
|
|
333
424
|
}
|
|
@@ -390,7 +481,11 @@ function createSetupSteps(tenantRoot, setupMode, sdkPackageRoot, planLike, env,
|
|
|
390
481
|
];
|
|
391
482
|
}
|
|
392
483
|
const hasWebCommand = planLike.commands.some((command) => command.id === "web");
|
|
393
|
-
const hasLocalRuntimeCommand = planLike.commands.some(
|
|
484
|
+
const hasLocalRuntimeCommand = planLike.commands.some(
|
|
485
|
+
(command) => command.id !== "web" && command.id !== "market-runner" && command.label !== "Treeseed Market API"
|
|
486
|
+
);
|
|
487
|
+
const hasMarketApiCommand = planLike.commands.some((command) => command.label === "Treeseed Market API");
|
|
488
|
+
const managedMarketPostgres = env.TREESEED_MARKET_LOCAL_POSTGRES_MANAGED === "true";
|
|
394
489
|
const needsCloudflareLocalRuntime = usesCloudflareWebRuntime || hasLocalRuntimeCommand;
|
|
395
490
|
const coreScripts = [
|
|
396
491
|
["starlight-patch", "Patch Starlight content path", "scripts/patch-starlight-content-path.ts", "dist/scripts/patch-starlight-content-path.js"],
|
|
@@ -406,6 +501,11 @@ function createSetupSteps(tenantRoot, setupMode, sdkPackageRoot, planLike, env,
|
|
|
406
501
|
"scripts/ensure-mailpit.ts",
|
|
407
502
|
"dist/scripts/ensure-mailpit.js"
|
|
408
503
|
);
|
|
504
|
+
const dockerReady = dockerIsAvailable(env);
|
|
505
|
+
const marketMigrateScript = existsSync(resolve(tenantRoot, "scripts/migrate-market-db.mjs")) ? {
|
|
506
|
+
command: process.execPath,
|
|
507
|
+
args: [resolve(tenantRoot, "scripts/migrate-market-db.mjs")]
|
|
508
|
+
} : null;
|
|
409
509
|
const steps = [
|
|
410
510
|
{
|
|
411
511
|
id: "workspace-links",
|
|
@@ -413,6 +513,26 @@ function createSetupSteps(tenantRoot, setupMode, sdkPackageRoot, planLike, env,
|
|
|
413
513
|
required: setupMode === "auto",
|
|
414
514
|
status: "planned"
|
|
415
515
|
},
|
|
516
|
+
...hasMarketApiCommand && managedMarketPostgres ? [
|
|
517
|
+
{
|
|
518
|
+
id: "market-postgres",
|
|
519
|
+
label: "Start local Market PostgreSQL",
|
|
520
|
+
required: true,
|
|
521
|
+
status: dockerReady ? "planned" : "failed",
|
|
522
|
+
detail: dockerReady ? "Treeseed will manage the local Market PostgreSQL container automatically." : "Docker daemon is unavailable; local Market API requires managed PostgreSQL."
|
|
523
|
+
}
|
|
524
|
+
] : [],
|
|
525
|
+
...hasMarketApiCommand ? [
|
|
526
|
+
{
|
|
527
|
+
id: "market-migrations",
|
|
528
|
+
label: "Apply local Market database migrations",
|
|
529
|
+
required: true,
|
|
530
|
+
command: marketMigrateScript?.command,
|
|
531
|
+
args: marketMigrateScript?.args,
|
|
532
|
+
status: marketMigrateScript ? "planned" : "failed",
|
|
533
|
+
detail: marketMigrateScript ? void 0 : "Unable to resolve scripts/migrate-market-db.mjs."
|
|
534
|
+
}
|
|
535
|
+
] : [],
|
|
416
536
|
{
|
|
417
537
|
id: "wrangler",
|
|
418
538
|
label: "Verify Wrangler executable",
|
|
@@ -461,7 +581,7 @@ function createSetupSteps(tenantRoot, setupMode, sdkPackageRoot, planLike, env,
|
|
|
461
581
|
detail: mailpitEnabled ? mailpit ? "Mailpit SMTP will listen on 127.0.0.1:1025 and the web UI on http://127.0.0.1:8025." : "Unable to resolve the Mailpit startup script." : "Docker Compose is unavailable, so Mailpit is disabled for this local dev run."
|
|
462
582
|
}
|
|
463
583
|
];
|
|
464
|
-
if (needsCloudflareLocalRuntime
|
|
584
|
+
if (needsCloudflareLocalRuntime) {
|
|
465
585
|
const migrate = resolveOptionalScriptEntrypoint(
|
|
466
586
|
sdkPackageRoot,
|
|
467
587
|
"scripts/tenant-d1-migrate-local.ts",
|
|
@@ -533,6 +653,48 @@ function createAgentCommand(id, tenantRoot, agentPackageRoot, sharedEnv, apiHost
|
|
|
533
653
|
localRuntime: nodeLocalRuntime(config.label)
|
|
534
654
|
};
|
|
535
655
|
}
|
|
656
|
+
function createMarketApiCommand(tenantRoot, sharedEnv, apiHost, apiPort) {
|
|
657
|
+
return {
|
|
658
|
+
id: "api",
|
|
659
|
+
label: "Treeseed Market API",
|
|
660
|
+
command: process.execPath,
|
|
661
|
+
args: [resolve(tenantRoot, "src/api/server.js")],
|
|
662
|
+
cwd: tenantRoot,
|
|
663
|
+
env: {
|
|
664
|
+
...sharedEnv,
|
|
665
|
+
HOST: apiHost,
|
|
666
|
+
PORT: String(apiPort),
|
|
667
|
+
TREESEED_ENVIRONMENT: sharedEnv.TREESEED_ENVIRONMENT ?? "local",
|
|
668
|
+
TREESEED_API_ENVIRONMENT: sharedEnv.TREESEED_API_ENVIRONMENT ?? "local",
|
|
669
|
+
TREESEED_API_REQUEST_LOGS: sharedEnv.TREESEED_API_REQUEST_LOGS ?? "true"
|
|
670
|
+
},
|
|
671
|
+
localRuntime: nodeLocalRuntime("Treeseed Market API")
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function createMarketOperationsRunnerCommand(tenantRoot, sharedEnv) {
|
|
675
|
+
return {
|
|
676
|
+
id: "market-runner",
|
|
677
|
+
label: "Market Operations Runner",
|
|
678
|
+
command: process.execPath,
|
|
679
|
+
args: [
|
|
680
|
+
"--experimental-transform-types",
|
|
681
|
+
resolve(tenantRoot, "src/market-operations-runner/entrypoint.js"),
|
|
682
|
+
"--market",
|
|
683
|
+
"local",
|
|
684
|
+
"--watch",
|
|
685
|
+
"--operation",
|
|
686
|
+
"project:web_deployment",
|
|
687
|
+
"--poll-interval-ms",
|
|
688
|
+
"5000"
|
|
689
|
+
],
|
|
690
|
+
cwd: tenantRoot,
|
|
691
|
+
env: {
|
|
692
|
+
...sharedEnv,
|
|
693
|
+
TREESEED_PLATFORM_RUNNER_ENVIRONMENT: sharedEnv.TREESEED_PLATFORM_RUNNER_ENVIRONMENT ?? "local"
|
|
694
|
+
},
|
|
695
|
+
localRuntime: nodeLocalRuntime("Market Operations Runner")
|
|
696
|
+
};
|
|
697
|
+
}
|
|
536
698
|
function createTreeseedIntegratedDevPlan(options = {}) {
|
|
537
699
|
const tenantRoot = resolve(options.cwd ?? process.cwd());
|
|
538
700
|
const surface = options.surface ?? "integrated";
|
|
@@ -549,18 +711,23 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
549
711
|
const teamId = options.teamId ?? mergedEnv.TREESEED_HOSTING_TEAM_ID;
|
|
550
712
|
const apiBaseUrl = options.apiHost != null || options.apiPort != null ? `http://${apiHost}:${apiPort}` : mergedEnv.TREESEED_API_BASE_URL?.trim() || `http://${apiHost}:${apiPort}`;
|
|
551
713
|
const selectedCommandIds = selectedSurfaceCommandIds(options);
|
|
552
|
-
const
|
|
714
|
+
const marketWorkspace = isMarketWorkspace(tenantRoot);
|
|
715
|
+
const effectiveCommandIds = marketWorkspace ? MARKET_DEV_COMMAND_IDS.filter((id) => selectedCommandIds.includes(id) || id === "market-runner" && selectedCommandIds.includes("api")) : selectedCommandIds;
|
|
716
|
+
const devResetId = options.reset ? String(Date.now()) : void 0;
|
|
717
|
+
const webUrl = effectiveCommandIds.includes("web") ? webUrlFor(webHost, webPort) : null;
|
|
553
718
|
const sdkPackageRoot = resolvePackageRoot("@treeseed/sdk", tenantRoot);
|
|
554
719
|
const agentPackageRoot = resolvePackageRootEnvOverride(mergedEnv, "TREESEED_AGENT_PACKAGE_ROOT", tenantRoot) ?? resolveOptionalPackageRoot("@treeseed/agent", tenantRoot);
|
|
555
720
|
const cliPackageRoot = resolveOptionalPackageRoot("@treeseed/cli", tenantRoot);
|
|
556
721
|
const deployConfig = loadDevDeployConfig(tenantRoot);
|
|
557
722
|
const webLocalRuntime = selectWebLocalRuntime(deployConfig?.surfaces?.web, fallbackWebProviderFromDeployConfig(deployConfig), options.webRuntime);
|
|
558
723
|
const usesCloudflareWebRuntime = webLocalRuntime.selected === "cloudflare-wrangler-local";
|
|
559
|
-
const usesGeneratedLocalD1State = usesCloudflareWebRuntime || webLocalRuntime.provider === "cloudflare" ||
|
|
724
|
+
const usesGeneratedLocalD1State = usesCloudflareWebRuntime || webLocalRuntime.provider === "cloudflare" || !marketWorkspace && effectiveCommandIds.some((id) => id !== "web");
|
|
560
725
|
const localD1PersistTo = mergedEnv.TREESEED_API_D1_LOCAL_PERSIST_TO ?? (usesGeneratedLocalD1State ? resolve(tenantRoot, ".treeseed", "generated", "environments", "local", ".wrangler", "state", "v3", "d1") : resolve(tenantRoot, ".wrangler", "state", "v3", "d1"));
|
|
561
726
|
const projectId = options.projectId ?? mergedEnv.TREESEED_PROJECT_ID ?? resolveSeededLocalProjectId(localD1PersistTo);
|
|
562
727
|
const resolvedHostingTeamId = teamId ?? mergedEnv.TREESEED_HOSTING_TEAM_ID;
|
|
563
728
|
const resolvedTeamId = mergedEnv.TREESEED_TEAM_ID ?? resolvedHostingTeamId ?? resolveSeededLocalTeamId(localD1PersistTo, projectId ?? null);
|
|
729
|
+
const marketDatabaseUrl = mergedEnv.TREESEED_MARKET_DATABASE_URL ?? TREESEED_DEFAULT_MARKET_POSTGRES_URL;
|
|
730
|
+
const managedMarketPostgres = marketWorkspace && isTreeseedManagedMarketPostgresUrl(marketDatabaseUrl);
|
|
564
731
|
const webEntrypoint = resolveNodeEntrypoint(
|
|
565
732
|
sdkPackageRoot,
|
|
566
733
|
"scripts/tenant-astro-command.ts",
|
|
@@ -590,14 +757,28 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
590
757
|
BETTER_AUTH_URL: mergedEnv.BETTER_AUTH_URL ?? webUrl,
|
|
591
758
|
TREESEED_API_BASE_URL: apiBaseUrl,
|
|
592
759
|
TREESEED_MARKET_API_BASE_URL: mergedEnv.TREESEED_MARKET_API_BASE_URL ?? apiBaseUrl,
|
|
760
|
+
TREESEED_API_REQUEST_LOGS: mergedEnv.TREESEED_API_REQUEST_LOGS ?? "true",
|
|
761
|
+
...marketWorkspace ? {
|
|
762
|
+
TREESEED_MARKET_DATABASE_URL: marketDatabaseUrl,
|
|
763
|
+
TREESEED_MARKET_LOCAL_POSTGRES_CONTAINER: mergedEnv.TREESEED_MARKET_LOCAL_POSTGRES_CONTAINER ?? TREESEED_DEFAULT_MARKET_POSTGRES_CONTAINER,
|
|
764
|
+
TREESEED_MARKET_LOCAL_POSTGRES_VOLUME: mergedEnv.TREESEED_MARKET_LOCAL_POSTGRES_VOLUME ?? TREESEED_DEFAULT_MARKET_POSTGRES_VOLUME,
|
|
765
|
+
TREESEED_MARKET_LOCAL_POSTGRES_PORT: mergedEnv.TREESEED_MARKET_LOCAL_POSTGRES_PORT ?? String(TREESEED_DEFAULT_MARKET_POSTGRES_PORT),
|
|
766
|
+
TREESEED_MARKET_LOCAL_POSTGRES_MANAGED: managedMarketPostgres ? "true" : "false"
|
|
767
|
+
} : {},
|
|
593
768
|
TREESEED_PROJECT_ID: projectId ?? mergedEnv.TREESEED_PROJECT_ID,
|
|
594
769
|
TREESEED_TEAM_ID: resolvedTeamId ?? mergedEnv.TREESEED_TEAM_ID,
|
|
595
770
|
TREESEED_HOSTING_TEAM_ID: resolvedHostingTeamId ?? mergedEnv.TREESEED_HOSTING_TEAM_ID,
|
|
596
771
|
TREESEED_API_D1_DATABASE_NAME: mergedEnv.TREESEED_API_D1_DATABASE_NAME ?? "SITE_DATA_DB",
|
|
597
772
|
SITE_DATA_DB: mergedEnv.SITE_DATA_DB ?? "SITE_DATA_DB",
|
|
598
773
|
TREESEED_API_D1_LOCAL_PERSIST_TO: localD1PersistTo,
|
|
774
|
+
TREESEED_WEB_SERVICE_ID: mergedEnv.TREESEED_WEB_SERVICE_ID ?? mergedEnv.TREESEED_API_WEB_SERVICE_ID ?? "web",
|
|
775
|
+
TREESEED_WEB_SERVICE_SECRET: mergedEnv.TREESEED_WEB_SERVICE_SECRET ?? mergedEnv.TREESEED_API_WEB_SERVICE_SECRET ?? "treeseed-web-service-dev-secret",
|
|
776
|
+
TREESEED_API_WEB_SERVICE_ID: mergedEnv.TREESEED_API_WEB_SERVICE_ID ?? mergedEnv.TREESEED_WEB_SERVICE_ID ?? "web",
|
|
777
|
+
TREESEED_API_WEB_SERVICE_SECRET: mergedEnv.TREESEED_API_WEB_SERVICE_SECRET ?? mergedEnv.TREESEED_WEB_SERVICE_SECRET ?? "treeseed-web-service-dev-secret",
|
|
778
|
+
TREESEED_PLATFORM_RUNNER_SECRET: mergedEnv.TREESEED_PLATFORM_RUNNER_SECRET ?? "treeseed-platform-runner-dev-secret",
|
|
599
779
|
TREESEED_FORM_TOKEN_SECRET: mergedEnv.TREESEED_FORM_TOKEN_SECRET ?? "treeseed-local-form-token-secret",
|
|
600
780
|
TREESEED_BETTER_AUTH_SECRET: mergedEnv.TREESEED_BETTER_AUTH_SECRET ?? "treeseed-local-better-auth-secret-minimum-32-characters",
|
|
781
|
+
...devResetId ? { TREESEED_DEV_RESET_ID: devResetId } : {},
|
|
601
782
|
TREESEED_SMTP_HOST: TREESEED_DEFAULT_LOCAL_SMTP_HOST,
|
|
602
783
|
TREESEED_SMTP_PORT: String(TREESEED_DEFAULT_LOCAL_SMTP_PORT),
|
|
603
784
|
TREESEED_SMTP_USERNAME: "",
|
|
@@ -617,7 +798,7 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
617
798
|
sharedEnv.TREESEED_PUBLIC_DEV_WATCH_RELOAD = sharedEnv.TREESEED_PUBLIC_DEV_WATCH_RELOAD || "true";
|
|
618
799
|
}
|
|
619
800
|
const commands = [];
|
|
620
|
-
if (
|
|
801
|
+
if (effectiveCommandIds.includes("web")) {
|
|
621
802
|
commands.push({
|
|
622
803
|
id: "web",
|
|
623
804
|
label: usesCloudflareWebRuntime ? "Cloudflare Wrangler UI" : "Astro UI",
|
|
@@ -628,11 +809,19 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
628
809
|
localRuntime: webLocalRuntime
|
|
629
810
|
});
|
|
630
811
|
}
|
|
631
|
-
if (
|
|
812
|
+
if (!marketWorkspace && effectiveCommandIds.some((id) => id !== "web") && !agentPackageRoot) {
|
|
632
813
|
throw new Error("Unable to resolve @treeseed/agent for local API or agent service surfaces.");
|
|
633
814
|
}
|
|
634
|
-
for (const id of
|
|
815
|
+
for (const id of effectiveCommandIds) {
|
|
635
816
|
if (id === "web") continue;
|
|
817
|
+
if (marketWorkspace && id === "api") {
|
|
818
|
+
commands.push(createMarketApiCommand(tenantRoot, sharedEnv, apiHost, apiPort));
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
if (marketWorkspace && id === "market-runner") {
|
|
822
|
+
commands.push(createMarketOperationsRunnerCommand(tenantRoot, sharedEnv));
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
636
825
|
commands.push(createAgentCommand(id, tenantRoot, agentPackageRoot, sharedEnv, apiHost, apiPort));
|
|
637
826
|
}
|
|
638
827
|
const readyChecks = commands.map((command) => {
|
|
@@ -648,7 +837,7 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
648
837
|
return {
|
|
649
838
|
id: command.id,
|
|
650
839
|
label: command.label,
|
|
651
|
-
required:
|
|
840
|
+
required: command.id === "market-runner",
|
|
652
841
|
strategy: "process"
|
|
653
842
|
};
|
|
654
843
|
});
|
|
@@ -680,7 +869,8 @@ function createTreeseedIntegratedDevPlan(options = {}) {
|
|
|
680
869
|
...commands.some((command) => command.id === "api") ? { api: nodeLocalRuntime("Treeseed API") } : {},
|
|
681
870
|
...commands.some((command) => command.id === "manager") ? { manager: nodeLocalRuntime("Manager") } : {},
|
|
682
871
|
...commands.some((command) => command.id === "worker") ? { worker: nodeLocalRuntime("Worker Runner") } : {},
|
|
683
|
-
...commands.some((command) => command.id === "agents") ? { agents: nodeLocalRuntime("Agents Loop") } : {}
|
|
872
|
+
...commands.some((command) => command.id === "agents") ? { agents: nodeLocalRuntime("Agents Loop") } : {},
|
|
873
|
+
...commands.some((command) => command.id === "market-runner") ? { marketRunner: nodeLocalRuntime("Market Operations Runner") } : {}
|
|
684
874
|
},
|
|
685
875
|
restartPolicy: {
|
|
686
876
|
initialBackoffMs: INITIAL_RESTART_BACKOFF_MS,
|
|
@@ -742,6 +932,12 @@ function defaultInspectPortOwners(ports) {
|
|
|
742
932
|
function defaultRemovePath(path) {
|
|
743
933
|
rmSync(path, { recursive: true, force: true });
|
|
744
934
|
}
|
|
935
|
+
function defaultResetMarketPostgres() {
|
|
936
|
+
return resetMarketPostgres(process.env, { spawnSync });
|
|
937
|
+
}
|
|
938
|
+
function defaultStopMarketPostgres() {
|
|
939
|
+
return stopMarketPostgres(process.env, { spawnSync });
|
|
940
|
+
}
|
|
745
941
|
function createManagedDevProcess(command, child) {
|
|
746
942
|
let resolveExit = () => {
|
|
747
943
|
};
|
|
@@ -790,8 +986,7 @@ async function stopManagedProcess(managed, signal, killProcess, graceMs) {
|
|
|
790
986
|
}
|
|
791
987
|
}
|
|
792
988
|
}
|
|
793
|
-
function
|
|
794
|
-
const outputPath = resolve(projectRoot, DEV_RELOAD_FILE);
|
|
989
|
+
function writeDevReloadStampPath(outputPath) {
|
|
795
990
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
796
991
|
writeFileSync(
|
|
797
992
|
outputPath,
|
|
@@ -807,6 +1002,9 @@ function writeDevReloadStamp(projectRoot) {
|
|
|
807
1002
|
"utf8"
|
|
808
1003
|
);
|
|
809
1004
|
}
|
|
1005
|
+
function writeDevReloadStamp(projectRoot) {
|
|
1006
|
+
writeDevReloadStampPath(resolve(projectRoot, DEV_RELOAD_FILE));
|
|
1007
|
+
}
|
|
810
1008
|
function defaultWrite(line, stream) {
|
|
811
1009
|
const target = stream === "stderr" ? process.stderr : process.stdout;
|
|
812
1010
|
target.write(line);
|
|
@@ -1112,11 +1310,11 @@ function runTreeseedIntegratedDevReset(reset, options, deps) {
|
|
|
1112
1310
|
return action;
|
|
1113
1311
|
}
|
|
1114
1312
|
if (action.kind === "service") {
|
|
1115
|
-
const stopped = deps.stopMailpitContainers();
|
|
1313
|
+
const stopped = action.id === "market-postgres" ? deps.resetMarketPostgres() : deps.stopMailpitContainers();
|
|
1116
1314
|
const result = {
|
|
1117
1315
|
...action,
|
|
1118
1316
|
status: stopped ? "removed" : "failed",
|
|
1119
|
-
detail: stopped ? "Mailpit container state
|
|
1317
|
+
detail: stopped ? action.id === "market-postgres" ? "Market PostgreSQL database state was reset." : "Mailpit container and inbox state were reset." : action.id === "market-postgres" ? "Unable to stop or remove the Treeseed-managed Market PostgreSQL container and volume." : "Unable to remove the Treeseed-managed Mailpit container and inbox state."
|
|
1120
1318
|
};
|
|
1121
1319
|
emitEvent(options, deps.write, {
|
|
1122
1320
|
type: "reset",
|
|
@@ -1127,6 +1325,36 @@ function runTreeseedIntegratedDevReset(reset, options, deps) {
|
|
|
1127
1325
|
return result;
|
|
1128
1326
|
}
|
|
1129
1327
|
if (!action.path || !existsSync(action.path)) {
|
|
1328
|
+
if (action.id === "dev-reload" && action.path) {
|
|
1329
|
+
try {
|
|
1330
|
+
writeDevReloadStampPath(action.path);
|
|
1331
|
+
const result2 = {
|
|
1332
|
+
...action,
|
|
1333
|
+
status: "refreshed",
|
|
1334
|
+
detail: action.path
|
|
1335
|
+
};
|
|
1336
|
+
emitEvent(options, deps.write, {
|
|
1337
|
+
type: "reset",
|
|
1338
|
+
status: result2.status,
|
|
1339
|
+
message: `${result2.label}: refreshed`,
|
|
1340
|
+
detail: result2
|
|
1341
|
+
});
|
|
1342
|
+
return result2;
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
const result2 = {
|
|
1345
|
+
...action,
|
|
1346
|
+
status: "failed",
|
|
1347
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
1348
|
+
};
|
|
1349
|
+
emitEvent(options, deps.write, {
|
|
1350
|
+
type: "reset",
|
|
1351
|
+
status: result2.status,
|
|
1352
|
+
message: `${result2.label}: failed`,
|
|
1353
|
+
detail: result2
|
|
1354
|
+
}, "stderr");
|
|
1355
|
+
return result2;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1130
1358
|
const result = {
|
|
1131
1359
|
...action,
|
|
1132
1360
|
status: "skipped",
|
|
@@ -1140,6 +1368,36 @@ function runTreeseedIntegratedDevReset(reset, options, deps) {
|
|
|
1140
1368
|
});
|
|
1141
1369
|
return result;
|
|
1142
1370
|
}
|
|
1371
|
+
if (action.id === "dev-reload") {
|
|
1372
|
+
try {
|
|
1373
|
+
writeDevReloadStampPath(action.path);
|
|
1374
|
+
const result = {
|
|
1375
|
+
...action,
|
|
1376
|
+
status: "refreshed",
|
|
1377
|
+
detail: action.path
|
|
1378
|
+
};
|
|
1379
|
+
emitEvent(options, deps.write, {
|
|
1380
|
+
type: "reset",
|
|
1381
|
+
status: result.status,
|
|
1382
|
+
message: `${result.label}: refreshed`,
|
|
1383
|
+
detail: result
|
|
1384
|
+
});
|
|
1385
|
+
return result;
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
const result = {
|
|
1388
|
+
...action,
|
|
1389
|
+
status: "failed",
|
|
1390
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
1391
|
+
};
|
|
1392
|
+
emitEvent(options, deps.write, {
|
|
1393
|
+
type: "reset",
|
|
1394
|
+
status: result.status,
|
|
1395
|
+
message: `${result.label}: failed`,
|
|
1396
|
+
detail: result
|
|
1397
|
+
}, "stderr");
|
|
1398
|
+
return result;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1143
1401
|
try {
|
|
1144
1402
|
deps.removePath(action.path);
|
|
1145
1403
|
const result = {
|
|
@@ -1219,6 +1477,15 @@ function attachPrefixedLogReader(child, surface, options, write) {
|
|
|
1219
1477
|
stderr: { suppressWorkerdBrokenPipeBlock: false }
|
|
1220
1478
|
};
|
|
1221
1479
|
function shouldSuppressLogLine(line, name) {
|
|
1480
|
+
if (!options.json && surface === "market-runner" && name === "stdout") {
|
|
1481
|
+
try {
|
|
1482
|
+
const parsed = JSON.parse(line);
|
|
1483
|
+
if (parsed.ok === true && parsed.claimed === false && parsed.operation == null) {
|
|
1484
|
+
return true;
|
|
1485
|
+
}
|
|
1486
|
+
} catch {
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1222
1489
|
const state = filterState[name];
|
|
1223
1490
|
if (state.suppressWorkerdBrokenPipeBlock) {
|
|
1224
1491
|
const trimmed = line.trim();
|
|
@@ -1310,6 +1577,99 @@ function runSetupStep(step, plan, deps) {
|
|
|
1310
1577
|
detail: [timeoutDetail, result.stdout, result.stderr].filter(Boolean).join("\n").trim() || `Exited with ${result.status ?? 1}.`
|
|
1311
1578
|
};
|
|
1312
1579
|
}
|
|
1580
|
+
function marketPostgresConfig(env) {
|
|
1581
|
+
return {
|
|
1582
|
+
container: env.TREESEED_MARKET_LOCAL_POSTGRES_CONTAINER?.trim() || TREESEED_DEFAULT_MARKET_POSTGRES_CONTAINER,
|
|
1583
|
+
volume: env.TREESEED_MARKET_LOCAL_POSTGRES_VOLUME?.trim() || TREESEED_DEFAULT_MARKET_POSTGRES_VOLUME,
|
|
1584
|
+
port: env.TREESEED_MARKET_LOCAL_POSTGRES_PORT?.trim() || String(TREESEED_DEFAULT_MARKET_POSTGRES_PORT),
|
|
1585
|
+
user: "treeseed",
|
|
1586
|
+
password: "treeseed",
|
|
1587
|
+
database: "market_local"
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
function dockerBinary(env) {
|
|
1591
|
+
return resolveTreeseedToolBinary("docker", { env }) ?? "docker";
|
|
1592
|
+
}
|
|
1593
|
+
function spawnDocker(args, env, deps, timeout = 3e4) {
|
|
1594
|
+
return deps.spawnSync(dockerBinary(env), args, {
|
|
1595
|
+
cwd: process.cwd(),
|
|
1596
|
+
env,
|
|
1597
|
+
encoding: "utf8",
|
|
1598
|
+
timeout
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
function dockerResultText(result) {
|
|
1602
|
+
return [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
1603
|
+
}
|
|
1604
|
+
function dockerVolumeIsMissing(result) {
|
|
1605
|
+
if (result.error) return false;
|
|
1606
|
+
const text = dockerResultText(result).toLowerCase();
|
|
1607
|
+
return text.includes("no such volume") || text.includes("not found");
|
|
1608
|
+
}
|
|
1609
|
+
function ensureMarketPostgres(env, deps) {
|
|
1610
|
+
const config = marketPostgresConfig(env);
|
|
1611
|
+
const inspect = spawnDocker(["inspect", config.container], env, deps);
|
|
1612
|
+
if ((inspect.status ?? 1) !== 0) {
|
|
1613
|
+
const run = spawnDocker([
|
|
1614
|
+
"run",
|
|
1615
|
+
"-d",
|
|
1616
|
+
"--name",
|
|
1617
|
+
config.container,
|
|
1618
|
+
"-e",
|
|
1619
|
+
`POSTGRES_USER=${config.user}`,
|
|
1620
|
+
"-e",
|
|
1621
|
+
`POSTGRES_PASSWORD=${config.password}`,
|
|
1622
|
+
"-e",
|
|
1623
|
+
`POSTGRES_DB=${config.database}`,
|
|
1624
|
+
"-p",
|
|
1625
|
+
`127.0.0.1:${config.port}:5432`,
|
|
1626
|
+
"-v",
|
|
1627
|
+
`${config.volume}:/var/lib/postgresql/data`,
|
|
1628
|
+
"postgres:16"
|
|
1629
|
+
], env, deps, 6e4);
|
|
1630
|
+
if ((run.status ?? 1) !== 0) {
|
|
1631
|
+
throw new Error(dockerResultText(run) || `Unable to start ${config.container}.`);
|
|
1632
|
+
}
|
|
1633
|
+
} else {
|
|
1634
|
+
const start = spawnDocker(["start", config.container], env, deps);
|
|
1635
|
+
if ((start.status ?? 1) !== 0) {
|
|
1636
|
+
throw new Error(dockerResultText(start) || `Unable to start existing ${config.container}.`);
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
const startedAt = Date.now();
|
|
1640
|
+
let last = "";
|
|
1641
|
+
while (Date.now() - startedAt < 45e3) {
|
|
1642
|
+
const ready = spawnDocker(["exec", config.container, "pg_isready", "-U", config.user, "-d", config.database], env, deps, 5e3);
|
|
1643
|
+
last = dockerResultText(ready);
|
|
1644
|
+
if ((ready.status ?? 1) === 0) {
|
|
1645
|
+
const query = spawnDocker(["exec", config.container, "psql", "-U", config.user, "-d", config.database, "-c", "SELECT 1"], env, deps, 5e3);
|
|
1646
|
+
last = dockerResultText(query) || last;
|
|
1647
|
+
if ((query.status ?? 1) === 0) {
|
|
1648
|
+
return `Market PostgreSQL is ready at 127.0.0.1:${config.port} (${config.container}).`;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 500);
|
|
1652
|
+
}
|
|
1653
|
+
throw new Error(last || `Timed out waiting for ${config.container} to accept connections.`);
|
|
1654
|
+
}
|
|
1655
|
+
function resetMarketPostgres(env, deps) {
|
|
1656
|
+
const config = marketPostgresConfig(env);
|
|
1657
|
+
spawnDocker(["rm", "-f", config.container], env, deps, 3e4);
|
|
1658
|
+
const existingVolume = spawnDocker(["volume", "inspect", config.volume], env, deps, 3e4);
|
|
1659
|
+
if ((existingVolume.status ?? 1) !== 0) {
|
|
1660
|
+
return dockerVolumeIsMissing(existingVolume);
|
|
1661
|
+
}
|
|
1662
|
+
const volume = spawnDocker(["volume", "rm", config.volume], env, deps, 3e4);
|
|
1663
|
+
return (volume.status ?? 1) === 0 || dockerVolumeIsMissing(volume);
|
|
1664
|
+
}
|
|
1665
|
+
function stopMarketPostgres(env, deps) {
|
|
1666
|
+
if (env.TREESEED_MARKET_LOCAL_POSTGRES_MANAGED !== "true") {
|
|
1667
|
+
return true;
|
|
1668
|
+
}
|
|
1669
|
+
const config = marketPostgresConfig(env);
|
|
1670
|
+
const result = spawnDocker(["rm", "-f", config.container], env, deps, 3e4);
|
|
1671
|
+
return (result.status ?? 1) === 0;
|
|
1672
|
+
}
|
|
1313
1673
|
function runLocalSetup(plan, options, deps) {
|
|
1314
1674
|
const results = [];
|
|
1315
1675
|
if (plan.setupMode === "off") {
|
|
@@ -1355,6 +1715,23 @@ function runLocalSetup(plan, options, deps) {
|
|
|
1355
1715
|
status: step.required ? "failed" : "degraded",
|
|
1356
1716
|
detail: "Wrangler was not found. Run `npx trsd install --json` and retry `npx trsd dev`."
|
|
1357
1717
|
};
|
|
1718
|
+
} else if (step.id === "market-postgres") {
|
|
1719
|
+
if (plan.setupMode === "check") {
|
|
1720
|
+
result = { ...step, status: "skipped", detail: "Local Market PostgreSQL startup was checked in non-mutating mode." };
|
|
1721
|
+
} else if (step.status === "failed") {
|
|
1722
|
+
result = step;
|
|
1723
|
+
} else {
|
|
1724
|
+
try {
|
|
1725
|
+
const detail = ensureMarketPostgres({ ...process.env, ...plan.commands[0]?.env }, deps);
|
|
1726
|
+
result = { ...step, status: "completed", detail };
|
|
1727
|
+
} catch (error) {
|
|
1728
|
+
result = {
|
|
1729
|
+
...step,
|
|
1730
|
+
status: "failed",
|
|
1731
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1358
1735
|
} else if (step.id === "wrangler-config") {
|
|
1359
1736
|
if (plan.setupMode === "check") {
|
|
1360
1737
|
result = { ...step, status: "skipped", detail: "Local Wrangler config generation was checked in non-mutating mode." };
|
|
@@ -1452,6 +1829,8 @@ async function runTreeseedIntegratedDev(options = {}, deps = {}) {
|
|
|
1452
1829
|
const prepareEnvironment = deps.prepareEnvironment ?? defaultPrepareEnvironment;
|
|
1453
1830
|
const removePath = deps.removePath ?? defaultRemovePath;
|
|
1454
1831
|
const stopMailpit = deps.stopMailpitContainers ?? stopKnownMailpitContainers;
|
|
1832
|
+
const resetMarketPostgresContainer = deps.resetMarketPostgres ?? defaultResetMarketPostgres;
|
|
1833
|
+
const stopMarketPostgresContainer = deps.stopMarketPostgres ?? defaultStopMarketPostgres;
|
|
1455
1834
|
const inspectPortOwners = deps.inspectPortOwners ?? defaultInspectPortOwners;
|
|
1456
1835
|
prepareEnvironment(tenantRoot);
|
|
1457
1836
|
const plan = createTreeseedIntegratedDevPlan({
|
|
@@ -1479,7 +1858,8 @@ async function runTreeseedIntegratedDev(options = {}, deps = {}) {
|
|
|
1479
1858
|
const resetResults = runTreeseedIntegratedDevReset(plan.reset, options, {
|
|
1480
1859
|
write,
|
|
1481
1860
|
removePath,
|
|
1482
|
-
stopMailpitContainers: stopMailpit
|
|
1861
|
+
stopMailpitContainers: stopMailpit,
|
|
1862
|
+
resetMarketPostgres: deps.resetMarketPostgres ? resetMarketPostgresContainer : () => resetMarketPostgres(plan.commands[0]?.env ?? process.env, { spawnSync: spawnSyncProcess })
|
|
1483
1863
|
});
|
|
1484
1864
|
const failedReset = resetResults?.actions.find((action) => action.status === "failed");
|
|
1485
1865
|
if (failedReset) {
|
|
@@ -1539,6 +1919,18 @@ async function runTreeseedIntegratedDev(options = {}, deps = {}) {
|
|
|
1539
1919
|
await Promise.all(
|
|
1540
1920
|
[...children.values()].map((managed) => stopManagedProcess(managed, "SIGTERM", killProcess, shutdownGraceMs))
|
|
1541
1921
|
);
|
|
1922
|
+
const marketEnv = plan.commands[0]?.env ?? process.env;
|
|
1923
|
+
const shouldStopMarketPostgres = marketEnv.TREESEED_MARKET_LOCAL_POSTGRES_MANAGED === "true";
|
|
1924
|
+
if (shouldStopMarketPostgres) {
|
|
1925
|
+
const stopped = deps.stopMarketPostgres ? stopMarketPostgresContainer() : stopMarketPostgres(marketEnv, { spawnSync: spawnSyncProcess });
|
|
1926
|
+
if (!stopped) {
|
|
1927
|
+
emitEvent(options, write, {
|
|
1928
|
+
type: "shutdown",
|
|
1929
|
+
status: "degraded",
|
|
1930
|
+
message: "Unable to stop the managed local Market PostgreSQL container."
|
|
1931
|
+
}, "stderr");
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1542
1934
|
children.clear();
|
|
1543
1935
|
for (const dispose of disposers) {
|
|
1544
1936
|
dispose();
|
|
@@ -1749,6 +2141,9 @@ async function runTreeseedIntegratedDev(options = {}, deps = {}) {
|
|
|
1749
2141
|
restartIds.add(id);
|
|
1750
2142
|
}
|
|
1751
2143
|
}
|
|
2144
|
+
if ((change.tenantApiChanged || change.sdkChanged) && commandsById.has("market-runner")) {
|
|
2145
|
+
restartIds.add("market-runner");
|
|
2146
|
+
}
|
|
1752
2147
|
for (const id of restartIds) {
|
|
1753
2148
|
await restartCommand(id);
|
|
1754
2149
|
}
|
|
@@ -1812,7 +2207,7 @@ async function runTreeseedIntegratedDev(options = {}, deps = {}) {
|
|
|
1812
2207
|
surface: check.id,
|
|
1813
2208
|
status: ready ? "ready" : "degraded",
|
|
1814
2209
|
url: check.url,
|
|
1815
|
-
message: `${check.label} is ${ready ? "ready" : "degraded"}.`
|
|
2210
|
+
message: `${check.label} is ${ready ? "ready" : "degraded"}${check.url ? ` at ${check.url}` : ""}.`
|
|
1816
2211
|
});
|
|
1817
2212
|
}
|
|
1818
2213
|
readinessInProgress = false;
|
|
@@ -1865,6 +2260,10 @@ export {
|
|
|
1865
2260
|
TREESEED_DEFAULT_LOCAL_SMTP_HOST,
|
|
1866
2261
|
TREESEED_DEFAULT_LOCAL_SMTP_PORT,
|
|
1867
2262
|
TREESEED_DEFAULT_MAILPIT_UI_PORT,
|
|
2263
|
+
TREESEED_DEFAULT_MARKET_POSTGRES_CONTAINER,
|
|
2264
|
+
TREESEED_DEFAULT_MARKET_POSTGRES_PORT,
|
|
2265
|
+
TREESEED_DEFAULT_MARKET_POSTGRES_URL,
|
|
2266
|
+
TREESEED_DEFAULT_MARKET_POSTGRES_VOLUME,
|
|
1868
2267
|
TREESEED_DEFAULT_WEB_HOST,
|
|
1869
2268
|
TREESEED_DEFAULT_WEB_PORT,
|
|
1870
2269
|
createTreeseedIntegratedDevPlan,
|
|
@@ -19,7 +19,7 @@ const { entry, currentPath } = Astro.props;
|
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="grid gap-6 md:grid-cols-[1.25fr_0.75fr]">
|
|
22
|
-
<div class="prose
|
|
22
|
+
<div class="prose">
|
|
23
23
|
<slot />
|
|
24
24
|
</div>
|
|
25
25
|
<div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-5">
|
|
@@ -17,7 +17,7 @@ const { entry, currentPath } = Astro.props;
|
|
|
17
17
|
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-7xl">{entry.title}</h1>
|
|
18
18
|
<p class="max-w-4xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{entry.summary}</p>
|
|
19
19
|
</section>
|
|
20
|
-
<article class="prose
|
|
20
|
+
<article class="prose max-w-4xl">
|
|
21
21
|
<slot />
|
|
22
22
|
</article>
|
|
23
23
|
</div>
|
|
@@ -92,7 +92,7 @@ const download = activeBook
|
|
|
92
92
|
<p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{document.entry.data.summary}</p>
|
|
93
93
|
)}
|
|
94
94
|
</header>
|
|
95
|
-
<div class="prose
|
|
95
|
+
<div class="prose max-w-none">
|
|
96
96
|
<PublishedContentBody html={document.html} />
|
|
97
97
|
</div>
|
|
98
98
|
</article>
|
|
@@ -79,7 +79,7 @@ const ungroupedEntries = (docsTree ?? []).filter((entry) =>
|
|
|
79
79
|
<p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{document.entry.data.summary}</p>
|
|
80
80
|
)}
|
|
81
81
|
</header>
|
|
82
|
-
<div class="prose
|
|
82
|
+
<div class="prose max-w-none">
|
|
83
83
|
<PublishedContentBody html={document.html} />
|
|
84
84
|
</div>
|
|
85
85
|
</article>
|
|
@@ -3,6 +3,7 @@ import '../../styles/global.css';
|
|
|
3
3
|
import '../../styles/theme.css';
|
|
4
4
|
import '../../styles/ui.css';
|
|
5
5
|
import '../../styles/forms.css';
|
|
6
|
+
import { ClientRouter } from 'astro:transitions';
|
|
6
7
|
import ThemeScript from '../../components/ui/theme/ThemeScript.astro';
|
|
7
8
|
import ThemeSelector from '../../components/ui/theme/ThemeSelector.astro';
|
|
8
9
|
import Button from '../../components/ui/forms/Button.astro';
|
|
@@ -85,6 +86,7 @@ const tableRows = [
|
|
|
85
86
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
86
87
|
<title>TreeSeed UI Catalog</title>
|
|
87
88
|
<ThemeScript defaultScheme={selected.scheme} defaultMode={selected.mode} />
|
|
89
|
+
<ClientRouter />
|
|
88
90
|
</head>
|
|
89
91
|
<body>
|
|
90
92
|
<main class="ts-ui-catalog">
|
package/dist/scripts/paths.js
CHANGED
|
@@ -5,7 +5,8 @@ const packageCandidate = resolve(fileURLToPath(new URL('..', import.meta.url)));
|
|
|
5
5
|
export const packageRoot = packageCandidate.endsWith('/dist')
|
|
6
6
|
? resolve(packageCandidate, '..')
|
|
7
7
|
: packageCandidate;
|
|
8
|
+
export const workspaceRoot = resolve(packageRoot, '..', '..');
|
|
8
9
|
export const fixtureRoot = requireSharedFixtureRoot();
|
|
9
10
|
export const fixtureWranglerConfig = resolve(fixtureRoot, 'wrangler.toml');
|
|
10
|
-
export const
|
|
11
|
+
export const sdkD1MigrationsRoot = resolve(workspaceRoot, 'packages', 'sdk', 'drizzle', 'd1');
|
|
11
12
|
export const fixtureSrcRoot = resolve(fixtureRoot, 'src');
|
package/dist/styles/forms.css
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
.ts-control {
|
|
45
45
|
appearance: none;
|
|
46
|
-
background: var(--ts-color-surface);
|
|
46
|
+
background-color: var(--ts-color-surface);
|
|
47
47
|
border: 1px solid var(--ts-color-border);
|
|
48
48
|
border-radius: var(--ts-radius-md);
|
|
49
49
|
color: var(--ts-color-text);
|
|
@@ -71,22 +71,28 @@
|
|
|
71
71
|
|
|
72
72
|
.ts-control:disabled,
|
|
73
73
|
.ts-control:read-only {
|
|
74
|
-
background: var(--ts-color-surface-muted);
|
|
74
|
+
background-color: var(--ts-color-surface-muted);
|
|
75
75
|
color: var(--ts-color-text-muted);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
.ts-control--select
|
|
78
|
+
.ts-control--select,
|
|
79
|
+
select.ts-control {
|
|
80
|
+
appearance: none;
|
|
81
|
+
background-color: var(--ts-color-surface);
|
|
79
82
|
background-image:
|
|
83
|
+
linear-gradient(var(--ts-color-border), var(--ts-color-border)),
|
|
80
84
|
linear-gradient(45deg, transparent 50%, currentColor 50%),
|
|
81
85
|
linear-gradient(135deg, currentColor 50%, transparent 50%);
|
|
82
86
|
background-position:
|
|
83
|
-
calc(100% -
|
|
84
|
-
calc(100% -
|
|
85
|
-
|
|
86
|
-
0.32rem 0.32rem,
|
|
87
|
-
0.32rem 0.32rem;
|
|
87
|
+
calc(100% - 2rem) 50%,
|
|
88
|
+
calc(100% - 1.17rem) calc(50% - 0.08rem),
|
|
89
|
+
calc(100% - 0.86rem) calc(50% - 0.08rem);
|
|
88
90
|
background-repeat: no-repeat;
|
|
89
|
-
|
|
91
|
+
background-size:
|
|
92
|
+
1px 1.2rem,
|
|
93
|
+
0.42rem 0.42rem,
|
|
94
|
+
0.42rem 0.42rem;
|
|
95
|
+
padding-right: 2.5rem;
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
.ts-control--textarea {
|
package/dist/styles/prose.css
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
.prose
|
|
1
|
+
.prose {
|
|
2
2
|
color: var(--ts-color-text);
|
|
3
3
|
font-size: 1.08rem;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
.prose
|
|
7
|
-
.prose
|
|
8
|
-
.prose
|
|
6
|
+
.prose h1,
|
|
7
|
+
.prose h2,
|
|
8
|
+
.prose h3 {
|
|
9
9
|
color: var(--ts-color-text);
|
|
10
10
|
line-height: 1.12;
|
|
11
11
|
font-weight: 700;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
.prose
|
|
14
|
+
.prose h1 {
|
|
15
15
|
font-size: clamp(2.4rem, 5vw, 4.1rem);
|
|
16
16
|
margin-bottom: 1.2rem;
|
|
17
17
|
font-family: var(--font-serif);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
.prose
|
|
20
|
+
.prose h2 {
|
|
21
21
|
font-size: clamp(1.85rem, 2.8vw, 2.5rem);
|
|
22
22
|
margin-top: 3.1rem;
|
|
23
23
|
margin-bottom: 1rem;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
.prose
|
|
26
|
+
.prose h3 {
|
|
27
27
|
font-size: 1.32rem;
|
|
28
28
|
margin-top: 2rem;
|
|
29
29
|
margin-bottom: 0.7rem;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
.prose
|
|
33
|
-
.prose
|
|
32
|
+
.prose p,
|
|
33
|
+
.prose li {
|
|
34
34
|
color: var(--ts-color-text-muted);
|
|
35
35
|
line-height: 1.85;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
.prose
|
|
38
|
+
.prose p {
|
|
39
39
|
margin: 1rem 0 1.2rem;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
.prose
|
|
42
|
+
.prose p + p {
|
|
43
43
|
margin-top: 1.35rem;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
.prose
|
|
46
|
+
.prose a {
|
|
47
47
|
color: var(--ts-color-accent-strong);
|
|
48
48
|
text-decoration: underline;
|
|
49
49
|
text-underline-offset: 0.16em;
|
|
50
50
|
font-weight: 600;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
.prose
|
|
53
|
+
.prose strong {
|
|
54
54
|
color: var(--ts-color-text);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
.prose
|
|
58
|
-
.prose
|
|
57
|
+
.prose ul,
|
|
58
|
+
.prose ol {
|
|
59
59
|
padding-left: 1.3rem;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
.prose
|
|
62
|
+
.prose blockquote {
|
|
63
63
|
border-left: 4px solid var(--ts-color-accent);
|
|
64
64
|
padding-left: 1rem;
|
|
65
65
|
color: var(--ts-color-text-muted);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
.prose
|
|
68
|
+
.prose code {
|
|
69
69
|
background: var(--ts-color-info-soft);
|
|
70
70
|
border: 1px solid var(--ts-color-info-border);
|
|
71
71
|
border-radius: 0.5rem;
|
|
72
72
|
padding: 0.1rem 0.35rem;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
.prose
|
|
75
|
+
.prose hr {
|
|
76
76
|
border-color: var(--ts-color-border);
|
|
77
77
|
margin: 2.4rem 0;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
.prose
|
|
80
|
+
.prose :where(table) {
|
|
81
81
|
width: 100%;
|
|
82
82
|
border-collapse: collapse;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
.prose
|
|
85
|
+
.prose :where(th, td) {
|
|
86
86
|
border-bottom: 1px solid var(--ts-color-border);
|
|
87
87
|
padding: 0.85rem 0.75rem;
|
|
88
88
|
text-align: left;
|
package/dist/styles/theme.css
CHANGED
|
@@ -119,16 +119,30 @@ body {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
.ts-theme-selector__field select {
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
appearance: none;
|
|
123
|
+
background-color: var(--ts-color-surface);
|
|
124
|
+
background-image:
|
|
125
|
+
linear-gradient(var(--ts-color-border), var(--ts-color-border)),
|
|
126
|
+
linear-gradient(45deg, transparent 50%, currentColor 50%),
|
|
127
|
+
linear-gradient(135deg, currentColor 50%, transparent 50%);
|
|
128
|
+
background-position:
|
|
129
|
+
calc(100% - 1.7rem) 50%,
|
|
130
|
+
calc(100% - 1rem) calc(50% - 0.08rem),
|
|
131
|
+
calc(100% - 0.72rem) calc(50% - 0.08rem);
|
|
132
|
+
background-repeat: no-repeat;
|
|
133
|
+
background-size:
|
|
134
|
+
1px 1.05rem,
|
|
135
|
+
0.36rem 0.36rem,
|
|
136
|
+
0.36rem 0.36rem;
|
|
124
137
|
border: 1px solid var(--ts-color-border-strong);
|
|
125
138
|
border-radius: var(--ts-radius-sm);
|
|
126
|
-
background: var(--ts-color-surface);
|
|
127
139
|
color: var(--ts-color-text);
|
|
128
140
|
font: inherit;
|
|
129
141
|
font-size: 0.86rem;
|
|
130
142
|
font-weight: 700;
|
|
131
|
-
|
|
143
|
+
min-height: 2.25rem;
|
|
144
|
+
padding: 0.42rem 2.15rem 0.42rem 0.62rem;
|
|
145
|
+
width: 100%;
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
.ts-theme-selector__field select:focus-visible {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/core",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.7",
|
|
4
4
|
"description": "Treeseed web framework package for Astro/Starlight site runtimes.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@astrojs/sitemap": "3.7.0",
|
|
71
71
|
"@astrojs/starlight": "0.37.6",
|
|
72
72
|
"@tailwindcss/vite": "^4.1.4",
|
|
73
|
-
"@treeseed/sdk": "github:treeseed-ai/sdk#0.10.
|
|
73
|
+
"@treeseed/sdk": "github:treeseed-ai/sdk#0.10.13",
|
|
74
74
|
"astro": "^5.6.1",
|
|
75
75
|
"esbuild": "^0.28.0",
|
|
76
76
|
"katex": "^0.16.22",
|