@sakupa/mcp 0.7.9 → 0.7.10

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 (3) hide show
  1. package/dist/bin.js +73 -20
  2. package/dist/index.js +73 -20
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -129,7 +129,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
129
129
  var ALLOWED_HIDDEN_PATHS = [".well-known/"];
130
130
 
131
131
  // ../core/dist/domain/version.js
132
- var SAKUPA_MCP_VERSION = "0.7.9";
132
+ var SAKUPA_MCP_VERSION = "0.7.10";
133
133
 
134
134
  // ../core/dist/domain/errors.js
135
135
  var HTTP_STATUS = {
@@ -1358,6 +1358,26 @@ async function diagnoseBinding(input) {
1358
1358
  const layers = `Pipeline: [1] public DNS (checked LIVE above) -> [2] Sakupa ownership verification: ${input.verificationStatus} -> [3] HTTPS certificate & serving: ` + (input.provisioning ? "provisioning (Cloudflare validates and issues within minutes once the records above are all OK; Sakupa retries automatically every ~5 minutes)." : "starts after verification.");
1359
1359
  return { checks, apexResolves, allOk, checklist, layers };
1360
1360
  }
1361
+ var DNS_RETRY_AFTER_SECONDS = 300;
1362
+ var DNS_MAX_ATTEMPTS = 10;
1363
+ function toDnsChecklist(checks) {
1364
+ return checks.map((c) => ({
1365
+ name: c.record.name,
1366
+ type: c.record.type,
1367
+ shortHost: c.shortHost,
1368
+ state: c.state,
1369
+ ...c.fix ? { fix: c.fix } : {}
1370
+ }));
1371
+ }
1372
+ function renderChecklistBlock(diag, fixTail) {
1373
+ const cadence = `Re-check every ${DNS_RETRY_AFTER_SECONDS / 60} minutes, up to ${DNS_MAX_ATTEMPTS} times.`;
1374
+ return `Live DNS checklist (host values are the SHORT panel form):
1375
+ ${diag.checklist}
1376
+
1377
+ ${diag.layers}
1378
+
1379
+ ` + (diag.allOk ? "All records are live; certificate issuance completes automatically \u2014 re-check in a few minutes until the binding is active." : `${fixTail} ${cadence}`);
1380
+ }
1361
1381
 
1362
1382
  // src/version.ts
1363
1383
  var MCP_VERSION = SAKUPA_MCP_VERSION;
@@ -1609,8 +1629,38 @@ async function uploadAll(ctx, targets, files, outputAbs) {
1609
1629
  }
1610
1630
  return targets.length;
1611
1631
  }
1612
- var DNS_RETRY_AFTER_SECONDS = 300;
1613
- var DNS_MAX_ATTEMPTS = 10;
1632
+ async function describePendingBinding(client, credential, pb) {
1633
+ const framing = `
1634
+ Domain binding IN PROGRESS: ${pb.apexDomain} \u2014 ` + (pb.phase === "provisioning" ? "ownership verified; certificates/serving are provisioning." : `awaiting DNS verification (challenge valid until ${pb.verificationExpiresAt}).`);
1635
+ let check;
1636
+ try {
1637
+ check = await client.checkVerification(pb.verificationId, credential);
1638
+ } catch {
1639
+ return {
1640
+ note: framing + "\n(Couldn't refresh binding progress from the server just now \u2014 try site_status again shortly.)"
1641
+ };
1642
+ }
1643
+ try {
1644
+ const diag = await diagnoseBinding({
1645
+ apexDomain: check.apexDomain,
1646
+ servingTarget: check.servingTarget,
1647
+ ...check.verificationRecord ? { verificationRecord: check.verificationRecord } : {},
1648
+ pendingDnsRecords: check.pendingDnsRecords,
1649
+ verificationStatus: check.status,
1650
+ provisioning: pb.phase === "provisioning"
1651
+ });
1652
+ const block = renderChecklistBlock(
1653
+ diag,
1654
+ "Relay every [MISSING]/[FIX] line to the user with its exact fix."
1655
+ );
1656
+ return { note: `${framing}
1657
+ ${block}`, checklist: toDnsChecklist(diag.checks) };
1658
+ } catch {
1659
+ return {
1660
+ note: framing + '\n(Live DNS lookups are unavailable right now \u2014 run bind_domain with action "status" for the per-record checklist.)'
1661
+ };
1662
+ }
1663
+ }
1614
1664
  function freeSiteCreationBarrier() {
1615
1665
  const recent = listRecentCreations(Date.now());
1616
1666
  if (recent.length < FREE_ACTIVE_SITES_PER_IP) return null;
@@ -1871,9 +1921,11 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
1871
1921
  const ctx = withProjectDir(baseCtx, args.projectDir);
1872
1922
  const site = requireSiteFile(ctx);
1873
1923
  const res = await ctx.client.getSiteStatus(site.siteId, site.credential);
1874
- return textJson("site_status_returned", "Site status:", {
1924
+ const binding = res.pendingDomainBinding ? await describePendingBinding(ctx.client, site.credential, res.pendingDomainBinding) : void 0;
1925
+ return textJson("site_status_returned", `Site status:${binding?.note ?? ""}`, {
1875
1926
  ...res,
1876
- projectDir: ctx.projectDir
1927
+ projectDir: ctx.projectDir,
1928
+ ...binding?.checklist ? { dnsChecklist: binding.checklist } : {}
1877
1929
  });
1878
1930
  } catch (e) {
1879
1931
  return toolError(e);
@@ -1952,7 +2004,7 @@ Once payment confirms, the site becomes permanent on its current URL. Binding a
1952
2004
  writeSiteFile(ctx.projectDir, { ...site, boundDomain: res2.apexDomain });
1953
2005
  }
1954
2006
  const apex2 = res2.apexDomain;
1955
- const { checks, apexResolves, allOk, checklist, layers } = await diagnoseBinding({
2007
+ const diag = await diagnoseBinding({
1956
2008
  apexDomain: apex2,
1957
2009
  servingTarget: res2.servingTarget,
1958
2010
  ...res2.verificationRecord ? { verificationRecord: res2.verificationRecord } : {},
@@ -1960,30 +2012,23 @@ Once payment confirms, the site becomes permanent on its current URL. Binding a
1960
2012
  verificationStatus: res2.status,
1961
2013
  provisioning: res2.provisioningJobId !== void 0
1962
2014
  });
2015
+ const { apexResolves, allOk } = diag;
1963
2016
  return text(
1964
2017
  res2.status === "verified" ? "domain_verification_succeeded" : "domain_verification_pending",
1965
2018
  `Domain binding status for ${apex2}: ${res2.status}
1966
2019
  ${res2.message}
1967
2020
 
1968
- Live DNS checklist (host values are the SHORT panel form):
1969
- ${checklist}
1970
-
1971
- ${layers}
1972
-
1973
- ` + (allOk && res2.status === "verified" ? "All records are live; certificate issuance completes automatically \u2014 check again in a few minutes until the binding is active." : "Fix any [MISSING]/[FIX] lines above, then re-run bind_domain status. Re-check every 5 minutes, up to 10 times; if still failing after that, show the user this checklist."),
2021
+ ` + renderChecklistBlock(
2022
+ diag,
2023
+ "Fix any [MISSING]/[FIX] lines above, then re-run bind_domain status; if still failing after the attempts below, show the user this checklist."
2024
+ ),
1974
2025
  {
1975
2026
  verificationId: res2.verificationId,
1976
2027
  status: res2.status,
1977
2028
  apexDomain: apex2,
1978
2029
  provisioningJobId: res2.provisioningJobId,
1979
2030
  servingTarget: res2.servingTarget,
1980
- dnsChecklist: checks.map((c) => ({
1981
- name: c.record.name,
1982
- type: c.record.type,
1983
- shortHost: c.shortHost,
1984
- state: c.state,
1985
- fix: c.fix || void 0
1986
- })),
2031
+ dnsChecklist: toDnsChecklist(diag.checks),
1987
2032
  apexResolves,
1988
2033
  retryAfterSeconds: DNS_RETRY_AFTER_SECONDS,
1989
2034
  maxAttempts: DNS_MAX_ATTEMPTS,
@@ -2291,6 +2336,12 @@ ${res.archiveUrl}`,
2291
2336
  deploymentId: z3.string().optional(),
2292
2337
  severity: severityEnum.optional(),
2293
2338
  description: z3.string().optional().describe("What happened, in the user's words (no secrets)."),
2339
+ agentContext: z3.string().optional().describe(
2340
+ "YOUR OWN factual account of the session as the AI: which tools you called, what they returned, expected vs actual. Write it yourself from your observations \u2014 never ask the user to compose it, and do not read it back to them; it travels alongside the user's description as a second witness. No secrets, no file contents."
2341
+ ),
2342
+ contactEmail: z3.string().optional().describe(
2343
+ "OPTIONAL. Before submitting, ask the user ONCE whether they want to leave a contact for follow-up. Omit entirely if they decline \u2014 never require it."
2344
+ ),
2294
2345
  confirmSubmit: z3.boolean().optional().describe("User reviewed the report payload and approved submission.")
2295
2346
  }
2296
2347
  },
@@ -2315,7 +2366,9 @@ ${res.archiveUrl}`,
2315
2366
  ...site ? { siteId: site.siteId } : {},
2316
2367
  ...args.severity !== void 0 ? { severity: args.severity } : {},
2317
2368
  diagnostics,
2318
- ...args.description !== void 0 ? { description: args.description } : {}
2369
+ ...args.description !== void 0 ? { description: args.description } : {},
2370
+ ...args.agentContext !== void 0 ? { agentContext: args.agentContext } : {},
2371
+ ...args.contactEmail !== void 0 ? { contactEmail: args.contactEmail } : {}
2319
2372
  };
2320
2373
  if (args.confirmSubmit !== true) {
2321
2374
  return textJson(
package/dist/index.js CHANGED
@@ -124,7 +124,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
124
124
  var ALLOWED_HIDDEN_PATHS = [".well-known/"];
125
125
 
126
126
  // ../core/dist/domain/version.js
127
- var SAKUPA_MCP_VERSION = "0.7.9";
127
+ var SAKUPA_MCP_VERSION = "0.7.10";
128
128
 
129
129
  // ../core/dist/domain/errors.js
130
130
  var HTTP_STATUS = {
@@ -1566,6 +1566,26 @@ async function diagnoseBinding(input) {
1566
1566
  const layers = `Pipeline: [1] public DNS (checked LIVE above) -> [2] Sakupa ownership verification: ${input.verificationStatus} -> [3] HTTPS certificate & serving: ` + (input.provisioning ? "provisioning (Cloudflare validates and issues within minutes once the records above are all OK; Sakupa retries automatically every ~5 minutes)." : "starts after verification.");
1567
1567
  return { checks, apexResolves, allOk, checklist, layers };
1568
1568
  }
1569
+ var DNS_RETRY_AFTER_SECONDS = 300;
1570
+ var DNS_MAX_ATTEMPTS = 10;
1571
+ function toDnsChecklist(checks) {
1572
+ return checks.map((c) => ({
1573
+ name: c.record.name,
1574
+ type: c.record.type,
1575
+ shortHost: c.shortHost,
1576
+ state: c.state,
1577
+ ...c.fix ? { fix: c.fix } : {}
1578
+ }));
1579
+ }
1580
+ function renderChecklistBlock(diag, fixTail) {
1581
+ const cadence = `Re-check every ${DNS_RETRY_AFTER_SECONDS / 60} minutes, up to ${DNS_MAX_ATTEMPTS} times.`;
1582
+ return `Live DNS checklist (host values are the SHORT panel form):
1583
+ ${diag.checklist}
1584
+
1585
+ ${diag.layers}
1586
+
1587
+ ` + (diag.allOk ? "All records are live; certificate issuance completes automatically \u2014 re-check in a few minutes until the binding is active." : `${fixTail} ${cadence}`);
1588
+ }
1569
1589
 
1570
1590
  // src/tools/definitions.ts
1571
1591
  function text(resultCode, t, data = {}, outcome = "completed") {
@@ -1673,8 +1693,38 @@ async function uploadAll(ctx, targets, files, outputAbs) {
1673
1693
  }
1674
1694
  return targets.length;
1675
1695
  }
1676
- var DNS_RETRY_AFTER_SECONDS = 300;
1677
- var DNS_MAX_ATTEMPTS = 10;
1696
+ async function describePendingBinding(client, credential, pb) {
1697
+ const framing = `
1698
+ Domain binding IN PROGRESS: ${pb.apexDomain} \u2014 ` + (pb.phase === "provisioning" ? "ownership verified; certificates/serving are provisioning." : `awaiting DNS verification (challenge valid until ${pb.verificationExpiresAt}).`);
1699
+ let check;
1700
+ try {
1701
+ check = await client.checkVerification(pb.verificationId, credential);
1702
+ } catch {
1703
+ return {
1704
+ note: framing + "\n(Couldn't refresh binding progress from the server just now \u2014 try site_status again shortly.)"
1705
+ };
1706
+ }
1707
+ try {
1708
+ const diag = await diagnoseBinding({
1709
+ apexDomain: check.apexDomain,
1710
+ servingTarget: check.servingTarget,
1711
+ ...check.verificationRecord ? { verificationRecord: check.verificationRecord } : {},
1712
+ pendingDnsRecords: check.pendingDnsRecords,
1713
+ verificationStatus: check.status,
1714
+ provisioning: pb.phase === "provisioning"
1715
+ });
1716
+ const block = renderChecklistBlock(
1717
+ diag,
1718
+ "Relay every [MISSING]/[FIX] line to the user with its exact fix."
1719
+ );
1720
+ return { note: `${framing}
1721
+ ${block}`, checklist: toDnsChecklist(diag.checks) };
1722
+ } catch {
1723
+ return {
1724
+ note: framing + '\n(Live DNS lookups are unavailable right now \u2014 run bind_domain with action "status" for the per-record checklist.)'
1725
+ };
1726
+ }
1727
+ }
1678
1728
  function freeSiteCreationBarrier() {
1679
1729
  const recent = listRecentCreations(Date.now());
1680
1730
  if (recent.length < FREE_ACTIVE_SITES_PER_IP) return null;
@@ -1935,9 +1985,11 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
1935
1985
  const ctx = withProjectDir(baseCtx, args.projectDir);
1936
1986
  const site = requireSiteFile(ctx);
1937
1987
  const res = await ctx.client.getSiteStatus(site.siteId, site.credential);
1938
- return textJson("site_status_returned", "Site status:", {
1988
+ const binding = res.pendingDomainBinding ? await describePendingBinding(ctx.client, site.credential, res.pendingDomainBinding) : void 0;
1989
+ return textJson("site_status_returned", `Site status:${binding?.note ?? ""}`, {
1939
1990
  ...res,
1940
- projectDir: ctx.projectDir
1991
+ projectDir: ctx.projectDir,
1992
+ ...binding?.checklist ? { dnsChecklist: binding.checklist } : {}
1941
1993
  });
1942
1994
  } catch (e) {
1943
1995
  return toolError(e);
@@ -2016,7 +2068,7 @@ Once payment confirms, the site becomes permanent on its current URL. Binding a
2016
2068
  writeSiteFile(ctx.projectDir, { ...site, boundDomain: res2.apexDomain });
2017
2069
  }
2018
2070
  const apex2 = res2.apexDomain;
2019
- const { checks, apexResolves, allOk, checklist, layers } = await diagnoseBinding({
2071
+ const diag = await diagnoseBinding({
2020
2072
  apexDomain: apex2,
2021
2073
  servingTarget: res2.servingTarget,
2022
2074
  ...res2.verificationRecord ? { verificationRecord: res2.verificationRecord } : {},
@@ -2024,30 +2076,23 @@ Once payment confirms, the site becomes permanent on its current URL. Binding a
2024
2076
  verificationStatus: res2.status,
2025
2077
  provisioning: res2.provisioningJobId !== void 0
2026
2078
  });
2079
+ const { apexResolves, allOk } = diag;
2027
2080
  return text(
2028
2081
  res2.status === "verified" ? "domain_verification_succeeded" : "domain_verification_pending",
2029
2082
  `Domain binding status for ${apex2}: ${res2.status}
2030
2083
  ${res2.message}
2031
2084
 
2032
- Live DNS checklist (host values are the SHORT panel form):
2033
- ${checklist}
2034
-
2035
- ${layers}
2036
-
2037
- ` + (allOk && res2.status === "verified" ? "All records are live; certificate issuance completes automatically \u2014 check again in a few minutes until the binding is active." : "Fix any [MISSING]/[FIX] lines above, then re-run bind_domain status. Re-check every 5 minutes, up to 10 times; if still failing after that, show the user this checklist."),
2085
+ ` + renderChecklistBlock(
2086
+ diag,
2087
+ "Fix any [MISSING]/[FIX] lines above, then re-run bind_domain status; if still failing after the attempts below, show the user this checklist."
2088
+ ),
2038
2089
  {
2039
2090
  verificationId: res2.verificationId,
2040
2091
  status: res2.status,
2041
2092
  apexDomain: apex2,
2042
2093
  provisioningJobId: res2.provisioningJobId,
2043
2094
  servingTarget: res2.servingTarget,
2044
- dnsChecklist: checks.map((c) => ({
2045
- name: c.record.name,
2046
- type: c.record.type,
2047
- shortHost: c.shortHost,
2048
- state: c.state,
2049
- fix: c.fix || void 0
2050
- })),
2095
+ dnsChecklist: toDnsChecklist(diag.checks),
2051
2096
  apexResolves,
2052
2097
  retryAfterSeconds: DNS_RETRY_AFTER_SECONDS,
2053
2098
  maxAttempts: DNS_MAX_ATTEMPTS,
@@ -2355,6 +2400,12 @@ ${res.archiveUrl}`,
2355
2400
  deploymentId: z3.string().optional(),
2356
2401
  severity: severityEnum.optional(),
2357
2402
  description: z3.string().optional().describe("What happened, in the user's words (no secrets)."),
2403
+ agentContext: z3.string().optional().describe(
2404
+ "YOUR OWN factual account of the session as the AI: which tools you called, what they returned, expected vs actual. Write it yourself from your observations \u2014 never ask the user to compose it, and do not read it back to them; it travels alongside the user's description as a second witness. No secrets, no file contents."
2405
+ ),
2406
+ contactEmail: z3.string().optional().describe(
2407
+ "OPTIONAL. Before submitting, ask the user ONCE whether they want to leave a contact for follow-up. Omit entirely if they decline \u2014 never require it."
2408
+ ),
2358
2409
  confirmSubmit: z3.boolean().optional().describe("User reviewed the report payload and approved submission.")
2359
2410
  }
2360
2411
  },
@@ -2379,7 +2430,9 @@ ${res.archiveUrl}`,
2379
2430
  ...site ? { siteId: site.siteId } : {},
2380
2431
  ...args.severity !== void 0 ? { severity: args.severity } : {},
2381
2432
  diagnostics,
2382
- ...args.description !== void 0 ? { description: args.description } : {}
2433
+ ...args.description !== void 0 ? { description: args.description } : {},
2434
+ ...args.agentContext !== void 0 ? { agentContext: args.agentContext } : {},
2435
+ ...args.contactEmail !== void 0 ? { contactEmail: args.contactEmail } : {}
2383
2436
  };
2384
2437
  if (args.confirmSubmit !== true) {
2385
2438
  return textJson(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sakupa/mcp",
3
- "version": "0.7.9",
3
+ "version": "0.7.10",
4
4
  "description": "Sakupa MCP server: publish AI-made static sites from your AI tool. AI-made pages, live in seconds.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",