ugly-app 0.1.761 → 0.1.763

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.
@@ -1 +1 @@
1
- {"version":3,"file":"feedbackResolve.d.ts","sourceRoot":"","sources":["../../src/cli/feedbackResolve.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAiDD,wBAAsB,eAAe,CACnC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,MAAM,CAAC,EAAE,CACP,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAChD,IAAI,GACR,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAiB3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8BpE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CASzD"}
1
+ {"version":3,"file":"feedbackResolve.d.ts","sourceRoot":"","sources":["../../src/cli/feedbackResolve.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD,wBAAsB,eAAe,CACnC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,MAAM,CAAC,EAAE,CACP,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAChD,IAAI,GACR,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAe3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8BpE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CASzD"}
@@ -1,43 +1,21 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { getUglyBotUrl } from '../shared/uglyBotUrl.js';
5
- function readAuth() {
6
- const authPath = path.join(os.homedir(), '.ugly-bot', 'auth.json');
7
- if (!fs.existsSync(authPath)) {
8
- throw new Error('Not logged in. Run "ugly-app login" first.');
9
- }
10
- return JSON.parse(fs.readFileSync(authPath, 'utf-8'));
11
- }
12
- function getAppApiUrl() {
13
- return getUglyBotUrl();
14
- }
15
- async function resolveOne(appApiUrl, token, item) {
16
- const res = await fetch(`${appApiUrl}/request`, {
17
- method: 'POST',
18
- headers: {
19
- 'Authorization': `Bearer ${token}`,
20
- 'Content-Type': 'application/json',
21
- },
22
- body: JSON.stringify({
23
- function: 'feedbackReportResolve',
24
- input: {
25
- feedbackReportId: item.id,
26
- status: item.status,
27
- resolution: item.resolution,
28
- },
29
- }),
30
- });
31
- if (!res.ok) {
32
- const body = await res.text().catch(() => '');
33
- throw new Error(`${res.status} ${body}`);
1
+ import { execTelemetryD1 } from './telemetryD1.js';
2
+ /**
3
+ * Update a single feedback report's status + resolution directly in the
4
+ * project's PROD Cloudflare D1 (`feedback_report` table) — the same store the
5
+ * `feedback` read CLI queries. The previous implementation POSTed
6
+ * `{function:'feedbackReportResolve'}` to `ugly.bot/request`, an endpoint that
7
+ * lived on the retired `app` monolith; the live ugly.bot is a billable-op proxy
8
+ * that 400s ("Missing op"), so resolves silently failed for every child app.
9
+ */
10
+ async function resolveOne(item) {
11
+ const { meta } = await execTelemetryD1('UPDATE feedback_report SET status = ?, resolution = ? WHERE id = ?', [item.status, item.resolution, item.id]);
12
+ if (!meta || (meta.changes ?? 0) === 0) {
13
+ throw new Error(`no feedback_report row with id "${item.id}"`);
34
14
  }
35
15
  }
36
16
  export async function resolveFeedback(opts) {
37
- const appApiUrl = getAppApiUrl();
38
- const auth = readAuth();
39
17
  try {
40
- await resolveOne(appApiUrl, auth.token, {
18
+ await resolveOne({
41
19
  id: opts.feedbackId,
42
20
  status: opts.status,
43
21
  resolution: opts.resolution,
@@ -55,13 +33,11 @@ export async function resolveFeedback(opts) {
55
33
  * leave items at `status: new` for a duplicate-process next cycle).
56
34
  */
57
35
  export async function resolveFeedbackBatch(items, onItem) {
58
- const appApiUrl = getAppApiUrl();
59
- const auth = readAuth();
60
36
  const failures = [];
61
37
  let successes = 0;
62
38
  for (const item of items) {
63
39
  try {
64
- await resolveOne(appApiUrl, auth.token, item);
40
+ await resolveOne(item);
65
41
  successes++;
66
42
  onItem?.(item, { ok: true });
67
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"feedbackResolve.js","sourceRoot":"","sources":["../../src/cli/feedbackResolve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feedbackResolve.js","sourceRoot":"","sources":["../../src/cli/feedbackResolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAcnD;;;;;;;GAOG;AACH,KAAK,UAAU,UAAU,CAAC,IAAyB;IACjD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CACpC,oEAAoE,EACpE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,CACxC,CAAC;IACF,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAA4B;IAE5B,IAAI,CAAC;QACH,MAAM,UAAU,CAAC;YACf,EAAE,EAAE,IAAI,CAAC,UAAU;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,+BAAgC,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAA4B,EAC5B,MAGS;IAET,MAAM,QAAQ,GAAoC,EAAE,CAAC;IACrD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACvB,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,KAAK,GAAI,CAAW,CAAC,OAAO,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACtC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,sCAAuC,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,IACE,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAQ,KAA0B,CAAC,EAAE,KAAK,QAAQ;YAClD,OAAQ,KAA8B,CAAC,MAAM,KAAK,QAAQ;YAC1D,OAAQ,KAAkC,CAAC,UAAU,KAAK,QAAQ,EAClE,CAAC;YACD,MAAM,IAAI,KAAK,CACb,iBAAiB,CAAC,qDAAqD,CACxE,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,KAA2D,CAAC;QACtE,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CACb,iBAAiB,CAAC,QAAQ,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC,MAAM,sCAAsC,CACtG,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type ProdNeonLookupOptions } from './prodDb.js';
2
+ export interface D1ExecResult {
3
+ results: Record<string, unknown>[];
4
+ /** D1 result meta — `changes` is the number of rows an UPDATE/DELETE modified. */
5
+ meta: {
6
+ changes?: number;
7
+ rows_written?: number;
8
+ rows_read?: number;
9
+ } | null;
10
+ }
11
+ /**
12
+ * Run a single SQL statement (read OR write) against the project's PRODUCTION
13
+ * Cloudflare D1 telemetry DB (errorLog / feedbackReport / …) via the HTTP API.
14
+ *
15
+ * This is the write-capable twin of the `feedback` / `errors` read path — both
16
+ * hit the same D1 database with the same publish-state-resolved token, so the
17
+ * CLI never has to route feedback mutations through a server endpoint.
18
+ */
19
+ export declare function execTelemetryD1(sql: string, params?: unknown[], opts?: ProdNeonLookupOptions): Promise<D1ExecResult>;
20
+ //# sourceMappingURL=telemetryD1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryD1.d.ts","sourceRoot":"","sources":["../../src/cli/telemetryD1.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACnC,kFAAkF;IAClF,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9E;AAeD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,OAAO,EAAO,EACtB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,YAAY,CAAC,CA2BvB"}
@@ -0,0 +1,41 @@
1
+ import { getSecret } from './publish/secret-storage.js';
2
+ import { resolveProdTelemetryD1, } from './prodDb.js';
3
+ const CLOUDFLARE_API_BASE = 'https://api.cloudflare.com/client/v4';
4
+ /** Resolve the Cloudflare API token for a project's D1 (same lookup the read path uses). */
5
+ async function resolveD1Token(d1) {
6
+ const token = (await getSecret(`cloudflare:token:${d1.projectId}`)) ??
7
+ (await getSecret(`cloudflare:access-token:${d1.projectId}`));
8
+ if (!token) {
9
+ throw new Error(`No Cloudflare token for project "${d1.projectId}". Re-authenticate: \`ugly-app publish\`.`);
10
+ }
11
+ return token;
12
+ }
13
+ /**
14
+ * Run a single SQL statement (read OR write) against the project's PRODUCTION
15
+ * Cloudflare D1 telemetry DB (errorLog / feedbackReport / …) via the HTTP API.
16
+ *
17
+ * This is the write-capable twin of the `feedback` / `errors` read path — both
18
+ * hit the same D1 database with the same publish-state-resolved token, so the
19
+ * CLI never has to route feedback mutations through a server endpoint.
20
+ */
21
+ export async function execTelemetryD1(sql, params = [], opts = {}) {
22
+ const d1 = resolveProdTelemetryD1(opts);
23
+ const token = await resolveD1Token(d1);
24
+ const res = await globalThis.fetch(`${CLOUDFLARE_API_BASE}/accounts/${d1.accountId}/d1/database/${d1.databaseId}/query`, {
25
+ method: 'POST',
26
+ headers: {
27
+ Authorization: `Bearer ${token}`,
28
+ 'Content-Type': 'application/json',
29
+ Accept: 'application/json',
30
+ },
31
+ body: JSON.stringify({ sql, params }),
32
+ });
33
+ if (!res.ok) {
34
+ const body = await res.text().catch(() => '');
35
+ throw new Error(`D1 query failed (${res.status}): ${body.slice(0, 200)}`);
36
+ }
37
+ const payload = (await res.json());
38
+ const first = payload.result?.[0];
39
+ return { results: first?.results ?? [], meta: first?.meta ?? null };
40
+ }
41
+ //# sourceMappingURL=telemetryD1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryD1.js","sourceRoot":"","sources":["../../src/cli/telemetryD1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EACL,sBAAsB,GAGvB,MAAM,aAAa,CAAC;AAErB,MAAM,mBAAmB,GAAG,sCAAsC,CAAC;AAQnE,4FAA4F;AAC5F,KAAK,UAAU,cAAc,CAAC,EAAmB;IAC/C,MAAM,KAAK,GACT,CAAC,MAAM,SAAS,CAAC,oBAAoB,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;QACrD,CAAC,MAAM,SAAS,CAAC,2BAA2B,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,oCAAoC,EAAE,CAAC,SAAS,2CAA2C,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,SAAoB,EAAE,EACtB,OAA8B,EAAE;IAEhC,MAAM,EAAE,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,KAAK,CAChC,GAAG,mBAAmB,aAAa,EAAE,CAAC,SAAS,gBAAgB,EAAE,CAAC,UAAU,QAAQ,EACpF;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,kBAAkB;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;KACtC,CACF,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAKhC,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;AACtE,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.761";
1
+ export declare const CLI_VERSION = "0.1.763";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.761";
2
+ export const CLI_VERSION = "0.1.763";
3
3
  //# sourceMappingURL=version.js.map
@@ -9,7 +9,103 @@ export interface BundledTool {
9
9
  /** Shown in the permission prompt, like mic/camera copy. */
10
10
  description: string;
11
11
  }
12
- export declare const BUNDLED_TOOLS: readonly BundledTool[];
12
+ export declare const BUNDLED_TOOLS: readonly [{
13
+ readonly name: "node";
14
+ readonly category: "toolchain";
15
+ readonly shellTool: true;
16
+ readonly description: "Node.js runtime — runs your project and its build tools.";
17
+ }, {
18
+ readonly name: "git";
19
+ readonly category: "toolchain";
20
+ readonly shellTool: true;
21
+ readonly description: "Git — version control for your project.";
22
+ }, {
23
+ readonly name: "pnpm";
24
+ readonly category: "toolchain";
25
+ readonly shellTool: true;
26
+ readonly description: "pnpm — installs your project’s dependencies.";
27
+ }, {
28
+ readonly name: "uv";
29
+ readonly category: "toolchain";
30
+ readonly shellTool: true;
31
+ readonly description: "uv — fast Python package manager.";
32
+ }, {
33
+ readonly name: "python";
34
+ readonly exe: "python3";
35
+ readonly category: "toolchain";
36
+ readonly shellTool: true;
37
+ readonly description: "Python runtime.";
38
+ }, {
39
+ readonly name: "curl";
40
+ readonly category: "net";
41
+ readonly shellTool: true;
42
+ readonly description: "curl — transfer data to/from a URL (used by shells for downloads).";
43
+ }, {
44
+ readonly name: "gh";
45
+ readonly category: "net";
46
+ readonly description: "GitHub CLI — sign in and manage repositories.";
47
+ }, {
48
+ readonly name: "cloudflared";
49
+ readonly category: "net";
50
+ readonly description: "Cloudflare tunnel — exposes your local preview at a public URL.";
51
+ }, {
52
+ readonly name: "nats";
53
+ readonly category: "net";
54
+ readonly description: "NATS CLI — messaging server tooling.";
55
+ }, {
56
+ readonly name: "postgres";
57
+ readonly category: "data";
58
+ readonly description: "PostgreSQL — local database for your project.";
59
+ }, {
60
+ readonly name: "jq";
61
+ readonly category: "data";
62
+ readonly description: "jq — command-line JSON processor.";
63
+ }, {
64
+ readonly name: "yq";
65
+ readonly category: "data";
66
+ readonly description: "yq — command-line YAML processor.";
67
+ }, {
68
+ readonly name: "pup";
69
+ readonly category: "data";
70
+ readonly description: "pup — command-line HTML parser.";
71
+ }, {
72
+ readonly name: "sqlite3";
73
+ readonly category: "data";
74
+ readonly description: "SQLite — command-line database shell.";
75
+ }, {
76
+ readonly name: "ffmpeg";
77
+ readonly category: "media";
78
+ readonly description: "FFmpeg — audio/video processing.";
79
+ }, {
80
+ readonly name: "imagemagick";
81
+ readonly exe: "magick";
82
+ readonly category: "media";
83
+ readonly description: "ImageMagick — image conversion and editing.";
84
+ }, {
85
+ readonly name: "yt-dlp";
86
+ readonly category: "media";
87
+ readonly description: "yt-dlp — download media from the web.";
88
+ }, {
89
+ readonly name: "pandoc";
90
+ readonly category: "doc";
91
+ readonly description: "Pandoc — document format conversion.";
92
+ }, {
93
+ readonly name: "pdftotext";
94
+ readonly category: "doc";
95
+ readonly description: "pdftotext — extract text from PDFs.";
96
+ }, {
97
+ readonly name: "tesseract";
98
+ readonly category: "doc";
99
+ readonly description: "Tesseract — OCR text from images.";
100
+ }];
101
+ /**
102
+ * The set of tool names an app may request — a real compile-time union derived
103
+ * from the catalog, NOT `string`. Type your request/grant lists as
104
+ * `readonly BundledToolName[]` so a typo or a name that isn't actually a bundled
105
+ * tool (e.g. requesting 'postgress' or a non-catalog name) is a build error
106
+ * instead of a silent no-op on the install side.
107
+ */
108
+ export type BundledToolName = (typeof BUNDLED_TOOLS)[number]['name'];
13
109
  /** Look up a tool descriptor by its request/grant name. */
14
110
  export declare function bundledTool(name: string): BundledTool | undefined;
15
111
  //# sourceMappingURL=bundledTools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundledTools.d.ts","sourceRoot":"","sources":["../../src/native/bundledTools.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IACzD,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EA0B9C,CAAC;AAIH,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE"}
1
+ {"version":3,"file":"bundledTools.d.ts","sourceRoot":"","sources":["../../src/native/bundledTools.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IACzD,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;CACrB;AAKD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BiB,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAIrE,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE"}
@@ -2,7 +2,10 @@
2
2
  // permission system (like mic/camera). This is VOCABULARY ONLY — names and
3
3
  // static metadata. Versions, download sources, install, PATH, and upgrade all
4
4
  // live in the host (ugly-studio); ugly-app never touches a binary.
5
- export const BUNDLED_TOOLS = Object.freeze([
5
+ // `as const satisfies` (not `: readonly BundledTool[]`) so the `name`s stay
6
+ // LITERAL types — that's what lets `BundledToolName` below be a real union the
7
+ // compiler checks requests against, instead of a rubber-stamp `string`.
8
+ export const BUNDLED_TOOLS = [
6
9
  // toolchain — needed on PATH so shells (`bash -lc 'pnpm dev'`) resolve them.
7
10
  { name: 'node', category: 'toolchain', shellTool: true, description: 'Node.js runtime — runs your project and its build tools.' },
8
11
  { name: 'git', category: 'toolchain', shellTool: true, description: 'Git — version control for your project.' },
@@ -28,7 +31,7 @@ export const BUNDLED_TOOLS = Object.freeze([
28
31
  { name: 'pandoc', category: 'doc', description: 'Pandoc — document format conversion.' },
29
32
  { name: 'pdftotext', category: 'doc', description: 'pdftotext — extract text from PDFs.' },
30
33
  { name: 'tesseract', category: 'doc', description: 'Tesseract — OCR text from images.' },
31
- ]);
34
+ ];
32
35
  const BY_NAME = new Map(BUNDLED_TOOLS.map((t) => [t.name, t]));
33
36
  /** Look up a tool descriptor by its request/grant name. */
34
37
  export function bundledTool(name) {
@@ -1 +1 @@
1
- {"version":3,"file":"bundledTools.js","sourceRoot":"","sources":["../../src/native/bundledTools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundledTools.js","sourceRoot":"","sources":["../../src/native/bundledTools.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ export { taskEntryUrl } from './facades/task.js';
20
20
  export { defineTask, taskContext } from './defineTask.js';
21
21
  export type { TaskDefinition, TaskContext } from './defineTask.js';
22
22
  export { MCP_CATALOG } from './mcp-catalog.js';
23
- export { BUNDLED_TOOLS, bundledTool, type BundledTool } from './bundledTools.js';
23
+ export { BUNDLED_TOOLS, bundledTool, type BundledTool, type BundledToolName } from './bundledTools.js';
24
24
  export { createProxyClient, nativeSigner } from './proxyClient.js';
25
25
  export { createProxyHost } from './proxyHost.js';
26
26
  export type { ProxyHost, ProxyHostOpts } from './proxyHost.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,OAAO,EACP,WAAW,EACX,SAAS,EACT,QAAQ,EACR,MAAM,EACN,SAAS,EACT,cAAc,EACd,aAAa,EACb,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGjF,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/D,YAAY,EACV,WAAW,EACX,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,GACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACvI,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnF,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,0EAA0E;AAC1E,wFAAwF;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAUtF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAoB,MAAM,mBAAmB,CAAC;AAEjF,mDAAmD;AACnD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AASjD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvI,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/native/index.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,0EAA0E;AAC1E,wFAAwF;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAUtF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,WAAW,EAA0C,MAAM,mBAAmB,CAAC;AAEvG,mDAAmD;AACnD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AASjD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvI,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.761",
3
+ "version": "0.1.763",
4
4
  "type": "module",
5
5
  "comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
6
6
  "files": [
@@ -0,0 +1,66 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ // The resolve path writes to Cloudflare D1 via execTelemetryD1 — mock it so the
4
+ // unit test asserts the SQL/params contract without hitting the network.
5
+ vi.mock('./telemetryD1.js', () => ({ execTelemetryD1: vi.fn() }));
6
+
7
+ import { execTelemetryD1 } from './telemetryD1.js';
8
+ import {
9
+ parseBatchPayload,
10
+ resolveFeedback,
11
+ resolveFeedbackBatch,
12
+ } from './feedbackResolve.js';
13
+
14
+ const mockExec = vi.mocked(execTelemetryD1);
15
+
16
+ beforeEach(() => {
17
+ mockExec.mockReset();
18
+ });
19
+
20
+ describe('resolveFeedback', () => {
21
+ it('UPDATEs feedback_report with status + resolution keyed by id', async () => {
22
+ mockExec.mockResolvedValue({ results: [], meta: { changes: 1 } });
23
+ await resolveFeedback({ feedbackId: 'fb-1', status: 'resolved', resolution: 'done' });
24
+ expect(mockExec).toHaveBeenCalledTimes(1);
25
+ const [sql, params] = mockExec.mock.calls[0]!;
26
+ expect(sql).toMatch(/UPDATE\s+feedback_report\s+SET\s+status\s*=\s*\?,\s*resolution\s*=\s*\?\s+WHERE\s+id\s*=\s*\?/i);
27
+ expect(params).toEqual(['resolved', 'done', 'fb-1']);
28
+ });
29
+
30
+ it('throws when no row matched the id (changes === 0)', async () => {
31
+ mockExec.mockResolvedValue({ results: [], meta: { changes: 0 } });
32
+ await expect(
33
+ resolveFeedback({ feedbackId: 'missing', status: 'declined', resolution: 'n/a' }),
34
+ ).rejects.toThrow(/no feedback_report row with id "missing"/);
35
+ });
36
+
37
+ it('throws when D1 returns no meta', async () => {
38
+ mockExec.mockResolvedValue({ results: [], meta: null });
39
+ await expect(
40
+ resolveFeedback({ feedbackId: 'x', status: 'resolved', resolution: 'y' }),
41
+ ).rejects.toThrow(/Failed to resolve feedback/);
42
+ });
43
+ });
44
+
45
+ describe('resolveFeedbackBatch', () => {
46
+ it('processes every item and reports partial failures without throwing', async () => {
47
+ mockExec
48
+ .mockResolvedValueOnce({ results: [], meta: { changes: 1 } }) // ok
49
+ .mockResolvedValueOnce({ results: [], meta: { changes: 0 } }); // missing row
50
+ const { successes, failures } = await resolveFeedbackBatch([
51
+ { id: 'a', status: 'resolved', resolution: 'r1' },
52
+ { id: 'b', status: 'resolved', resolution: 'r2' },
53
+ ]);
54
+ expect(successes).toBe(1);
55
+ expect(failures).toHaveLength(1);
56
+ expect(failures[0]!.id).toBe('b');
57
+ });
58
+ });
59
+
60
+ describe('parseBatchPayload', () => {
61
+ it('rejects an invalid status value', () => {
62
+ expect(() =>
63
+ parseBatchPayload(JSON.stringify([{ id: 'a', status: 'nope', resolution: 'x' }])),
64
+ ).toThrow(/invalid status "nope"/);
65
+ });
66
+ });
@@ -1,7 +1,4 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { getUglyBotUrl } from '../shared/uglyBotUrl.js';
1
+ import { execTelemetryD1 } from './telemetryD1.js';
5
2
 
6
3
  export interface FeedbackResolveOptions {
7
4
  feedbackId: string;
@@ -15,60 +12,29 @@ export interface FeedbackResolveItem {
15
12
  resolution: string;
16
13
  }
17
14
 
18
- interface AuthConfig {
19
- token: string;
20
- userId: string;
21
- serverUrl: string;
22
- }
23
-
24
- function readAuth(): AuthConfig {
25
- const authPath = path.join(os.homedir(), '.ugly-bot', 'auth.json');
26
- if (!fs.existsSync(authPath)) {
27
- throw new Error(
28
- 'Not logged in. Run "ugly-app login" first.',
29
- );
30
- }
31
- return JSON.parse(fs.readFileSync(authPath, 'utf-8')) as AuthConfig;
32
- }
33
-
34
- function getAppApiUrl(): string {
35
- return getUglyBotUrl();
36
- }
37
-
38
- async function resolveOne(
39
- appApiUrl: string,
40
- token: string,
41
- item: FeedbackResolveItem,
42
- ): Promise<void> {
43
- const res = await fetch(`${appApiUrl}/request`, {
44
- method: 'POST',
45
- headers: {
46
- 'Authorization': `Bearer ${token}`,
47
- 'Content-Type': 'application/json',
48
- },
49
- body: JSON.stringify({
50
- function: 'feedbackReportResolve',
51
- input: {
52
- feedbackReportId: item.id,
53
- status: item.status,
54
- resolution: item.resolution,
55
- },
56
- }),
57
- });
58
-
59
- if (!res.ok) {
60
- const body = await res.text().catch(() => '');
61
- throw new Error(`${res.status} ${body}`);
15
+ /**
16
+ * Update a single feedback report's status + resolution directly in the
17
+ * project's PROD Cloudflare D1 (`feedback_report` table) — the same store the
18
+ * `feedback` read CLI queries. The previous implementation POSTed
19
+ * `{function:'feedbackReportResolve'}` to `ugly.bot/request`, an endpoint that
20
+ * lived on the retired `app` monolith; the live ugly.bot is a billable-op proxy
21
+ * that 400s ("Missing op"), so resolves silently failed for every child app.
22
+ */
23
+ async function resolveOne(item: FeedbackResolveItem): Promise<void> {
24
+ const { meta } = await execTelemetryD1(
25
+ 'UPDATE feedback_report SET status = ?, resolution = ? WHERE id = ?',
26
+ [item.status, item.resolution, item.id],
27
+ );
28
+ if (!meta || (meta.changes ?? 0) === 0) {
29
+ throw new Error(`no feedback_report row with id "${item.id}"`);
62
30
  }
63
31
  }
64
32
 
65
33
  export async function resolveFeedback(
66
34
  opts: FeedbackResolveOptions,
67
35
  ): Promise<void> {
68
- const appApiUrl = getAppApiUrl();
69
- const auth = readAuth();
70
36
  try {
71
- await resolveOne(appApiUrl, auth.token, {
37
+ await resolveOne({
72
38
  id: opts.feedbackId,
73
39
  status: opts.status,
74
40
  resolution: opts.resolution,
@@ -92,13 +58,11 @@ export async function resolveFeedbackBatch(
92
58
  result: { ok: true } | { ok: false; error: string },
93
59
  ) => void,
94
60
  ): Promise<{ successes: number; failures: { id: string; error: string }[] }> {
95
- const appApiUrl = getAppApiUrl();
96
- const auth = readAuth();
97
61
  const failures: { id: string; error: string }[] = [];
98
62
  let successes = 0;
99
63
  for (const item of items) {
100
64
  try {
101
- await resolveOne(appApiUrl, auth.token, item);
65
+ await resolveOne(item);
102
66
  successes++;
103
67
  onItem?.(item, { ok: true });
104
68
  } catch (e) {
@@ -0,0 +1,68 @@
1
+ import { getSecret } from './publish/secret-storage.js';
2
+ import {
3
+ resolveProdTelemetryD1,
4
+ type ProdNeonLookupOptions,
5
+ type ProdTelemetryD1,
6
+ } from './prodDb.js';
7
+
8
+ const CLOUDFLARE_API_BASE = 'https://api.cloudflare.com/client/v4';
9
+
10
+ export interface D1ExecResult {
11
+ results: Record<string, unknown>[];
12
+ /** D1 result meta — `changes` is the number of rows an UPDATE/DELETE modified. */
13
+ meta: { changes?: number; rows_written?: number; rows_read?: number } | null;
14
+ }
15
+
16
+ /** Resolve the Cloudflare API token for a project's D1 (same lookup the read path uses). */
17
+ async function resolveD1Token(d1: ProdTelemetryD1): Promise<string> {
18
+ const token =
19
+ (await getSecret(`cloudflare:token:${d1.projectId}`)) ??
20
+ (await getSecret(`cloudflare:access-token:${d1.projectId}`));
21
+ if (!token) {
22
+ throw new Error(
23
+ `No Cloudflare token for project "${d1.projectId}". Re-authenticate: \`ugly-app publish\`.`,
24
+ );
25
+ }
26
+ return token;
27
+ }
28
+
29
+ /**
30
+ * Run a single SQL statement (read OR write) against the project's PRODUCTION
31
+ * Cloudflare D1 telemetry DB (errorLog / feedbackReport / …) via the HTTP API.
32
+ *
33
+ * This is the write-capable twin of the `feedback` / `errors` read path — both
34
+ * hit the same D1 database with the same publish-state-resolved token, so the
35
+ * CLI never has to route feedback mutations through a server endpoint.
36
+ */
37
+ export async function execTelemetryD1(
38
+ sql: string,
39
+ params: unknown[] = [],
40
+ opts: ProdNeonLookupOptions = {},
41
+ ): Promise<D1ExecResult> {
42
+ const d1 = resolveProdTelemetryD1(opts);
43
+ const token = await resolveD1Token(d1);
44
+ const res = await globalThis.fetch(
45
+ `${CLOUDFLARE_API_BASE}/accounts/${d1.accountId}/d1/database/${d1.databaseId}/query`,
46
+ {
47
+ method: 'POST',
48
+ headers: {
49
+ Authorization: `Bearer ${token}`,
50
+ 'Content-Type': 'application/json',
51
+ Accept: 'application/json',
52
+ },
53
+ body: JSON.stringify({ sql, params }),
54
+ },
55
+ );
56
+ if (!res.ok) {
57
+ const body = await res.text().catch(() => '');
58
+ throw new Error(`D1 query failed (${res.status}): ${body.slice(0, 200)}`);
59
+ }
60
+ const payload = (await res.json()) as {
61
+ result?: {
62
+ results?: Record<string, unknown>[];
63
+ meta?: D1ExecResult['meta'];
64
+ }[];
65
+ };
66
+ const first = payload.result?.[0];
67
+ return { results: first?.results ?? [], meta: first?.meta ?? null };
68
+ }
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.761";
2
+ export const CLI_VERSION = "0.1.763";
@@ -15,7 +15,10 @@ export interface BundledTool {
15
15
  description: string;
16
16
  }
17
17
 
18
- export const BUNDLED_TOOLS: readonly BundledTool[] = Object.freeze([
18
+ // `as const satisfies` (not `: readonly BundledTool[]`) so the `name`s stay
19
+ // LITERAL types — that's what lets `BundledToolName` below be a real union the
20
+ // compiler checks requests against, instead of a rubber-stamp `string`.
21
+ export const BUNDLED_TOOLS = [
19
22
  // toolchain — needed on PATH so shells (`bash -lc 'pnpm dev'`) resolve them.
20
23
  { name: 'node', category: 'toolchain', shellTool: true, description: 'Node.js runtime — runs your project and its build tools.' },
21
24
  { name: 'git', category: 'toolchain', shellTool: true, description: 'Git — version control for your project.' },
@@ -41,9 +44,18 @@ export const BUNDLED_TOOLS: readonly BundledTool[] = Object.freeze([
41
44
  { name: 'pandoc', category: 'doc', description: 'Pandoc — document format conversion.' },
42
45
  { name: 'pdftotext', category: 'doc', description: 'pdftotext — extract text from PDFs.' },
43
46
  { name: 'tesseract', category: 'doc', description: 'Tesseract — OCR text from images.' },
44
- ]);
47
+ ] as const satisfies readonly BundledTool[];
45
48
 
46
- const BY_NAME = new Map(BUNDLED_TOOLS.map((t) => [t.name, t]));
49
+ /**
50
+ * The set of tool names an app may request — a real compile-time union derived
51
+ * from the catalog, NOT `string`. Type your request/grant lists as
52
+ * `readonly BundledToolName[]` so a typo or a name that isn't actually a bundled
53
+ * tool (e.g. requesting 'postgress' or a non-catalog name) is a build error
54
+ * instead of a silent no-op on the install side.
55
+ */
56
+ export type BundledToolName = (typeof BUNDLED_TOOLS)[number]['name'];
57
+
58
+ const BY_NAME: Map<string, BundledTool> = new Map(BUNDLED_TOOLS.map((t) => [t.name, t]));
47
59
 
48
60
  /** Look up a tool descriptor by its request/grant name. */
49
61
  export function bundledTool(name: string): BundledTool | undefined {
@@ -65,7 +65,7 @@ export { defineTask, taskContext } from './defineTask.js';
65
65
  export type { TaskDefinition, TaskContext } from './defineTask.js';
66
66
  export { MCP_CATALOG } from './mcp-catalog.js';
67
67
 
68
- export { BUNDLED_TOOLS, bundledTool, type BundledTool } from './bundledTools.js';
68
+ export { BUNDLED_TOOLS, bundledTool, type BundledTool, type BundledToolName } from './bundledTools.js';
69
69
 
70
70
  // ── Ugly Proxy (remote UglyNative over WebRTC) ──
71
71
  export { createProxyClient, nativeSigner } from './proxyClient.js';