@venturewild/workspace 0.3.6 → 0.3.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.
Files changed (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +112 -112
  3. package/package.json +83 -83
  4. package/server/bin/wild-workspace.mjs +995 -995
  5. package/server/src/account.mjs +114 -114
  6. package/server/src/agent-login.mjs +146 -146
  7. package/server/src/agent-readiness.mjs +200 -200
  8. package/server/src/agent.mjs +468 -453
  9. package/server/src/bazaar/core.mjs +579 -579
  10. package/server/src/bazaar/index.mjs +75 -75
  11. package/server/src/bazaar/mcp-server.mjs +328 -328
  12. package/server/src/bazaar/mock-tickup.mjs +97 -97
  13. package/server/src/bazaar/preview-server.mjs +95 -95
  14. package/server/src/bazaar/seed-recipes/customer-feedback-form/know-how.md +23 -23
  15. package/server/src/bazaar/seed-recipes/customer-feedback-form/recipe.json +24 -24
  16. package/server/src/bazaar/seed-recipes/landing-page-launch/know-how.md +29 -29
  17. package/server/src/bazaar/seed-recipes/landing-page-launch/recipe.json +25 -25
  18. package/server/src/bazaar/seed-recipes/personal-portfolio/know-how.md +21 -21
  19. package/server/src/bazaar/seed-recipes/personal-portfolio/recipe.json +24 -24
  20. package/server/src/bazaar/seed-recipes/receipt-sorter/know-how.md +31 -31
  21. package/server/src/bazaar/seed-recipes/receipt-sorter/recipe.json +25 -25
  22. package/server/src/bazaar/seed-recipes/tickup-hr-matching/know-how.md +79 -79
  23. package/server/src/bazaar/seed-recipes/tickup-hr-matching/recipe.json +32 -32
  24. package/server/src/canvas/core.mjs +421 -421
  25. package/server/src/canvas/index.mjs +42 -42
  26. package/server/src/canvas/mcp-server.mjs +253 -253
  27. package/server/src/config.mjs +404 -404
  28. package/server/src/daemon-bin.mjs +110 -110
  29. package/server/src/daemon-supervisor.mjs +285 -285
  30. package/server/src/doctor.mjs +375 -375
  31. package/server/src/inbox.mjs +86 -86
  32. package/server/src/index.mjs +2475 -2365
  33. package/server/src/logpaths.mjs +98 -98
  34. package/server/src/observability.mjs +45 -45
  35. package/server/src/operator.mjs +92 -92
  36. package/server/src/pairing.mjs +137 -137
  37. package/server/src/service.mjs +515 -515
  38. package/server/src/session-reporter.mjs +201 -201
  39. package/server/src/settings.mjs +145 -0
  40. package/server/src/share.mjs +182 -182
  41. package/server/src/skills.mjs +213 -0
  42. package/server/src/supervisor.mjs +647 -647
  43. package/server/src/support-consent.mjs +133 -133
  44. package/server/src/sync.mjs +248 -248
  45. package/server/src/transcript.mjs +121 -121
  46. package/server/src/turn-mcp.mjs +46 -46
  47. package/server/src/usage.mjs +405 -0
  48. package/web/dist/assets/index-BxRx8EsD.js +91 -0
  49. package/web/dist/assets/index-DoOPBr3s.css +1 -0
  50. package/web/dist/index.html +2 -2
  51. package/web/dist/assets/index-B7cOsWLt.js +0 -91
  52. package/web/dist/assets/index-Dl0VT5e6.css +0 -1
@@ -1,24 +1,24 @@
1
- {
2
- "id": "personal-portfolio",
3
- "title": "Personal portfolio site",
4
- "producer": { "name": "Nia", "handle": "nia", "kind": "maker" },
5
- "pitch": "A sharp one-page portfolio — intro, projects, contact — live in one shot.",
6
- "vendorDescription": "Nia's portfolio template. The layout that landed her three freelance clients: a confident intro, a project grid, and a contact line that converts.",
7
- "summary": "A single-page portfolio: hero intro, a grid of project cards, and a contact section. Swap the text and images to make it yours.",
8
- "outcomeScore": 0.81,
9
- "outcomeStats": { "builds": 40, "working": 32 },
10
- "safetyBadge": "tested",
11
- "rating": { "stars": 4.3, "count": 21 },
12
- "tags": [
13
- "portfolio", "personal site", "personal website", "resume site", "cv site",
14
- "about me", "showcase", "designer portfolio", "developer portfolio", "projects"
15
- ],
16
- "reward": {
17
- "model": "one-time",
18
- "unit": "per build",
19
- "perUseValue": 0,
20
- "oneTimeValue": 5.0,
21
- "note": "Nia earns a one-time share each time her portfolio know-how is used."
22
- },
23
- "buildDir": "portfolio"
24
- }
1
+ {
2
+ "id": "personal-portfolio",
3
+ "title": "Personal portfolio site",
4
+ "producer": { "name": "Nia", "handle": "nia", "kind": "maker" },
5
+ "pitch": "A sharp one-page portfolio — intro, projects, contact — live in one shot.",
6
+ "vendorDescription": "Nia's portfolio template. The layout that landed her three freelance clients: a confident intro, a project grid, and a contact line that converts.",
7
+ "summary": "A single-page portfolio: hero intro, a grid of project cards, and a contact section. Swap the text and images to make it yours.",
8
+ "outcomeScore": 0.81,
9
+ "outcomeStats": { "builds": 40, "working": 32 },
10
+ "safetyBadge": "tested",
11
+ "rating": { "stars": 4.3, "count": 21 },
12
+ "tags": [
13
+ "portfolio", "personal site", "personal website", "resume site", "cv site",
14
+ "about me", "showcase", "designer portfolio", "developer portfolio", "projects"
15
+ ],
16
+ "reward": {
17
+ "model": "one-time",
18
+ "unit": "per build",
19
+ "perUseValue": 0,
20
+ "oneTimeValue": 5.0,
21
+ "note": "Nia earns a one-time share each time her portfolio know-how is used."
22
+ },
23
+ "buildDir": "portfolio"
24
+ }
@@ -1,31 +1,31 @@
1
- # Sam's receipt-sorter — how to build it
2
-
3
- > Absorb this and build the user a receipt-sorting tool in one shot. Single
4
- > self-contained `index.html` (inline CSS + JS), no build step, runs offline.
5
-
6
- ## Build steps
7
-
8
- 1. Create `receipt-sorter/index.html`.
9
- 2. The page:
10
- - A **textarea** to paste receipts, one per line, in a loose form like
11
- `2026-03-04 Uber 18.50` or `Adobe subscription 52.99`. Prefill with ~6
12
- realistic example lines so it's usable immediately.
13
- - A **"Sort receipts"** button.
14
- - A **results table**: columns Date · Vendor · Category · Amount, best-effort
15
- parsed from each line. Below it, a **category breakdown** (sum per category)
16
- and a **grand total**.
17
- 3. Categorize with a simple keyword map you can extend, e.g. Uber/Lyft/taxi →
18
- Travel; restaurant/coffee/lunch → Meals; Adobe/Figma/subscription/SaaS →
19
- Software; staples/paper/supplies → Supplies; everything else → Other.
20
- 4. Parse the amount as the last number on the line; parse a leading ISO date if
21
- present. Be forgiving — never crash on a weird line, just put it in "Other".
22
- 5. House style: clean, tabular, easy to scan. One accent color. A small "Export
23
- CSV" button that downloads the table is a nice touch.
24
-
25
- ## Finish
26
-
27
- After writing the files:
28
-
29
- 1. Call **`launch_preview`** with `{ "dir": "receipt-sorter" }`.
30
- 2. Call **`record_use`** with recipe id `receipt-sorter` and a short summary.
31
- 3. Tell the user it's live in the preview, briefly.
1
+ # Sam's receipt-sorter — how to build it
2
+
3
+ > Absorb this and build the user a receipt-sorting tool in one shot. Single
4
+ > self-contained `index.html` (inline CSS + JS), no build step, runs offline.
5
+
6
+ ## Build steps
7
+
8
+ 1. Create `receipt-sorter/index.html`.
9
+ 2. The page:
10
+ - A **textarea** to paste receipts, one per line, in a loose form like
11
+ `2026-03-04 Uber 18.50` or `Adobe subscription 52.99`. Prefill with ~6
12
+ realistic example lines so it's usable immediately.
13
+ - A **"Sort receipts"** button.
14
+ - A **results table**: columns Date · Vendor · Category · Amount, best-effort
15
+ parsed from each line. Below it, a **category breakdown** (sum per category)
16
+ and a **grand total**.
17
+ 3. Categorize with a simple keyword map you can extend, e.g. Uber/Lyft/taxi →
18
+ Travel; restaurant/coffee/lunch → Meals; Adobe/Figma/subscription/SaaS →
19
+ Software; staples/paper/supplies → Supplies; everything else → Other.
20
+ 4. Parse the amount as the last number on the line; parse a leading ISO date if
21
+ present. Be forgiving — never crash on a weird line, just put it in "Other".
22
+ 5. House style: clean, tabular, easy to scan. One accent color. A small "Export
23
+ CSV" button that downloads the table is a nice touch.
24
+
25
+ ## Finish
26
+
27
+ After writing the files:
28
+
29
+ 1. Call **`launch_preview`** with `{ "dir": "receipt-sorter" }`.
30
+ 2. Call **`record_use`** with recipe id `receipt-sorter` and a short summary.
31
+ 3. Tell the user it's live in the preview, briefly.
@@ -1,25 +1,25 @@
1
- {
2
- "id": "receipt-sorter",
3
- "title": "Sort receipts into a tidy expense table",
4
- "producer": { "name": "Sam", "handle": "sam", "kind": "maker" },
5
- "pitch": "Paste a pile of receipts and get a clean, categorized expense table with totals — built in one shot.",
6
- "vendorDescription": "Sam built this to stop drowning in shoebox receipts at tax time. Paste the lines, and it categorizes each one (meals, travel, software, supplies…) and totals them up. His agent packaged it so anyone can use it.",
7
- "summary": "A single page where you paste receipt lines and get a sorted, categorized table with a running total and a category breakdown. No spreadsheet skills needed.",
8
- "outcomeScore": 0.83,
9
- "outcomeStats": { "builds": 22, "working": 18 },
10
- "safetyBadge": "tested",
11
- "rating": { "stars": 4.4, "count": 14 },
12
- "tags": [
13
- "receipts", "receipt", "expenses", "expense", "bookkeeping", "spreadsheet",
14
- "csv", "accounting", "invoices", "invoice", "tax", "taxes", "sort",
15
- "categorize", "budget", "finance", "money tracking"
16
- ],
17
- "reward": {
18
- "model": "one-time",
19
- "unit": "per build",
20
- "perUseValue": 0,
21
- "oneTimeValue": 5.0,
22
- "note": "Sam earns a one-time share each time his receipt-sorter know-how is used."
23
- },
24
- "buildDir": "receipt-sorter"
25
- }
1
+ {
2
+ "id": "receipt-sorter",
3
+ "title": "Sort receipts into a tidy expense table",
4
+ "producer": { "name": "Sam", "handle": "sam", "kind": "maker" },
5
+ "pitch": "Paste a pile of receipts and get a clean, categorized expense table with totals — built in one shot.",
6
+ "vendorDescription": "Sam built this to stop drowning in shoebox receipts at tax time. Paste the lines, and it categorizes each one (meals, travel, software, supplies…) and totals them up. His agent packaged it so anyone can use it.",
7
+ "summary": "A single page where you paste receipt lines and get a sorted, categorized table with a running total and a category breakdown. No spreadsheet skills needed.",
8
+ "outcomeScore": 0.83,
9
+ "outcomeStats": { "builds": 22, "working": 18 },
10
+ "safetyBadge": "tested",
11
+ "rating": { "stars": 4.4, "count": 14 },
12
+ "tags": [
13
+ "receipts", "receipt", "expenses", "expense", "bookkeeping", "spreadsheet",
14
+ "csv", "accounting", "invoices", "invoice", "tax", "taxes", "sort",
15
+ "categorize", "budget", "finance", "money tracking"
16
+ ],
17
+ "reward": {
18
+ "model": "one-time",
19
+ "unit": "per build",
20
+ "perUseValue": 0,
21
+ "oneTimeValue": 5.0,
22
+ "note": "Sam earns a one-time share each time his receipt-sorter know-how is used."
23
+ },
24
+ "buildDir": "receipt-sorter"
25
+ }
@@ -1,79 +1,79 @@
1
- # TickUp HR-matching kit — how to build it
2
-
3
- > This is TickUp's hard-won way of standing up candidate matching. Absorb it and
4
- > build it for the user in one shot. You are building **the user's own hiring
5
- > site**; it calls TickUp's matching service to do the ranking.
6
-
7
- ## What you're building
8
-
9
- A single-page hiring site that lets a recruiter:
10
-
11
- 1. describe a **role** (free text),
12
- 2. paste a list of **candidates** (one per line), and
13
- 3. get them **auto-ranked** with a score and a one-line reason for each.
14
-
15
- The ranking is done by **TickUp's matching service** — your site sends the role +
16
- candidates to it and renders what comes back. You do **not** write the matching
17
- logic yourself; that's TickUp's engine.
18
-
19
- ## Build steps
20
-
21
- 1. Create a folder `candidate-matcher/` in the workspace root.
22
- 2. Put everything in a single `candidate-matcher/index.html` (inline CSS + JS — no
23
- build step, no dependencies, so it just runs).
24
- 3. The page layout:
25
- - A header with the title (e.g. the user's agency name + "· Candidate Matcher")
26
- and a small line **"Matching by TickUp"**.
27
- - A **Role** `<textarea>` — prefill it with a realistic example so the page is
28
- usable the instant it loads, e.g.:
29
- `Senior Frontend Engineer — React + TypeScript, design systems, 5+ years, startup pace.`
30
- - A **Candidates** `<textarea>` — one candidate per line in the form
31
- `Name — skills / experience`. Prefill 5 realistic examples, e.g.:
32
- ```
33
- Maya Chen — React, TypeScript, design systems, 6y, ex-Stripe
34
- Daniel Okafor — Vue, JavaScript, 3y agency
35
- Priya Nair — React, Node, GraphQL, 7y, led a frontend team
36
- Tom Becker — Python, Django, data, 4y
37
- Aisha Rahman — React, TypeScript, accessibility, 5y, startup
38
- ```
39
- - A **"Find best matches"** button.
40
- - A results area (empty until the button is clicked).
41
- 4. Wire the button: on click, POST to the matching service at the **same-origin
42
- path `/match`** with `{ role, candidates }` where `candidates` is the lines of
43
- the candidates box (trimmed, non-empty). Then render the returned `ranked`
44
- array as cards, **best first**.
45
- ```js
46
- const res = await fetch('/match', {
47
- method: 'POST',
48
- headers: { 'Content-Type': 'application/json' },
49
- body: JSON.stringify({ role, candidates }),
50
- });
51
- const data = await res.json();
52
- // data.ranked is best-first: [{ name: string, score: 0-100, why: string, skills: string[] }]
53
- ```
54
- Each result card shows: the candidate **name**, the **score** (0–100) as a
55
- number **and** a horizontal bar, and the **why** line. Give the top match a
56
- subtle "Top match" ribbon.
57
-
58
- ## Make it feel good (TickUp house style)
59
-
60
- - Clean, modern, lots of whitespace. System font stack.
61
- - TickUp accent gradient: `#6d5efc → #4d8bff` for the header and the score bars.
62
- - Cards with soft shadow + rounded corners. Score bar fills proportional to score.
63
- - A tiny empty state in the results area before the first search
64
- ("Describe a role and your candidates, then hit Find best matches").
65
- - It should look like a real product, not a form. This is the moment the user
66
- thinks *"I built this?"* — make it land.
67
-
68
- ## Finish (so the user sees it immediately)
69
-
70
- After the files are written:
71
-
72
- 1. Call **`launch_preview`** with `{ "dir": "candidate-matcher" }` so the live
73
- preview opens on the user's screen with the site running.
74
- 2. Call **`record_use`** with the recipe id `tickup-hr-matching` and a one-line
75
- `summary` of what you built, so TickUp gets credit and the marketplace records
76
- the transaction.
77
- 3. Tell the user, in one or two short sentences, that it's live in the preview —
78
- invite them to try a search. Never mention "API" or internal mechanics; speak
79
- like a capable assistant who just built them a thing.
1
+ # TickUp HR-matching kit — how to build it
2
+
3
+ > This is TickUp's hard-won way of standing up candidate matching. Absorb it and
4
+ > build it for the user in one shot. You are building **the user's own hiring
5
+ > site**; it calls TickUp's matching service to do the ranking.
6
+
7
+ ## What you're building
8
+
9
+ A single-page hiring site that lets a recruiter:
10
+
11
+ 1. describe a **role** (free text),
12
+ 2. paste a list of **candidates** (one per line), and
13
+ 3. get them **auto-ranked** with a score and a one-line reason for each.
14
+
15
+ The ranking is done by **TickUp's matching service** — your site sends the role +
16
+ candidates to it and renders what comes back. You do **not** write the matching
17
+ logic yourself; that's TickUp's engine.
18
+
19
+ ## Build steps
20
+
21
+ 1. Create a folder `candidate-matcher/` in the workspace root.
22
+ 2. Put everything in a single `candidate-matcher/index.html` (inline CSS + JS — no
23
+ build step, no dependencies, so it just runs).
24
+ 3. The page layout:
25
+ - A header with the title (e.g. the user's agency name + "· Candidate Matcher")
26
+ and a small line **"Matching by TickUp"**.
27
+ - A **Role** `<textarea>` — prefill it with a realistic example so the page is
28
+ usable the instant it loads, e.g.:
29
+ `Senior Frontend Engineer — React + TypeScript, design systems, 5+ years, startup pace.`
30
+ - A **Candidates** `<textarea>` — one candidate per line in the form
31
+ `Name — skills / experience`. Prefill 5 realistic examples, e.g.:
32
+ ```
33
+ Maya Chen — React, TypeScript, design systems, 6y, ex-Stripe
34
+ Daniel Okafor — Vue, JavaScript, 3y agency
35
+ Priya Nair — React, Node, GraphQL, 7y, led a frontend team
36
+ Tom Becker — Python, Django, data, 4y
37
+ Aisha Rahman — React, TypeScript, accessibility, 5y, startup
38
+ ```
39
+ - A **"Find best matches"** button.
40
+ - A results area (empty until the button is clicked).
41
+ 4. Wire the button: on click, POST to the matching service at the **same-origin
42
+ path `/match`** with `{ role, candidates }` where `candidates` is the lines of
43
+ the candidates box (trimmed, non-empty). Then render the returned `ranked`
44
+ array as cards, **best first**.
45
+ ```js
46
+ const res = await fetch('/match', {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({ role, candidates }),
50
+ });
51
+ const data = await res.json();
52
+ // data.ranked is best-first: [{ name: string, score: 0-100, why: string, skills: string[] }]
53
+ ```
54
+ Each result card shows: the candidate **name**, the **score** (0–100) as a
55
+ number **and** a horizontal bar, and the **why** line. Give the top match a
56
+ subtle "Top match" ribbon.
57
+
58
+ ## Make it feel good (TickUp house style)
59
+
60
+ - Clean, modern, lots of whitespace. System font stack.
61
+ - TickUp accent gradient: `#6d5efc → #4d8bff` for the header and the score bars.
62
+ - Cards with soft shadow + rounded corners. Score bar fills proportional to score.
63
+ - A tiny empty state in the results area before the first search
64
+ ("Describe a role and your candidates, then hit Find best matches").
65
+ - It should look like a real product, not a form. This is the moment the user
66
+ thinks *"I built this?"* — make it land.
67
+
68
+ ## Finish (so the user sees it immediately)
69
+
70
+ After the files are written:
71
+
72
+ 1. Call **`launch_preview`** with `{ "dir": "candidate-matcher" }` so the live
73
+ preview opens on the user's screen with the site running.
74
+ 2. Call **`record_use`** with the recipe id `tickup-hr-matching` and a one-line
75
+ `summary` of what you built, so TickUp gets credit and the marketplace records
76
+ the transaction.
77
+ 3. Tell the user, in one or two short sentences, that it's live in the preview —
78
+ invite them to try a search. Never mention "API" or internal mechanics; speak
79
+ like a capable assistant who just built them a thing.
@@ -1,32 +1,32 @@
1
- {
2
- "id": "tickup-hr-matching",
3
- "title": "HR platform with AI candidate matching",
4
- "producer": { "name": "TickUp", "handle": "tickup", "kind": "vendor" },
5
- "pitch": "Stand up a hiring page that auto-ranks candidates against any role — powered by TickUp's matching engine.",
6
- "vendorDescription": "TickUp's HR-matching kit. We've shipped candidate matching for 200+ recruiting teams. Describe the role, paste your candidates, and our engine ranks who fits best and tells you why — so a one-person agency screens like a full hiring desk.",
7
- "summary": "A clean single-page hiring site (no setup, no login) with a role box and a candidate list. Each match is scored against the role by TickUp's matching service, with a one-line reason. Built for you in one shot; the matching runs every time you use it.",
8
- "outcomeScore": 0.94,
9
- "outcomeStats": { "builds": 38, "working": 36 },
10
- "safetyBadge": "verified",
11
- "rating": { "stars": 4.8, "count": 27 },
12
- "tags": [
13
- "hr", "human resources", "recruiting", "recruiter", "recruitment",
14
- "candidate", "candidates", "candidate matching", "matching", "match",
15
- "hiring", "hire", "applicant", "applicants", "ats", "talent", "resume",
16
- "resumes", "screening", "shortlist", "job", "roles"
17
- ],
18
- "reward": {
19
- "model": "recurring",
20
- "unit": "per match",
21
- "perUseValue": 0.40,
22
- "oneTimeValue": 12.0,
23
- "note": "TickUp earns a small amount every time the matching service ranks candidates — for as long as the site runs."
24
- },
25
- "service": {
26
- "id": "tickup-match",
27
- "label": "TickUp matching service",
28
- "endpointPath": "/match",
29
- "contract": "POST /match body: { role: string, candidates: string[] } -> { ranked: [{ name: string, score: number(0-100), why: string, skills: string[] }] } (ranked is best-first; skills is a list of strings)"
30
- },
31
- "buildDir": "candidate-matcher"
32
- }
1
+ {
2
+ "id": "tickup-hr-matching",
3
+ "title": "HR platform with AI candidate matching",
4
+ "producer": { "name": "TickUp", "handle": "tickup", "kind": "vendor" },
5
+ "pitch": "Stand up a hiring page that auto-ranks candidates against any role — powered by TickUp's matching engine.",
6
+ "vendorDescription": "TickUp's HR-matching kit. We've shipped candidate matching for 200+ recruiting teams. Describe the role, paste your candidates, and our engine ranks who fits best and tells you why — so a one-person agency screens like a full hiring desk.",
7
+ "summary": "A clean single-page hiring site (no setup, no login) with a role box and a candidate list. Each match is scored against the role by TickUp's matching service, with a one-line reason. Built for you in one shot; the matching runs every time you use it.",
8
+ "outcomeScore": 0.94,
9
+ "outcomeStats": { "builds": 38, "working": 36 },
10
+ "safetyBadge": "verified",
11
+ "rating": { "stars": 4.8, "count": 27 },
12
+ "tags": [
13
+ "hr", "human resources", "recruiting", "recruiter", "recruitment",
14
+ "candidate", "candidates", "candidate matching", "matching", "match",
15
+ "hiring", "hire", "applicant", "applicants", "ats", "talent", "resume",
16
+ "resumes", "screening", "shortlist", "job", "roles"
17
+ ],
18
+ "reward": {
19
+ "model": "recurring",
20
+ "unit": "per match",
21
+ "perUseValue": 0.40,
22
+ "oneTimeValue": 12.0,
23
+ "note": "TickUp earns a small amount every time the matching service ranks candidates — for as long as the site runs."
24
+ },
25
+ "service": {
26
+ "id": "tickup-match",
27
+ "label": "TickUp matching service",
28
+ "endpointPath": "/match",
29
+ "contract": "POST /match body: { role: string, candidates: string[] } -> { ranked: [{ name: string, score: number(0-100), why: string, skills: string[] }] } (ranked is best-first; skills is a list of strings)"
30
+ },
31
+ "buildDir": "candidate-matcher"
32
+ }