@flowdular/sandbox 0.2.8 → 0.2.9

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.
@@ -66,6 +66,40 @@ import { createServer } from "vite";
66
66
 
67
67
  // ../dev-console/src/index.mjs
68
68
  import { createLogger } from "vite";
69
+
70
+ // ../dev-console/src/brand.mjs
71
+ var MARK = [
72
+ " XXX XXX",
73
+ " XXX XXX",
74
+ " XXXXXXXXXXXXXXXXX",
75
+ "XXXXXXXXXXXXXXXXXXX",
76
+ " XXX XXX",
77
+ "XXXXXXXXXXXXXXXXXXX",
78
+ " XXXXXXXXXXXXXXXXX",
79
+ " XXX XXX",
80
+ " XXX XXX"
81
+ ];
82
+ function renderBrandHeader({
83
+ title = "FLOWDULAR",
84
+ subtitle = "",
85
+ color = false,
86
+ columns = process.stdout.columns ?? 80,
87
+ terminal = Boolean(process.stdout.isTTY)
88
+ } = {}) {
89
+ const brand = (text) => color ? `\x1B[1;38;5;42m${text}\x1B[0m` : text;
90
+ const muted = (text) => color ? `\x1B[90m${text}\x1B[0m` : text;
91
+ if (!terminal) {
92
+ return ` ${brand(title)}${subtitle ? ` ${muted(subtitle)}` : ""}`;
93
+ }
94
+ const heading = [
95
+ ` ${brand(title)}`,
96
+ ...subtitle ? [` ${muted(subtitle)}`] : []
97
+ ];
98
+ if (columns < 21) return heading.join("\n");
99
+ return [...MARK.map((row) => ` ${brand(row)}`), "", ...heading].join("\n");
100
+ }
101
+
102
+ // ../dev-console/src/index.mjs
69
103
  var ansiPattern = /\u001B\[[0-?]*[ -/]*[@-~]/g;
70
104
  var ansi = {
71
105
  reset: "\x1B[0m",
@@ -116,7 +150,7 @@ function statusLine(theme, label, value, tone = "text") {
116
150
  }
117
151
  function printReady({ title, subtitle, lines, theme }) {
118
152
  console.log("");
119
- console.log(` ${theme.brand(title)} ${theme.muted(subtitle)}`);
153
+ console.log(renderBrandHeader({ title, subtitle, color: theme.enabled }));
120
154
  for (const [label, value, tone = "text"] of lines) {
121
155
  if (value === null || value === void 0) continue;
122
156
  console.log(statusLine(theme, label, value, tone));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowdular/sandbox",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "The Flowdular sandbox: chat a change, build it behind the gates, preview it in the real application, deliver it as code.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/flowdular/flowdular/tree/main/packages/sandbox#readme",
@@ -55,9 +55,9 @@
55
55
  "@octanejs/seo": "0.0.38",
56
56
  "@octanejs/vite-plugin": "0.1.51",
57
57
  "octane": "0.1.51",
58
- "segment-state": "0.2.0",
58
+ "segment-state": "0.2.1",
59
59
  "vite": "8.2.2",
60
- "@flowdular/sdk": "0.2.3"
60
+ "@flowdular/sdk": "0.2.4"
61
61
  },
62
62
  "imports": {
63
63
  "#coding-agent": "./internal/coding-agent/src/index.ts"
@@ -4,6 +4,7 @@ import { access, cp, readFile, readdir, writeFile } from 'node:fs/promises';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { createRequire } from 'node:module';
6
6
  import type { SessionModule } from './sessions.ts';
7
+ import { parseDocument } from 'yaml';
7
8
 
8
9
  export interface InstallResult {
9
10
  readonly ran: boolean;
@@ -36,10 +37,6 @@ async function packageName(directory: string): Promise<string | null> {
36
37
  }
37
38
  }
38
39
 
39
- function yamlString(value: string): string {
40
- return `'${value.replace(/'/g, "''")}'`;
41
- }
42
-
43
40
  /* A session workspace is a pnpm workspace of its own: the draft modules are its
44
41
  projects, every other workspace package is linked to the live checkout, and
45
42
  the host lockfile seeds the resolution so the session installs exactly the
@@ -57,7 +54,7 @@ export async function materializeSessionWorkspace(options: {
57
54
  );
58
55
  if (name) draft.add(name);
59
56
  }
60
- const overrides: string[] = [];
57
+ const overrides: Record<string, string> = {};
61
58
  for (const group of ['packages', 'modules']) {
62
59
  let entries: readonly string[] = [];
63
60
  try {
@@ -69,9 +66,7 @@ export async function materializeSessionWorkspace(options: {
69
66
  const directory = join(options.workspaceRoot, group, entry);
70
67
  const name = await packageName(directory);
71
68
  if (!name || draft.has(name)) continue;
72
- overrides.push(
73
- ` ${yamlString(name)}: ${yamlString(`link:${directory}`)}`,
74
- );
69
+ overrides[name] = `link:${directory}`;
75
70
  }
76
71
  }
77
72
 
@@ -89,7 +84,7 @@ export async function materializeSessionWorkspace(options: {
89
84
  if (typeof sdk.version !== 'string')
90
85
  throw new Error('Invalid installed SDK version.');
91
86
  sdkVersion = sdk.version;
92
- overrides.push(` '@flowdular/sdk': ${yamlString(`link:${sdkRoot}`)}`);
87
+ overrides['@flowdular/sdk'] = `link:${sdkRoot}`;
93
88
  } catch (error) {
94
89
  if (
95
90
  !['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(
@@ -132,29 +127,23 @@ export async function materializeSessionWorkspace(options: {
132
127
  join(options.workspaceRoot, 'pnpm-workspace.yaml'),
133
128
  'utf8',
134
129
  ).catch(() => '');
135
- const carried = hostWorkspace
136
- .split('\n')
137
- .filter(
138
- (line) =>
139
- !/^(packages|overrides):/.test(line) &&
140
- !/^\s+-\s+(platform|modules\/\*|packages\/\*)\s*$/.test(line),
141
- )
142
- .join('\n')
143
- .trim();
130
+ // Edit YAML structurally so lists, custom package globs and host overrides
131
+ // cannot spill into an unrelated setting when a top-level key is replaced.
132
+ const workspaceDocument = parseDocument(hostWorkspace);
133
+ if (workspaceDocument.errors.length > 0) throw workspaceDocument.errors[0];
134
+ workspaceDocument.set('packages', ['modules/*']);
135
+ workspaceDocument.set('allowUnusedPatches', true);
136
+ for (const name of draft) {
137
+ if (workspaceDocument.hasIn(['overrides', name])) {
138
+ workspaceDocument.deleteIn(['overrides', name]);
139
+ }
140
+ }
141
+ for (const [name, target] of Object.entries(overrides)) {
142
+ workspaceDocument.setIn(['overrides', name], target);
143
+ }
144
144
  await writeFile(
145
145
  join(options.sessionWorkspace, 'pnpm-workspace.yaml'),
146
- `${[
147
- 'packages:',
148
- ' - modules/*',
149
- /* Host patches travel along even when no draft depends on the patched
150
- package; pnpm must not treat that as an error. */
151
- 'allowUnusedPatches: true',
152
- carried,
153
- 'overrides:',
154
- ...overrides,
155
- ]
156
- .filter(Boolean)
157
- .join('\n')}\n`,
146
+ workspaceDocument.toString(),
158
147
  'utf8',
159
148
  );
160
149
  for (const shared of ['pnpm-lock.yaml', 'patches']) {