@venturewild/workspace 0.1.14 → 0.2.0

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.
Files changed (37) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +112 -112
  3. package/package.json +83 -76
  4. package/server/bin/wild-workspace.mjs +825 -763
  5. package/server/src/agent.mjs +453 -386
  6. package/server/src/bazaar/core.mjs +579 -0
  7. package/server/src/bazaar/index.mjs +75 -0
  8. package/server/src/bazaar/mcp-server.mjs +328 -0
  9. package/server/src/bazaar/mock-tickup.mjs +97 -0
  10. package/server/src/bazaar/preview-server.mjs +95 -0
  11. package/server/src/bazaar/seed-recipes/customer-feedback-form/know-how.md +23 -0
  12. package/server/src/bazaar/seed-recipes/customer-feedback-form/recipe.json +24 -0
  13. package/server/src/bazaar/seed-recipes/landing-page-launch/know-how.md +29 -0
  14. package/server/src/bazaar/seed-recipes/landing-page-launch/recipe.json +25 -0
  15. package/server/src/bazaar/seed-recipes/personal-portfolio/know-how.md +21 -0
  16. package/server/src/bazaar/seed-recipes/personal-portfolio/recipe.json +24 -0
  17. package/server/src/bazaar/seed-recipes/receipt-sorter/know-how.md +31 -0
  18. package/server/src/bazaar/seed-recipes/receipt-sorter/recipe.json +25 -0
  19. package/server/src/bazaar/seed-recipes/tickup-hr-matching/know-how.md +79 -0
  20. package/server/src/bazaar/seed-recipes/tickup-hr-matching/recipe.json +32 -0
  21. package/server/src/canvas/core.mjs +324 -0
  22. package/server/src/canvas/index.mjs +42 -0
  23. package/server/src/canvas/mcp-server.mjs +253 -0
  24. package/server/src/config.mjs +365 -365
  25. package/server/src/daemon-supervisor.mjs +216 -216
  26. package/server/src/inbox.mjs +86 -86
  27. package/server/src/index.mjs +1948 -1721
  28. package/server/src/logpaths.mjs +98 -98
  29. package/server/src/service.mjs +419 -419
  30. package/server/src/share.mjs +182 -148
  31. package/server/src/sync.mjs +248 -248
  32. package/server/src/turn-mcp.mjs +46 -0
  33. package/web/dist/assets/index-DVWgeTl_.js +91 -0
  34. package/web/dist/assets/index-Dl0VT5e6.css +1 -0
  35. package/web/dist/index.html +2 -2
  36. package/web/dist/assets/index-Bj-mdLGj.css +0 -1
  37. package/web/dist/assets/index-Dc6jo84c.js +0 -89
@@ -1,98 +1,98 @@
1
- // logpaths — one registry for the machine-global logs so `doctor`, `logs`, and
2
- // the operator channel all read the same set, and a tiny append/rotate/tail
3
- // helper for the new logs we write ourselves (cli, operator).
4
- //
5
- // WHY a registry and not just scattered paths: a brand-new user's install is the
6
- // riskiest moment (no Claude yet, wrong Node, port busy, daemon won't resolve),
7
- // and "I can't see what happened on their machine" is the #1 un-debuggable
8
- // failure. Centralising the log locations is what lets `wild-workspace doctor`
9
- // gather them and the operator channel tail them by name — never by arbitrary
10
- // path (the tail allowlist is TAILABLE below).
11
- //
12
- // NOTE: the supervisor + daemon-supervisor keep writing their logs at the
13
- // global-dir root (supervisor.log / server.out.log / daemon.log) — those paths
14
- // are reboot-proven and pinned by tests via an injected globalDir, so we mirror
15
- // them here for READING rather than moving them. Everything lives under
16
- // ~/.wild-workspace (NEVER the synced workspace — CLAUDE.md principle #1).
17
-
18
- import os from 'node:os';
19
- import path from 'node:path';
20
- import fs from 'node:fs';
21
-
22
- // THE machine-global dir. Mirrors service.mjs globalDir() + the supervisor
23
- // defaults. Overridable via env for tests / unusual homes.
24
- export function globalDir(env = process.env) {
25
- return env.WILD_WORKSPACE_GLOBAL_DIR || path.join(os.homedir(), '.wild-workspace');
26
- }
27
-
28
- // Logical name → filename. The first three are written by existing components;
29
- // cli + operator are new. Doctor bundles go under diagnosticsDir() (below).
30
- export const LOG_FILES = Object.freeze({
31
- supervisor: 'supervisor.log', // WorkspaceSupervisor watchdog
32
- server: 'server.out.log', // the :5173 server's stdout/stderr (launcher-redirected)
33
- daemon: 'daemon.log', // the bmo-sync daemon
34
- cli: 'cli.log', // every `wild-workspace …` invocation (first-run capture)
35
- operator: 'operator.log', // the consented operator channel's audit trail
36
- audit: 'audit.log', // privileged action audit trail (share/sync/agent — S8)
37
- });
38
-
39
- // Logs the operator channel may tail BY NAME — never an arbitrary path.
40
- export const TAILABLE = Object.freeze(Object.keys(LOG_FILES));
41
-
42
- export function logFile(name, env = process.env) {
43
- return path.join(globalDir(env), LOG_FILES[name] || `${name}.log`);
44
- }
45
-
46
- export function diagnosticsDir(env = process.env) {
47
- return path.join(globalDir(env), 'diagnostics');
48
- }
49
-
50
- const MAX_LOG_BYTES = 2 * 1024 * 1024; // 2 MB → rotate to .1 (keep one prior gen)
51
-
52
- // Rotate `file` to `file.1` once it grows past maxBytes. Best-effort, no throw.
53
- export function rotateIfBig(file, maxBytes = MAX_LOG_BYTES) {
54
- try {
55
- if (fs.statSync(file).size > maxBytes) fs.renameSync(file, `${file}.1`);
56
- } catch {
57
- /* missing / racing rename — nothing to rotate */
58
- }
59
- }
60
-
61
- // Append a timestamped line to a named log; ensures the dir + rotates. Returns
62
- // the file path. Never throws — logging must not break the caller's path.
63
- export function appendLine(name, line, env = process.env) {
64
- const file = logFile(name, env);
65
- try {
66
- fs.mkdirSync(path.dirname(file), { recursive: true });
67
- rotateIfBig(file);
68
- fs.appendFileSync(file, `[${new Date().toISOString()}] ${line}\n`);
69
- } catch {
70
- /* read-only fs etc. — degrade silently */
71
- }
72
- return file;
73
- }
74
-
75
- // Last `n` lines of a file (logs are size-capped, so reading whole is cheap).
76
- // Returns '' when the file is missing/unreadable.
77
- export function tailFile(file, n = 200) {
78
- try {
79
- // Drop the trailing newline so the last line isn't an empty entry.
80
- const lines = fs.readFileSync(file, 'utf8').replace(/\r?\n$/, '').split(/\r?\n/);
81
- return lines.slice(Math.max(0, lines.length - n)).join('\n');
82
- } catch {
83
- return '';
84
- }
85
- }
86
-
87
- // All known logs with on-disk size + mtime (null when absent) — for doctor/logs.
88
- export function listLogs(env = process.env) {
89
- return TAILABLE.map((name) => {
90
- const file = logFile(name, env);
91
- try {
92
- const st = fs.statSync(file);
93
- return { name, file, exists: true, size: st.size, mtime: st.mtimeMs };
94
- } catch {
95
- return { name, file, exists: false, size: null, mtime: null };
96
- }
97
- });
98
- }
1
+ // logpaths — one registry for the machine-global logs so `doctor`, `logs`, and
2
+ // the operator channel all read the same set, and a tiny append/rotate/tail
3
+ // helper for the new logs we write ourselves (cli, operator).
4
+ //
5
+ // WHY a registry and not just scattered paths: a brand-new user's install is the
6
+ // riskiest moment (no Claude yet, wrong Node, port busy, daemon won't resolve),
7
+ // and "I can't see what happened on their machine" is the #1 un-debuggable
8
+ // failure. Centralising the log locations is what lets `wild-workspace doctor`
9
+ // gather them and the operator channel tail them by name — never by arbitrary
10
+ // path (the tail allowlist is TAILABLE below).
11
+ //
12
+ // NOTE: the supervisor + daemon-supervisor keep writing their logs at the
13
+ // global-dir root (supervisor.log / server.out.log / daemon.log) — those paths
14
+ // are reboot-proven and pinned by tests via an injected globalDir, so we mirror
15
+ // them here for READING rather than moving them. Everything lives under
16
+ // ~/.wild-workspace (NEVER the synced workspace — CLAUDE.md principle #1).
17
+
18
+ import os from 'node:os';
19
+ import path from 'node:path';
20
+ import fs from 'node:fs';
21
+
22
+ // THE machine-global dir. Mirrors service.mjs globalDir() + the supervisor
23
+ // defaults. Overridable via env for tests / unusual homes.
24
+ export function globalDir(env = process.env) {
25
+ return env.WILD_WORKSPACE_GLOBAL_DIR || path.join(os.homedir(), '.wild-workspace');
26
+ }
27
+
28
+ // Logical name → filename. The first three are written by existing components;
29
+ // cli + operator are new. Doctor bundles go under diagnosticsDir() (below).
30
+ export const LOG_FILES = Object.freeze({
31
+ supervisor: 'supervisor.log', // WorkspaceSupervisor watchdog
32
+ server: 'server.out.log', // the :5173 server's stdout/stderr (launcher-redirected)
33
+ daemon: 'daemon.log', // the bmo-sync daemon
34
+ cli: 'cli.log', // every `wild-workspace …` invocation (first-run capture)
35
+ operator: 'operator.log', // the consented operator channel's audit trail
36
+ audit: 'audit.log', // privileged action audit trail (share/sync/agent — S8)
37
+ });
38
+
39
+ // Logs the operator channel may tail BY NAME — never an arbitrary path.
40
+ export const TAILABLE = Object.freeze(Object.keys(LOG_FILES));
41
+
42
+ export function logFile(name, env = process.env) {
43
+ return path.join(globalDir(env), LOG_FILES[name] || `${name}.log`);
44
+ }
45
+
46
+ export function diagnosticsDir(env = process.env) {
47
+ return path.join(globalDir(env), 'diagnostics');
48
+ }
49
+
50
+ const MAX_LOG_BYTES = 2 * 1024 * 1024; // 2 MB → rotate to .1 (keep one prior gen)
51
+
52
+ // Rotate `file` to `file.1` once it grows past maxBytes. Best-effort, no throw.
53
+ export function rotateIfBig(file, maxBytes = MAX_LOG_BYTES) {
54
+ try {
55
+ if (fs.statSync(file).size > maxBytes) fs.renameSync(file, `${file}.1`);
56
+ } catch {
57
+ /* missing / racing rename — nothing to rotate */
58
+ }
59
+ }
60
+
61
+ // Append a timestamped line to a named log; ensures the dir + rotates. Returns
62
+ // the file path. Never throws — logging must not break the caller's path.
63
+ export function appendLine(name, line, env = process.env) {
64
+ const file = logFile(name, env);
65
+ try {
66
+ fs.mkdirSync(path.dirname(file), { recursive: true });
67
+ rotateIfBig(file);
68
+ fs.appendFileSync(file, `[${new Date().toISOString()}] ${line}\n`);
69
+ } catch {
70
+ /* read-only fs etc. — degrade silently */
71
+ }
72
+ return file;
73
+ }
74
+
75
+ // Last `n` lines of a file (logs are size-capped, so reading whole is cheap).
76
+ // Returns '' when the file is missing/unreadable.
77
+ export function tailFile(file, n = 200) {
78
+ try {
79
+ // Drop the trailing newline so the last line isn't an empty entry.
80
+ const lines = fs.readFileSync(file, 'utf8').replace(/\r?\n$/, '').split(/\r?\n/);
81
+ return lines.slice(Math.max(0, lines.length - n)).join('\n');
82
+ } catch {
83
+ return '';
84
+ }
85
+ }
86
+
87
+ // All known logs with on-disk size + mtime (null when absent) — for doctor/logs.
88
+ export function listLogs(env = process.env) {
89
+ return TAILABLE.map((name) => {
90
+ const file = logFile(name, env);
91
+ try {
92
+ const st = fs.statSync(file);
93
+ return { name, file, exists: true, size: st.size, mtime: st.mtimeMs };
94
+ } catch {
95
+ return { name, file, exists: false, size: null, mtime: null };
96
+ }
97
+ });
98
+ }