@wirl/mcp 0.2.3 → 0.2.4

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 (2) hide show
  1. package/bin.js +114 -72
  2. package/package.json +1 -1
package/bin.js CHANGED
@@ -2463,7 +2463,7 @@ var init_manifest = __esm({
2463
2463
  };
2464
2464
  CREATABLE_CONNECTION_KINDS = CONNECTION_KINDS.filter((kind) => !(kind in UNDELIVERED_KINDS));
2465
2465
  needsNoKey = (kind) => kind === "none";
2466
- ACCENTS = ["blue", "green", "sun", "purple", "red", "sky", "orange", "lime"];
2466
+ ACCENTS = ["blue", "green", "sun", "purple", "red", "sky", "orange", "lime", "mint", "butter", "blush", "lilac"];
2467
2467
  SCHEDULE_LIMITS = {
2468
2468
  perApp: 10,
2469
2469
  minTimeoutMs: 3e4,
@@ -2923,7 +2923,11 @@ var init_retention = __esm({
2923
2923
  * The counts settle a "why was my app paused" question and the claims
2924
2924
  * ration the mail; neither is worth anything two months on.
2925
2925
  */
2926
- flowDayRowsDays: 60
2926
+ flowDayRowsDays: 60,
2927
+ /** A row of the AI call ledger is kept this long, then removed. */
2928
+ aiCallDays: 90,
2929
+ /** An AI monthly total (the rows the caps read) is kept this long, 24 months. */
2930
+ aiMonthDays: 730
2927
2931
  };
2928
2932
  }
2929
2933
  });
@@ -2956,6 +2960,7 @@ own live deploy and a person's yes. Declare a host under \`connections\`, then \
2956
2960
  wirl attaches the key. An undeclared host is refused; a public API needing no key uses \`"kind": "none"\`.
2957
2961
  Declaring one deploys before anyone approves it; the deploy says per connection whether it is usable now or
2958
2962
  waiting on an admin. A vendor has 60 seconds to answer, whole, unless it streams: ask a model for a stream.
2963
+ Models: \`https://ai.wirl/<vendor>/\u2026\` (openrouter, openai, anthropic, google) with the vendor's own API and no key; OpenRouter works out of the box on wirl's allowance, an org's own key lifts it. See Models.
2959
2964
 
2960
2965
  Six headers say who is asking: \`x-wirl-user-id\`, \`x-wirl-user-email\`, \`x-wirl-user-name\`,
2961
2966
  \`x-wirl-role\`, \`x-wirl-app-id\`, \`x-wirl-org\`. Read the name with
@@ -3008,7 +3013,7 @@ var init_version = __esm({
3008
3013
  "packages/core/src/version.ts"() {
3009
3014
  "use strict";
3010
3015
  WORKSPACE_VERSION = "0.0.0";
3011
- BUILT_VERSION = true ? "0.2.3" : null;
3016
+ BUILT_VERSION = true ? "0.2.4" : null;
3012
3017
  }
3013
3018
  });
3014
3019
 
@@ -5195,11 +5200,12 @@ company email domain; in any other org, including a personal one or one
5195
5200
  made with \`wirl orgs create\`, it starts private. Deploys are one
5196
5201
  command; sharing is by email; a third-party API is declared, never pasted.`;
5197
5202
  var SKILL_DOCS_LINE = "Before you build, fetch https://docs.wirl.dev/llms-full.txt: every page of the docs as one Markdown file, so there is no need to read the site page by page.";
5198
- var SKILL_RULES = `1. **Never ask for or paste an API key.** Declare the connection in \`wirl.json\` and deploy. Needs no key at all (a public API)? Declare it with "kind": "none" and its hosts. If the key is missing, the deploy prints a link to the app's keys page; show the person that link. Locally, keys live in \`.wirl/keys.json\`, which git ignores. To try a vendor call locally without the key, map its connection to a server of your own in \`.wirl/mocks.json\`, like \`{ "anthropic": "http://127.0.0.1:4010" }\`: \`wirl dev\` then sends the calls to that connection's hosts there instead (\`wirl dev --help\` has the rest).
5203
+ var SKILL_RULES = `1. **Never ask for or paste an API key.** Declare the connection in \`wirl.json\` and deploy. Needs no key at all (a public API)? Declare it with "kind": "none" and its hosts. If the key is missing, the deploy prints a link to the app's keys page; show the person that link. Locally, keys live in \`.wirl/keys.json\`, which git ignores. To try a vendor call locally without the key, map its connection to a server of your own in \`.wirl/mocks.json\`, like \`{ "anthropic": "http://127.0.0.1:4010" }\`: \`wirl dev\` then sends the calls to that connection's hosts there instead (\`wirl dev --help\` has the rest). Models need no key either: call https://ai.wirl/<vendor>/\u2026 (see Models).
5199
5204
  2. **Call third-party APIs by their real URL** (\`fetch("https://api.hubspot.com/...")\`). wirl attaches the key on the way out, deployed and under \`wirl dev\` alike.
5200
- 3. If a command names several organisations and asks which, ask the person; pass \`--org\` or put \`"org"\` in \`wirl.json\`.
5201
- 4. To keep a file out of the deploy, list it in a \`.wirlignore\` at the project root (gitignore-style lines; no \`!\` negation).
5202
- 5. **A file that can lose data waits for a person.** A deploy that would apply a destructive file (one wirl.json's \`"destructive"\` list must name) to the live database stops and names the page where a person approves each one. Show the person those pages, and deploy again once they say they approved. If \`${WIRL_BIN} deploy\` asks you to type a file's name, stop it and show the page instead, or deploy with \`--json\`, which never asks. Never type the name yourself or send the confirmation: that is the person's, and no flag skips it.`;
5205
+ 3. **Asked to connect an app to Slack, or to receive events from any outside service:** follow the pattern on https://docs.wirl.dev/models (public path with "verify": "slack", a connection of kind http_bearer for the bot token and one of kind webhook_secret for the signing secret, the Slack app manifest you give the person to create the app with). Never ask for the token or secret in chat: the person pastes them on the app's Connections page, and you say which two values.
5206
+ 4. If a command names several organisations and asks which, ask the person; pass \`--org\` or put \`"org"\` in \`wirl.json\`.
5207
+ 5. To keep a file out of the deploy, list it in a \`.wirlignore\` at the project root (gitignore-style lines; no \`!\` negation).
5208
+ 6. **A file that can lose data waits for a person.** A deploy that would apply a destructive file (one wirl.json's \`"destructive"\` list must name) to the live database stops and names the page where a person approves each one. Show the person those pages, and deploy again once they say they approved. If \`${WIRL_BIN} deploy\` asks you to type a file's name, stop it and show the page instead, or deploy with \`--json\`, which never asks. Never type the name yourself or send the confirmation: that is the person's, and no flag skips it.`;
5203
5209
  var SKILL_MANIFEST_EXAMPLE = `\`\`\`json
5204
5210
  { "app": "crm-sync", "server": "server.mjs", "connections": [{ "slug": "hubspot", "hosts": ["api.hubspot.com"] }] }
5205
5211
  \`\`\``;
@@ -5250,37 +5256,59 @@ ${FLOWS_CONTRACT}
5250
5256
  init_src();
5251
5257
  var SUGGESTIONS = [
5252
5258
  {
5253
- title: "Rename it to something we'd actually use",
5254
- prompt: `Rename this noticeboard to something my team would actually use. Ask me what we would use it for, suggest three names, and when I pick one, change the page's title and heading and the description in wirl.json to match. Keep "app" in wirl.json as it is: a new name there would make a second app at a new address. Then deploy it with wirl deploy.`
5259
+ number: 1,
5260
+ title: "Summarise the week",
5261
+ capability: "A model comes with every app. Your agent just uses it; nothing to sign up for or paste.",
5262
+ prompt: `Add a "Summarise this week" button above the notes. When pressed, send this week's notes to a language model and show a three-line summary at the top of the page. Try it with wirl dev, then deploy it with wirl deploy. Keep the latest summary so everyone who opens the page sees it.`,
5263
+ youGet: "a summary card above the notes."
5255
5264
  },
5256
5265
  {
5257
- title: "Try a new look in a preview first",
5258
- prompt: "Give the noticeboard a warmer look: pinned notes as coloured cards, and tags as small coloured labels. Put it up with wirl preview first and give me the preview's address to check. Deploy it with wirl deploy only after I say it looks right."
5266
+ number: 2,
5267
+ title: "Give notes a due date",
5268
+ capability: "The database is yours. Changing its shape is one migration file and one deploy; wirl applies it before the new version goes live, and the Data page on the dashboard shows the result.",
5269
+ prompt: "Add an optional due date to notes. Add the column in a new migration file with the next number, and never edit a migration that has already been applied. Let people set the date when they post or edit a note, show it on each note, and put notes due soonest at the top. Try it with wirl dev, then deploy it with wirl deploy.",
5270
+ youGet: "a date on each note, the soonest first, and a new column on the Data page."
5259
5271
  },
5260
5272
  {
5261
- title: "Add a due date to notes",
5262
- prompt: "Add an optional due date to notes on the noticeboard. Add the column in a new file, migrations/0002_due_date.sql, and never edit 0001. Let people set the date when they post or edit a note, show it on each note, and put notes due soonest at the top. Try it with wirl dev, then deploy it with wirl deploy."
5273
+ number: 3,
5274
+ title: "Pull in something from outside",
5275
+ capability: "Every call out goes through wirl. The agent declares the host as a connection; a public API needs no key, and one that does gets its key on the dashboard, never in the code.",
5276
+ prompt: `Show today's weather under the notes for our city (ask me which city if you don't know), from a public weather API that needs no key. Declare the API's host as a connection in wirl.json with "kind": "none". Try it with wirl dev, then deploy it with wirl deploy. If the deploy says the connection is waiting on an admin, show me the link it prints.`,
5277
+ youGet: "a weather line under the notes, and the host listed on the app's Connections page."
5263
5278
  },
5264
5279
  {
5265
- title: "Show the weather from a public API",
5266
- prompt: `Show today's weather for our office at the top of the noticeboard, from Open-Meteo, a public weather API that needs no key. Ask me which city our office is in. Add this entry to "connections" in wirl.json: {"slug": "open-meteo", "kind": "none", "hosts": ["api.open-meteo.com"]}. Fetch Open-Meteo's own URL from server.mjs, and deploy it with wirl deploy. If the deploy says open-meteo is waiting, the connection needs approving, which your sign-in cannot do: tell me to approve it on the app's Connections page on app.wirl.dev, or to ask an admin of our organisation to. The weather shows once it is approved.`
5280
+ number: 4,
5281
+ title: "Try a new look before anyone sees it",
5282
+ // The mock says "Previews are free."; the starter carries no price words (its test forbids "free").
5283
+ capability: "Previews are a safe place to try. A preview gets its own address and its own database, so you can look at a change with a colleague before it goes live.",
5284
+ prompt: "Give the noticeboard a calmer look: more space between notes, a softer background, the newest note set apart at the top. Put it up as a preview called new-look with wirl preview and give me the link. Don't deploy it yet. Keep the change on a branch and don't run wirl deploy until I say deploy it.",
5285
+ youGet: 'a second address to open next to this one. Say "deploy it" when you like it.'
5267
5286
  },
5268
5287
  {
5269
- title: "Change when the tidy-up runs",
5270
- prompt: "Change the noticeboard's nightly tidy-up: archive notes after 14 days instead of 30, and run it at 6pm on weekdays in my time zone (ask me which). Change the schedule in wirl.json and the number in server.mjs, deploy it with wirl deploy, then run it once with wirl run tidy and tell me what it said."
5271
- },
5272
- {
5273
- title: "Find out what happened from the logs",
5274
- prompt: "Read this app's logs with wirl logs and tell me, in a few lines, what people did on the noticeboard today and whether anything failed."
5288
+ number: 5,
5289
+ title: "Share it with a colleague",
5290
+ capability: "Company sign-in is already on. Anyone you name opens the link with their work account; the Access page shows who can, and you can take it back any time.",
5291
+ prompt: "Help me share this app with a colleague: tell me how to give them access and the link they open.",
5292
+ youGet: "their name on the Access page, and a link they open with their work account."
5275
5293
  },
5276
5294
  {
5277
- title: "Share it with a colleague",
5278
- prompt: `Help me share this noticeboard with a colleague. Sharing is done by me, not by a deploy: tell me to share it from the app's Access page on app.wirl.dev (the "Who can open it" row on the noticeboard links to it), where I add their email address. Then tell me what they will see when they open the address.`
5295
+ number: 6,
5296
+ title: "Connect it to Slack",
5297
+ capability: "Apps can reach the tools your company already uses. Your agent knows wirl's Slack pattern: it gives you a Slack app to create in one click, you paste two values on the app's Connections page, and the noticeboard starts a DM with you. Ask it about the notes, or tell it to add one, from Slack.",
5298
+ prompt: "Connect this noticeboard to Slack so it DMs me this week's summary and I can chat with it there: ask it about the notes, or tell it to add or change one. Give me the Slack app manifest to create the app with, and tell me which two values to paste on the app's Connections page.",
5299
+ youGet: "a DM from the noticeboard in Slack. Everything above works without it.",
5300
+ optional: true
5279
5301
  }
5280
5302
  ];
5303
+ var splitCapability = (capability) => {
5304
+ const stop = capability.indexOf(". ");
5305
+ return [capability.slice(0, stop + 1), capability.slice(stop + 2)];
5306
+ };
5281
5307
  var SUGGESTIONS_SOURCE = [
5282
5308
  "const SUGGESTIONS = [",
5283
- ...SUGGESTIONS.map(({ title, prompt }) => ` { title: ${JSON.stringify(title)}, prompt: ${JSON.stringify(prompt)} },`),
5309
+ ...SUGGESTIONS.map(
5310
+ ({ number, title, capability, prompt, youGet, optional }) => ` { number: ${String(number)}, title: ${JSON.stringify(title)}, capability: ${JSON.stringify(capability)}, prompt: ${JSON.stringify(prompt)}, youGet: ${JSON.stringify(youGet)}${optional ? ", optional: true" : ""} },`
5311
+ ),
5284
5312
  "];"
5285
5313
  ].join("\n");
5286
5314
  var SERVER_HEAD = String.raw`/**
@@ -5288,9 +5316,9 @@ var SERVER_HEAD = String.raw`/**
5288
5316
  *
5289
5317
  * Your team posts short notes here, tags them, pins the ones everyone should
5290
5318
  * see, and edits or removes their own. Every night a schedule archives old
5291
- * notes nobody pinned. The page also explains itself: a "How this works on
5292
- * wirl" panel, one row per feature, each linking to that page of the app on
5293
- * app.wirl.dev, and a few changes to ask your coding agent for next.
5319
+ * notes nobody pinned. Below the notes, "Make it yours": six prompts to
5320
+ * paste to your coding agent, in order, each saying what wirl gives the app
5321
+ * and what you get. Under them, the app's pages on app.wirl.dev.
5294
5322
  *
5295
5323
  * The whole app is this one file:
5296
5324
  * - The page is HTML this module returns: plain forms, no script.
@@ -5461,8 +5489,9 @@ async function page(request, url, me, env) {
5461
5489
  "<p class='dim'>Your first app on wirl. Signed in as <b>" + escape(me.name) + "</b>" + (me.role ? " (" + escape(me.role) + ")" : "") + ".</p></header>",
5462
5490
  shown,
5463
5491
  "<ul class='notes'>" + (notes.length === 0 ? "<li class='dim'>Nothing here yet.</li>" : notes.map((note) => card(note, me, archived)).join("")) + "</ul>",
5464
- panel(request, me, lastRun),
5465
- suggestions(),
5492
+ "<p class='dim'>Nightly tidy-up, which archives notes older than " + ARCHIVE_AFTER_DAYS + " days that nobody pinned: " +
5493
+ (lastRun ? "last run " + escape(lastRun.ran_at.slice(0, 16)) + " UTC: " + escape(lastRun.note) : "Not run yet.") + "</p>",
5494
+ prompts(request),
5466
5495
  "</main>",
5467
5496
  "</html>",
5468
5497
  ].join("\n");
@@ -5507,50 +5536,54 @@ function card(note, me, archived) {
5507
5536
  );
5508
5537
  }
5509
5538
 
5510
- // The app's page on the dashboard, from the address it was opened at:
5539
+ // The app's pages on the dashboard, from the address it was opened at:
5511
5540
  // <org>--<app>.wirl.run, or <org>--<app>--<preview>.wirl.run for a preview.
5512
5541
  // Under wirl dev the address is 127.0.0.1, which names no app: null.
5513
5542
  function dashboard(request) {
5514
5543
  const label = new URL(request.url).hostname.split(".")[0];
5515
5544
  const parts = label.split("--");
5516
5545
  if (parts.length < 2) return null;
5517
- const org = request.headers.get("x-wirl-org") || parts[0];
5518
- return DASHBOARD + "/apps/" + encodeURIComponent(org) + "/" + encodeURIComponent(parts[1]);
5546
+ const org = encodeURIComponent(request.headers.get("x-wirl-org") || parts[0]);
5547
+ return { app: DASHBOARD + "/apps/" + org + "/" + encodeURIComponent(parts[1]), org: DASHBOARD + "/orgs/" + org };
5519
5548
  }
5520
5549
 
5521
- function panel(request, me, lastRun) {
5522
- const base = dashboard(request);
5523
- const last = lastRun ? "Last run " + lastRun.ran_at.slice(0, 16) + " UTC: " + lastRun.note : "Not run yet.";
5524
- // One row per feature: what it is, what it does in this app, and its page.
5525
- const rows = [
5526
- ["Who can open it", "wirl signed you in before this page loaded and tells the app who you are, in headers: here you are " + me.name + (me.role ? ", " + me.role : "") + ". The app has no sign-in code of its own. It started private to you; choose who else can open it on Access.", "/access", "Access"],
5527
- ["Your data", "Notes are rows in this app's own SQLite database. Its tables are in migrations/0001_init.sql, and a deploy applies each new file in migrations/ before it goes live.", "/deployments", "Deployments"],
5528
- ["A schedule", "tidy runs every night at 02:00 UTC and archives notes older than " + ARCHIVE_AFTER_DAYS + " days that nobody pinned. " + last + " Run it now from Overview.", "", "Overview"],
5529
- ["Logs", "Each request writes a line with console.log, and so does each change to a note. Read them on Logs, or ask your agent to run wirl logs.", "/logs", "Logs"],
5530
- ["Versions", "Each wirl deploy is a new version, and the earlier ones stay: going back to one takes a click.", "/deployments", "Deployments"],
5531
- ["Previews", "wirl preview puts a change up at an address of its own, with its own database, and nothing goes live until you deploy. Open previews are listed on Overview.", "", "Overview"],
5532
- ["Outside APIs", "Declare a connection in wirl.json and fetch the service's own URL: wirl adds the key on the way out, so it never reaches this code or a chat.", "/connections", "Connections"],
5533
- ["Settings", "Describe the app for your team's list of tools, hand it to someone else, or delete it.", "/settings", "Settings"],
5550
+ // The onboarding path: each prompt whole, visible and ready to select and
5551
+ // copy, with what wirl gives the app and what you get. Then what the app
5552
+ // already uses, and its pages on the dashboard.
5553
+ function prompts(request) {
5554
+ const where = dashboard(request);
5555
+ const pages = [
5556
+ ["Overview", "app", ""],
5557
+ ["Data", "app", "/data"],
5558
+ ["Access", "app", "/access"],
5559
+ ["Logs", "app", "/logs"],
5560
+ ["Deployments", "app", "/deployments"],
5561
+ ["Models", "org", "/models"],
5562
+ ["Connections", "app", "/connections"],
5563
+ ["Settings", "app", "/settings"],
5534
5564
  ];
5565
+ const link = ([label, of, path]) =>
5566
+ where === null ? "<span class='dim'>" + label + "</span>" : "<a href='" + escape(where[of] + path) + "'>" + label + "</a>";
5567
+ const step = (each) => {
5568
+ const stop = each.capability.indexOf(". ");
5569
+ return (
5570
+ "<li class='step" + (each.optional ? " optional" : "") + "'>" +
5571
+ "<h3><span class='number'>" + each.number + "</span> " + escape(each.title) +
5572
+ (each.optional ? " <span class='badge'>Optional. The big one.</span>" : "") + "</h3>" +
5573
+ "<p class='dim'><b>" + escape(each.capability.slice(0, stop + 1)) + "</b> " + escape(each.capability.slice(stop + 2)) + "</p>" +
5574
+ "<pre>" + escape(each.prompt) + "</pre>" +
5575
+ "<p class='dim'>You get: " + escape(each.youGet) + "</p>" +
5576
+ "</li>"
5577
+ );
5578
+ };
5535
5579
  return [
5536
- "<section><h2>How this works on wirl</h2>",
5537
- "<table>",
5538
- ...rows.map(([feature, what, path, label]) =>
5539
- "<tr><td>" + feature + "</td><td>" + escape(what) + "</td><td>" +
5540
- (base === null ? "<span class='dim'>" + label + "</span>" : "<a href='" + escape(base + path) + "'>" + label + "</a>") +
5541
- "</td></tr>",
5542
- ),
5543
- "</table>",
5544
- base === null ? "<p class='dim'>Running under wirl dev, so these pages are not linked here: they open on app.wirl.dev once it is deployed.</p>" : "",
5545
- "</section>",
5546
- ].join("\n");
5547
- }
5548
-
5549
- function suggestions() {
5550
- return [
5551
- "<section><h2>Ask your agent for a first change</h2>",
5552
- "<p class='dim'>Each of these is a whole prompt. Open one, copy it, and paste it to the coding agent that made this app.</p>",
5553
- ...SUGGESTIONS.map((each) => "<details><summary>" + escape(each.title) + "</summary><pre>" + escape(each.prompt) + "</pre></details>"),
5580
+ "<section id='prompts'><h2>Make it yours</h2>",
5581
+ "<p>This app is live, at a link your team can open. Everything below is a whole prompt. Copy one, paste it to the coding agent that made this app, and the feature appears here on the next deploy. Go in order or skip around; the last one is the big one.</p>",
5582
+ "<ol class='steps'>",
5583
+ ...SUGGESTIONS.map(step),
5584
+ "</ol>",
5585
+ "<p class='dim uses'>This app already uses a database, a nightly schedule, company sign-in and logs. Each has a page on the dashboard: " + pages.map(link).join(" · ") + "</p>",
5586
+ where === null ? "<p class='dim'>Running under wirl dev, so these pages are not linked here: they open on app.wirl.dev once it is deployed.</p>" : "",
5554
5587
  "</section>",
5555
5588
  ].join("\n");
5556
5589
  }
@@ -5575,10 +5608,16 @@ const STYLE = [
5575
5608
  ".meta, .actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 13px; }",
5576
5609
  ".actions { margin-top: 8px; } .actions form { margin: 0; } .actions details { flex-basis: 100%; order: 3; }",
5577
5610
  ".tag { text-decoration: none; }",
5578
- "table { width: 100%; border-collapse: collapse; font-size: 14px; }",
5579
- "td { border-top: 1px solid var(--line); padding: 8px 6px; vertical-align: top; }",
5580
- "td:first-child { font-weight: 600; }",
5581
- "pre { white-space: pre-wrap; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 10px; font-size: 13px; }",
5611
+ "ol.steps { list-style: none; padding: 0; display: grid; gap: 12px; }",
5612
+ ".step { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; }",
5613
+ ".step.optional { border: 2px solid var(--accent); }",
5614
+ ".step h3 { font-size: 16px; margin: 0 0 6px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }",
5615
+ ".step p { margin: 6px 0; } .step b { color: var(--accent); }",
5616
+ ".number { font-size: 12px; background: var(--ink); color: var(--bg); padding: 2px 7px; border-radius: 5px; }",
5617
+ ".optional .number { background: var(--accent); }",
5618
+ ".badge { font-size: 12px; font-weight: 600; color: var(--dim); border: 1px solid var(--line); padding: 1px 8px; border-radius: 999px; }",
5619
+ ".uses { border-top: 1px solid var(--line); padding-top: 12px; font-size: 14px; }",
5620
+ "pre { white-space: pre-wrap; user-select: all; background: var(--bg); border: 1px solid var(--line); border-radius: 6px; padding: 10px; font-size: 13px; }",
5582
5621
  "details { margin: 6px 0; } summary { cursor: pointer; }",
5583
5622
  ].join("\n");
5584
5623
 
@@ -5640,7 +5679,7 @@ var README = [
5640
5679
  "",
5641
5680
  "Your first app on wirl: a board where your team posts short notes, tags them, pins the ones everyone should see, and edits or removes their own. Every night a schedule archives old notes nobody pinned.",
5642
5681
  "",
5643
- 'Open it at the address `wirl deploy` prints. It starts private to you. Its page has a "How this works on wirl" panel: one row per thing wirl does for this app, each linking to that page of the app on app.wirl.dev.',
5682
+ "Open it at the address `wirl deploy` prints. It starts private to you. Its page is the way in: six prompts to give your coding agent, each saying what wirl gives the app and what you get, and under them the app's pages on app.wirl.dev.",
5644
5683
  "",
5645
5684
  "## What is where",
5646
5685
  "",
@@ -5655,11 +5694,14 @@ var README = [
5655
5694
  "",
5656
5695
  "It prints the address to open, and a `curl` line that runs the nightly tidy-up now.",
5657
5696
  "",
5658
- "## Changes to ask your agent for",
5697
+ "## Make it yours",
5659
5698
  "",
5660
- "Each is a whole prompt: paste it to your coding agent as it is.",
5699
+ "The same six prompts as the page. Each is a whole prompt: paste it to your coding agent as it is. Go in order or skip around; the last one is the big one.",
5661
5700
  "",
5662
- ...SUGGESTIONS.flatMap(({ title, prompt }) => [`### ${title}`, "", `> ${prompt}`, ""])
5701
+ ...SUGGESTIONS.flatMap(({ number, title, capability, prompt, youGet, optional }) => {
5702
+ const [bold, rest] = splitCapability(capability);
5703
+ return [`### ${String(number)}. ${title}`, "", ...optional ? ["Optional. The big one.", ""] : [], `**${bold}** ${rest}`, "", `> ${prompt}`, "", `You get: ${youGet}`, ""];
5704
+ })
5663
5705
  ].join("\n");
5664
5706
  var STARTER_FILES = {
5665
5707
  "server.mjs": SERVER_MODULE,
@@ -6274,7 +6316,7 @@ async function callApiBytes(creds, path, options = {}) {
6274
6316
  body = {};
6275
6317
  }
6276
6318
  if (response.status === 401 || response.status === 403) {
6277
- throw new CliError("Not signed in, or this token cannot do that.", `Try \`${WIRL_BIN} login\`.`);
6319
+ throw new CliError("Not signed in, or this token cannot do that.", `Try \`${WIRL_BIN} login\`.`, { code: "unauthenticated" });
6278
6320
  }
6279
6321
  if (response.status === 404) throw new CliError("Not found, or you do not have access to it.");
6280
6322
  throw new CliError(body.message ?? body.error ?? `Request failed (${response.status}).`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirl/mcp",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "MCP server for wirl: let your coding agent deploy what it just built, privately.",
5
5
  "keywords": [
6
6
  "mcp",