@runcofactor/cli 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +125 -0
  2. package/dist/api-catalog-GFGCLVS4.js +401 -0
  3. package/dist/api-catalog-GFGCLVS4.js.map +1 -0
  4. package/dist/attachment-SJC7D7FY.js +276 -0
  5. package/dist/attachment-SJC7D7FY.js.map +1 -0
  6. package/dist/auth-EN6NQCJY.js +31 -0
  7. package/dist/auth-EN6NQCJY.js.map +1 -0
  8. package/dist/bin.js +7 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/chunk-3CZU7XCS.js +272 -0
  11. package/dist/chunk-3CZU7XCS.js.map +1 -0
  12. package/dist/chunk-4NRDONSC.js +1048 -0
  13. package/dist/chunk-4NRDONSC.js.map +1 -0
  14. package/dist/chunk-4PNOV7OV.js +51980 -0
  15. package/dist/chunk-4PNOV7OV.js.map +1 -0
  16. package/dist/chunk-52IO7ACJ.js +2941 -0
  17. package/dist/chunk-52IO7ACJ.js.map +1 -0
  18. package/dist/chunk-6LEZCKKV.js +663 -0
  19. package/dist/chunk-6LEZCKKV.js.map +1 -0
  20. package/dist/chunk-A4OFTUVV.js +170 -0
  21. package/dist/chunk-A4OFTUVV.js.map +1 -0
  22. package/dist/chunk-B2VISN2V.js +2459 -0
  23. package/dist/chunk-B2VISN2V.js.map +1 -0
  24. package/dist/chunk-CLAWT7BJ.js +271 -0
  25. package/dist/chunk-CLAWT7BJ.js.map +1 -0
  26. package/dist/chunk-GKY2KXO5.js +281 -0
  27. package/dist/chunk-GKY2KXO5.js.map +1 -0
  28. package/dist/chunk-I4QLI3JO.js +413 -0
  29. package/dist/chunk-I4QLI3JO.js.map +1 -0
  30. package/dist/chunk-IMPZAX6L.js +180 -0
  31. package/dist/chunk-IMPZAX6L.js.map +1 -0
  32. package/dist/chunk-J6SH7GQT.js +241 -0
  33. package/dist/chunk-J6SH7GQT.js.map +1 -0
  34. package/dist/chunk-JDBCZ3Z2.js +298 -0
  35. package/dist/chunk-JDBCZ3Z2.js.map +1 -0
  36. package/dist/chunk-JICSYFRJ.js +46 -0
  37. package/dist/chunk-JICSYFRJ.js.map +1 -0
  38. package/dist/chunk-JWHYXEA2.js +32 -0
  39. package/dist/chunk-JWHYXEA2.js.map +1 -0
  40. package/dist/chunk-N7HFALX3.js +88 -0
  41. package/dist/chunk-N7HFALX3.js.map +1 -0
  42. package/dist/chunk-Q4BO4Z5V.js +178 -0
  43. package/dist/chunk-Q4BO4Z5V.js.map +1 -0
  44. package/dist/chunk-QFDOWABX.js +195 -0
  45. package/dist/chunk-QFDOWABX.js.map +1 -0
  46. package/dist/chunk-SJJW77WN.js +605 -0
  47. package/dist/chunk-SJJW77WN.js.map +1 -0
  48. package/dist/chunk-VKVL7WBN.js +50 -0
  49. package/dist/chunk-VKVL7WBN.js.map +1 -0
  50. package/dist/chunk-WOHL4FTB.js +353 -0
  51. package/dist/chunk-WOHL4FTB.js.map +1 -0
  52. package/dist/chunk-XQXVG7RA.js +426 -0
  53. package/dist/chunk-XQXVG7RA.js.map +1 -0
  54. package/dist/chunk-ZD3KHESI.js +94 -0
  55. package/dist/chunk-ZD3KHESI.js.map +1 -0
  56. package/dist/credential-COLTBV6D.js +450 -0
  57. package/dist/credential-COLTBV6D.js.map +1 -0
  58. package/dist/credential-template-EEPYFG7R.js +291 -0
  59. package/dist/credential-template-EEPYFG7R.js.map +1 -0
  60. package/dist/debug-workflow-KOVH5GOP.js +259 -0
  61. package/dist/debug-workflow-KOVH5GOP.js.map +1 -0
  62. package/dist/dist-44PZR7BQ.js +423 -0
  63. package/dist/dist-44PZR7BQ.js.map +1 -0
  64. package/dist/docs-3SSORHB5.js +366 -0
  65. package/dist/docs-3SSORHB5.js.map +1 -0
  66. package/dist/doctor-OTSIWV6G.js +132 -0
  67. package/dist/doctor-OTSIWV6G.js.map +1 -0
  68. package/dist/feature-flag-T2LRZME3.js +283 -0
  69. package/dist/feature-flag-T2LRZME3.js.map +1 -0
  70. package/dist/file-type-S3UUBVCT.js +4205 -0
  71. package/dist/file-type-S3UUBVCT.js.map +1 -0
  72. package/dist/index.d.ts +3 -0
  73. package/dist/index.js +982 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/init-TGWRECT2.js +208 -0
  76. package/dist/init-TGWRECT2.js.map +1 -0
  77. package/dist/install-DXSNWZKO.js +295 -0
  78. package/dist/install-DXSNWZKO.js.map +1 -0
  79. package/dist/issues-XIZOPX6T.js +564 -0
  80. package/dist/issues-XIZOPX6T.js.map +1 -0
  81. package/dist/knobs-NBINZIUB.js +295 -0
  82. package/dist/knobs-NBINZIUB.js.map +1 -0
  83. package/dist/list-3TDHK637.js +59 -0
  84. package/dist/list-3TDHK637.js.map +1 -0
  85. package/dist/local-HICVD6PU.js +100 -0
  86. package/dist/local-HICVD6PU.js.map +1 -0
  87. package/dist/login-UOIUXVUK.js +315 -0
  88. package/dist/login-UOIUXVUK.js.map +1 -0
  89. package/dist/mcp-54IJEOUA.js +1956 -0
  90. package/dist/mcp-54IJEOUA.js.map +1 -0
  91. package/dist/pdf-extract-ABWV3L5X.js +13 -0
  92. package/dist/pdf-extract-ABWV3L5X.js.map +1 -0
  93. package/dist/pdfjs-DQ2YA5S3.js +41561 -0
  94. package/dist/pdfjs-DQ2YA5S3.js.map +1 -0
  95. package/dist/property-UXLOLPTD.js +701 -0
  96. package/dist/property-UXLOLPTD.js.map +1 -0
  97. package/dist/property-skill-guide.md +189 -0
  98. package/dist/psql-BYUUNLGG.js +115 -0
  99. package/dist/psql-BYUUNLGG.js.map +1 -0
  100. package/dist/record-4TR2UIIS.js +233 -0
  101. package/dist/record-4TR2UIIS.js.map +1 -0
  102. package/dist/redis-35VBUYW7.js +116 -0
  103. package/dist/redis-35VBUYW7.js.map +1 -0
  104. package/dist/release-OOLTUBUT.js +354 -0
  105. package/dist/release-OOLTUBUT.js.map +1 -0
  106. package/dist/sandbox-XGSUU6G7.js +2046 -0
  107. package/dist/sandbox-XGSUU6G7.js.map +1 -0
  108. package/dist/scenarios-GWLJEGHA.js +280 -0
  109. package/dist/scenarios-GWLJEGHA.js.map +1 -0
  110. package/dist/session-MYFNZPRP.js +2414 -0
  111. package/dist/session-MYFNZPRP.js.map +1 -0
  112. package/dist/skill-KM34LDMO.js +1839 -0
  113. package/dist/skill-KM34LDMO.js.map +1 -0
  114. package/dist/skills/debug-run/SKILL.md +262 -0
  115. package/dist/skills/debug-run/history/1.0.0.md +244 -0
  116. package/dist/skills/debug-run/history/1.0.1.md +245 -0
  117. package/dist/skills/debug-run/history/1.0.2.md +254 -0
  118. package/dist/skills/debug-run/history/1.1.0.md +262 -0
  119. package/dist/skills/debug-run/version.json +3 -0
  120. package/dist/spec-RA3CFEKG.js +951 -0
  121. package/dist/spec-RA3CFEKG.js.map +1 -0
  122. package/dist/src-LB4HBTJQ.js +1516 -0
  123. package/dist/src-LB4HBTJQ.js.map +1 -0
  124. package/dist/src-N3TPKGTY.js +244 -0
  125. package/dist/src-N3TPKGTY.js.map +1 -0
  126. package/dist/src-UVDX5UP6.js +17 -0
  127. package/dist/src-UVDX5UP6.js.map +1 -0
  128. package/dist/start-PSEQSQA3.js +151 -0
  129. package/dist/start-PSEQSQA3.js.map +1 -0
  130. package/dist/tag-YY6YAABQ.js +22 -0
  131. package/dist/tag-YY6YAABQ.js.map +1 -0
  132. package/dist/task-IQC3YR5K.js +922 -0
  133. package/dist/task-IQC3YR5K.js.map +1 -0
  134. package/dist/test-suite-DZNJFXDW.js +394 -0
  135. package/dist/test-suite-DZNJFXDW.js.map +1 -0
  136. package/dist/trace-HXIW7U2D.js +14 -0
  137. package/dist/trace-HXIW7U2D.js.map +1 -0
  138. package/dist/triage-ORG45R5W.js +16 -0
  139. package/dist/triage-ORG45R5W.js.map +1 -0
  140. package/dist/upgrade-L2VYMP2V.js +61 -0
  141. package/dist/upgrade-L2VYMP2V.js.map +1 -0
  142. package/dist/workflow-XYFH5LTP.js +3708 -0
  143. package/dist/workflow-XYFH5LTP.js.map +1 -0
  144. package/dist/workflow-cache-NQJQFWMV.js +253 -0
  145. package/dist/workflow-cache-NQJQFWMV.js.map +1 -0
  146. package/dist/workflow-debug-BGD4UIXU.js +927 -0
  147. package/dist/workflow-debug-BGD4UIXU.js.map +1 -0
  148. package/dist/workflow-proposals-MTUDX46O.js +382 -0
  149. package/dist/workflow-proposals-MTUDX46O.js.map +1 -0
  150. package/package.json +61 -0
@@ -0,0 +1,426 @@
1
+ import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
+ import {
3
+ apiRequest
4
+ } from "./chunk-WOHL4FTB.js";
5
+ import {
6
+ getArgValue,
7
+ hasFlag,
8
+ resolveConfig
9
+ } from "./chunk-A4OFTUVV.js";
10
+
11
+ // src/tag.ts
12
+ import process from "process";
13
+ var VALID_COLORS = [
14
+ "red",
15
+ "orange",
16
+ "yellow",
17
+ "green",
18
+ "teal",
19
+ "blue",
20
+ "indigo",
21
+ "purple",
22
+ "pink",
23
+ "gray"
24
+ ];
25
+ var VALID_ENTITY_TYPES = ["issue", "workflow", "attachment"];
26
+ function printTagHelp() {
27
+ console.log(
28
+ [
29
+ "Usage: canary tag <sub-command> [options]",
30
+ "",
31
+ "Sub-commands:",
32
+ " list [--with-stats] [--json] List tags in the org",
33
+ " create --name <name> --color <color> [--description <text>]",
34
+ " Create a new tag",
35
+ " update <id> [--name] [--color] [--description]",
36
+ " Update an existing tag",
37
+ " delete <id> Delete a tag",
38
+ " assign --entity-type <t> --entity-id <id> --tags <id,id,...>",
39
+ " Replace tags on an entity",
40
+ " for --entity-type <t> --entity-id <id> List tags on an entity",
41
+ "",
42
+ "Entity types: " + VALID_ENTITY_TYPES.join(", "),
43
+ "Colors: " + VALID_COLORS.join(", "),
44
+ "",
45
+ "Tag names can also be used directly on workflow create/patch:",
46
+ " canary workflow create --tags smoke,regression ...",
47
+ " canary workflow patch <id> --tags-add flaky",
48
+ "",
49
+ "Common options:",
50
+ " --env <env> Target environment (prod, dev, local)",
51
+ " --api-url <url> API URL override",
52
+ " --token <key> API token override",
53
+ " --json Output raw JSON"
54
+ ].join("\n")
55
+ );
56
+ }
57
+ async function fetchAllTags(apiUrl, token) {
58
+ const result = await apiRequest(apiUrl, token, "GET", "/org/tags");
59
+ if (!result.ok) {
60
+ throw new Error(result.error ?? "Failed to fetch tags");
61
+ }
62
+ return result.data ?? [];
63
+ }
64
+ function levenshtein(a, b) {
65
+ const m = a.length;
66
+ const n = b.length;
67
+ if (m === 0) return n;
68
+ if (n === 0) return m;
69
+ const dp = Array(n + 1).fill(0).map((_, i) => i);
70
+ for (let i = 1; i <= m; i++) {
71
+ let prev = dp[0];
72
+ dp[0] = i;
73
+ for (let j = 1; j <= n; j++) {
74
+ const tmp = dp[j];
75
+ dp[j] = Math.min(
76
+ dp[j] + 1,
77
+ dp[j - 1] + 1,
78
+ prev + (a[i - 1] === b[j - 1] ? 0 : 1)
79
+ );
80
+ prev = tmp;
81
+ }
82
+ }
83
+ return dp[n];
84
+ }
85
+ function resolveTagNames(tags, requested) {
86
+ const byLowerName = new Map(tags.map((t) => [t.name.toLowerCase(), t]));
87
+ const tagIds = [];
88
+ const unknown = [];
89
+ for (const raw of requested) {
90
+ const name = raw.trim();
91
+ if (!name) continue;
92
+ const match = byLowerName.get(name.toLowerCase());
93
+ if (match) {
94
+ tagIds.push(match.id);
95
+ } else {
96
+ unknown.push(name);
97
+ }
98
+ }
99
+ return { tagIds, unknown };
100
+ }
101
+ function formatUnknownTagsError(unknown, tags, exampleWorkflowId) {
102
+ const lines = [];
103
+ for (const name of unknown) {
104
+ lines.push(`Tag "${name}" not found.`);
105
+ const suggestions = tags.map((t) => ({ tag: t, dist: levenshtein(name.toLowerCase(), t.name.toLowerCase()) })).filter((s) => s.dist <= 2).sort((a, b) => a.dist - b.dist).slice(0, 3);
106
+ if (suggestions.length > 0) {
107
+ lines.push("");
108
+ lines.push("Did you mean one of these existing tags?");
109
+ for (const s of suggestions) {
110
+ lines.push(` - ${s.tag.name} (id: ${s.tag.id})`);
111
+ }
112
+ }
113
+ lines.push("");
114
+ }
115
+ lines.push("List all tags: canary tag list");
116
+ lines.push(`Create this tag: canary tag create --name "${unknown[0]}" --color blue`);
117
+ if (exampleWorkflowId) {
118
+ lines.push(
119
+ `Then retry with: canary workflow patch ${exampleWorkflowId} --tags ${unknown.join(",")}`
120
+ );
121
+ }
122
+ return lines.join("\n");
123
+ }
124
+ async function handleList(argv, apiUrl, token) {
125
+ const withStats = hasFlag(argv, "--with-stats");
126
+ const jsonOutput = hasFlag(argv, "--json");
127
+ if (withStats) {
128
+ const result = await apiRequest(apiUrl, token, "GET", "/org/tags/stats");
129
+ if (!result.ok) {
130
+ console.error(`Error: ${result.error}`);
131
+ process.exit(1);
132
+ }
133
+ if (jsonOutput) {
134
+ console.log(JSON.stringify({ data: result.data }, null, 2));
135
+ return;
136
+ }
137
+ if (!result.data || result.data.length === 0) {
138
+ console.log("No tags found.");
139
+ return;
140
+ }
141
+ const idW2 = 36;
142
+ const nameW2 = 24;
143
+ const colorW2 = 8;
144
+ const countW = 6;
145
+ console.log(
146
+ ["ID".padEnd(idW2), "Name".padEnd(nameW2), "Color".padEnd(colorW2), "Uses".padEnd(countW)].join(
147
+ " "
148
+ )
149
+ );
150
+ for (const t of result.data) {
151
+ console.log(
152
+ [
153
+ t.id.padEnd(idW2),
154
+ t.name.padEnd(nameW2),
155
+ t.color.padEnd(colorW2),
156
+ String(t.assignmentCount).padEnd(countW)
157
+ ].join(" ")
158
+ );
159
+ }
160
+ return;
161
+ }
162
+ const tags = await fetchAllTags(apiUrl, token);
163
+ if (jsonOutput) {
164
+ console.log(JSON.stringify({ data: tags }, null, 2));
165
+ return;
166
+ }
167
+ if (tags.length === 0) {
168
+ console.log("No tags found.");
169
+ return;
170
+ }
171
+ const idW = 36;
172
+ const nameW = 24;
173
+ const colorW = 8;
174
+ console.log(["ID".padEnd(idW), "Name".padEnd(nameW), "Color".padEnd(colorW)].join(" "));
175
+ for (const t of tags) {
176
+ console.log([t.id.padEnd(idW), t.name.padEnd(nameW), t.color.padEnd(colorW)].join(" "));
177
+ }
178
+ }
179
+ async function handleCreate(argv, apiUrl, token) {
180
+ const name = getArgValue(argv, "--name");
181
+ const color = getArgValue(argv, "--color");
182
+ const description = getArgValue(argv, "--description");
183
+ const jsonOutput = hasFlag(argv, "--json");
184
+ if (!name) {
185
+ console.error("Error: --name is required.");
186
+ process.exit(1);
187
+ }
188
+ if (!color) {
189
+ console.error(`Error: --color is required. Options: ${VALID_COLORS.join(", ")}`);
190
+ process.exit(1);
191
+ }
192
+ if (!VALID_COLORS.includes(color)) {
193
+ console.error(`Error: invalid color "${color}". Must be one of: ${VALID_COLORS.join(", ")}`);
194
+ process.exit(1);
195
+ }
196
+ const body = { name, color };
197
+ if (description) body.description = description;
198
+ const result = await apiRequest(apiUrl, token, "POST", "/org/tags", body);
199
+ if (!result.ok || !result.tag) {
200
+ console.error(`Error: ${result.error ?? "create failed"}`);
201
+ process.exit(1);
202
+ }
203
+ if (jsonOutput) {
204
+ console.log(JSON.stringify(result.tag, null, 2));
205
+ return;
206
+ }
207
+ console.log(`\u2713 Created tag "${result.tag.name}"`);
208
+ console.log(` ID: ${result.tag.id}`);
209
+ console.log(` Color: ${result.tag.color}`);
210
+ }
211
+ async function handleUpdate(argv, apiUrl, token) {
212
+ const id = argv.find((a) => !a.startsWith("-"));
213
+ if (!id) {
214
+ console.error("Error: missing tag ID. Usage: canary tag update <id> [--name] [--color] [--description]");
215
+ process.exit(1);
216
+ }
217
+ const name = getArgValue(argv, "--name");
218
+ const color = getArgValue(argv, "--color");
219
+ const description = getArgValue(argv, "--description");
220
+ const jsonOutput = hasFlag(argv, "--json");
221
+ if (!name && !color && description === void 0) {
222
+ console.error("Error: provide at least one of: --name, --color, --description");
223
+ process.exit(1);
224
+ }
225
+ if (color && !VALID_COLORS.includes(color)) {
226
+ console.error(`Error: invalid color "${color}". Must be one of: ${VALID_COLORS.join(", ")}`);
227
+ process.exit(1);
228
+ }
229
+ const body = {};
230
+ if (name) body.name = name;
231
+ if (color) body.color = color;
232
+ if (description !== void 0) body.description = description;
233
+ const result = await apiRequest(apiUrl, token, "PUT", `/org/tags/${id}`, body);
234
+ if (!result.ok || !result.tag) {
235
+ console.error(`Error: ${result.error ?? "update failed"}`);
236
+ process.exit(1);
237
+ }
238
+ if (jsonOutput) {
239
+ console.log(JSON.stringify(result.tag, null, 2));
240
+ return;
241
+ }
242
+ console.log(`\u2713 Updated tag ${result.tag.id}`);
243
+ }
244
+ async function handleDelete(argv, apiUrl, token) {
245
+ const id = argv.find((a) => !a.startsWith("-"));
246
+ if (!id) {
247
+ console.error("Error: missing tag ID.");
248
+ process.exit(1);
249
+ }
250
+ const jsonOutput = hasFlag(argv, "--json");
251
+ const result = await apiRequest(apiUrl, token, "DELETE", `/org/tags/${id}`);
252
+ if (!result.ok) {
253
+ console.error(`Error: ${result.error ?? "delete failed"}`);
254
+ process.exit(1);
255
+ }
256
+ if (jsonOutput) {
257
+ console.log(JSON.stringify({ ok: true, id }, null, 2));
258
+ return;
259
+ }
260
+ console.log(`\u2713 Deleted tag ${id}`);
261
+ }
262
+ function parseEntityType(raw) {
263
+ if (!raw || !VALID_ENTITY_TYPES.includes(raw)) {
264
+ console.error(
265
+ `Error: --entity-type required, must be one of: ${VALID_ENTITY_TYPES.join(", ")}`
266
+ );
267
+ process.exit(1);
268
+ }
269
+ return raw;
270
+ }
271
+ async function handleAssign(argv, apiUrl, token) {
272
+ const entityType = parseEntityType(getArgValue(argv, "--entity-type"));
273
+ const entityId = getArgValue(argv, "--entity-id");
274
+ const tagsArg = getArgValue(argv, "--tags");
275
+ const jsonOutput = hasFlag(argv, "--json");
276
+ if (!entityId) {
277
+ console.error("Error: --entity-id is required.");
278
+ process.exit(1);
279
+ }
280
+ if (!tagsArg) {
281
+ console.error("Error: --tags is required (comma-separated tag IDs, or use `canary tag for` to inspect current tags).");
282
+ process.exit(1);
283
+ }
284
+ const tagIds = tagsArg.split(",").map((s) => s.trim()).filter(Boolean);
285
+ const result = await apiRequest(apiUrl, token, "PUT", "/org/tags/entity", {
286
+ entityType,
287
+ entityId,
288
+ tagIds
289
+ });
290
+ if (!result.ok) {
291
+ console.error(`Error: ${result.error ?? "assign failed"}`);
292
+ process.exit(1);
293
+ }
294
+ if (jsonOutput) {
295
+ console.log(JSON.stringify({ ok: true, entityType, entityId, tagIds }, null, 2));
296
+ return;
297
+ }
298
+ console.log(`\u2713 Set ${tagIds.length} tag(s) on ${entityType} ${entityId}`);
299
+ }
300
+ async function handleFor(argv, apiUrl, token) {
301
+ const entityType = parseEntityType(getArgValue(argv, "--entity-type"));
302
+ const entityId = getArgValue(argv, "--entity-id");
303
+ const jsonOutput = hasFlag(argv, "--json");
304
+ if (!entityId) {
305
+ console.error("Error: --entity-id is required.");
306
+ process.exit(1);
307
+ }
308
+ const result = await apiRequest(
309
+ apiUrl,
310
+ token,
311
+ "GET",
312
+ `/org/tags/entity/${entityType}/${entityId}`
313
+ );
314
+ if (!result.ok) {
315
+ console.error(`Error: ${result.error}`);
316
+ process.exit(1);
317
+ }
318
+ if (jsonOutput) {
319
+ console.log(JSON.stringify({ data: result.data }, null, 2));
320
+ return;
321
+ }
322
+ if (!result.data || result.data.length === 0) {
323
+ console.log("(no tags)");
324
+ return;
325
+ }
326
+ for (const t of result.data) {
327
+ console.log(` ${t.id} ${t.name} [${t.color}]`);
328
+ }
329
+ }
330
+ async function applyWorkflowTagFlags(opts) {
331
+ const { apiUrl, token, argv, workflowId } = opts;
332
+ const replace = getArgValue(argv, "--tags");
333
+ const add = getArgValue(argv, "--tags-add");
334
+ const remove = getArgValue(argv, "--tags-remove");
335
+ const rawIds = getArgValue(argv, "--tag-id");
336
+ if (!replace && !add && !remove && !rawIds) return null;
337
+ if (replace && (add || remove)) {
338
+ throw new Error("--tags cannot be combined with --tags-add or --tags-remove");
339
+ }
340
+ const splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : [];
341
+ const replaceNames = splitCsv(replace);
342
+ const addNames = splitCsv(add);
343
+ const removeNames = splitCsv(remove);
344
+ const extraIds = splitCsv(rawIds);
345
+ const allNames = [...replaceNames, ...addNames, ...removeNames];
346
+ const allTags = allNames.length > 0 ? await fetchAllTags(apiUrl, token) : [];
347
+ const resolveOrThrow = (names) => {
348
+ if (names.length === 0) return [];
349
+ const { tagIds, unknown } = resolveTagNames(allTags, names);
350
+ if (unknown.length > 0) {
351
+ throw new Error(formatUnknownTagsError(unknown, allTags, workflowId));
352
+ }
353
+ return tagIds;
354
+ };
355
+ let finalIds;
356
+ if (replace !== void 0) {
357
+ finalIds = [...resolveOrThrow(replaceNames), ...extraIds];
358
+ } else {
359
+ const currentRes = await apiRequest(
360
+ apiUrl,
361
+ token,
362
+ "GET",
363
+ `/org/tags/entity/workflow/${workflowId}`
364
+ );
365
+ if (!currentRes.ok) {
366
+ throw new Error(currentRes.error ?? "failed to read current tags");
367
+ }
368
+ const current = new Set((currentRes.data ?? []).map((t) => t.id));
369
+ for (const id of resolveOrThrow(addNames)) current.add(id);
370
+ for (const id of extraIds) current.add(id);
371
+ const removeIds = new Set(resolveOrThrow(removeNames));
372
+ for (const id of removeIds) current.delete(id);
373
+ finalIds = Array.from(current);
374
+ }
375
+ const uniq = Array.from(new Set(finalIds));
376
+ const result = await apiRequest(apiUrl, token, "PUT", "/org/tags/entity", {
377
+ entityType: "workflow",
378
+ entityId: workflowId,
379
+ tagIds: uniq
380
+ });
381
+ if (!result.ok) {
382
+ throw new Error(result.error ?? "failed to assign tags");
383
+ }
384
+ return { applied: true, tagIds: uniq };
385
+ }
386
+ async function runTag(argv) {
387
+ const [subCommand, ...rest] = argv;
388
+ if (!subCommand || subCommand === "help" || hasFlag(argv, "--help", "-h")) {
389
+ printTagHelp();
390
+ return;
391
+ }
392
+ const { apiUrl, token } = await resolveConfig(rest);
393
+ switch (subCommand) {
394
+ case "list":
395
+ await handleList(rest, apiUrl, token);
396
+ return;
397
+ case "create":
398
+ await handleCreate(rest, apiUrl, token);
399
+ return;
400
+ case "update":
401
+ await handleUpdate(rest, apiUrl, token);
402
+ return;
403
+ case "delete":
404
+ await handleDelete(rest, apiUrl, token);
405
+ return;
406
+ case "assign":
407
+ await handleAssign(rest, apiUrl, token);
408
+ return;
409
+ case "for":
410
+ await handleFor(rest, apiUrl, token);
411
+ return;
412
+ default:
413
+ console.error(`Unknown tag sub-command: ${subCommand}`);
414
+ printTagHelp();
415
+ process.exit(1);
416
+ }
417
+ }
418
+
419
+ export {
420
+ fetchAllTags,
421
+ resolveTagNames,
422
+ formatUnknownTagsError,
423
+ applyWorkflowTagFlags,
424
+ runTag
425
+ };
426
+ //# sourceMappingURL=chunk-XQXVG7RA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tag.ts"],"sourcesContent":["/**\n * CLI Tag Commands\n *\n * List, create, update, delete, and assign org-scoped tags.\n *\n * @module tag\n */\n\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\n\nexport type TagColor =\n | 'red'\n | 'orange'\n | 'yellow'\n | 'green'\n | 'teal'\n | 'blue'\n | 'indigo'\n | 'purple'\n | 'pink'\n | 'gray';\n\nconst VALID_COLORS: TagColor[] = [\n 'red',\n 'orange',\n 'yellow',\n 'green',\n 'teal',\n 'blue',\n 'indigo',\n 'purple',\n 'pink',\n 'gray',\n];\n\nconst VALID_ENTITY_TYPES = ['issue', 'workflow', 'attachment'] as const;\nexport type TagEntityType = (typeof VALID_ENTITY_TYPES)[number];\n\nexport type Tag = {\n id: string;\n name: string;\n color: TagColor;\n description: string | null;\n};\n\ntype ListResponse = { ok: boolean; error?: string; data: Tag[] };\ntype StatsResponse = {\n ok: boolean;\n error?: string;\n data: Array<Tag & { assignmentCount: number }>;\n};\ntype MutateResponse = { ok: boolean; error?: string; tag?: Tag };\ntype OkResponse = { ok: boolean; error?: string };\n\nfunction printTagHelp(): void {\n console.log(\n [\n 'Usage: canary tag <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list [--with-stats] [--json] List tags in the org',\n ' create --name <name> --color <color> [--description <text>]',\n ' Create a new tag',\n ' update <id> [--name] [--color] [--description]',\n ' Update an existing tag',\n ' delete <id> Delete a tag',\n ' assign --entity-type <t> --entity-id <id> --tags <id,id,...>',\n ' Replace tags on an entity',\n ' for --entity-type <t> --entity-id <id> List tags on an entity',\n '',\n 'Entity types: ' + VALID_ENTITY_TYPES.join(', '),\n 'Colors: ' + VALID_COLORS.join(', '),\n '',\n 'Tag names can also be used directly on workflow create/patch:',\n ' canary workflow create --tags smoke,regression ...',\n ' canary workflow patch <id> --tags-add flaky',\n '',\n 'Common options:',\n ' --env <env> Target environment (prod, dev, local)',\n ' --api-url <url> API URL override',\n ' --token <key> API token override',\n ' --json Output raw JSON',\n ].join('\\n')\n );\n}\n\nexport async function fetchAllTags(apiUrl: string, token: string): Promise<Tag[]> {\n const result = await apiRequest<ListResponse>(apiUrl, token, 'GET', '/org/tags');\n if (!result.ok) {\n throw new Error(result.error ?? 'Failed to fetch tags');\n }\n return result.data ?? [];\n}\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n if (m === 0) return n;\n if (n === 0) return m;\n const dp: number[] = Array(n + 1)\n .fill(0)\n .map((_, i) => i);\n for (let i = 1; i <= m; i++) {\n let prev = dp[0];\n dp[0] = i;\n for (let j = 1; j <= n; j++) {\n const tmp = dp[j];\n dp[j] = Math.min(\n dp[j] + 1,\n dp[j - 1] + 1,\n prev + (a[i - 1] === b[j - 1] ? 0 : 1)\n );\n prev = tmp;\n }\n }\n return dp[n];\n}\n\n/**\n * Resolve a comma-separated list of tag names to IDs. Throws with an actionable\n * error (including \"did you mean\" suggestions) if any name is unknown.\n */\nexport function resolveTagNames(\n tags: Tag[],\n requested: string[]\n): { tagIds: string[]; unknown: string[] } {\n const byLowerName = new Map(tags.map((t) => [t.name.toLowerCase(), t]));\n const tagIds: string[] = [];\n const unknown: string[] = [];\n for (const raw of requested) {\n const name = raw.trim();\n if (!name) continue;\n const match = byLowerName.get(name.toLowerCase());\n if (match) {\n tagIds.push(match.id);\n } else {\n unknown.push(name);\n }\n }\n return { tagIds, unknown };\n}\n\nexport function formatUnknownTagsError(\n unknown: string[],\n tags: Tag[],\n exampleWorkflowId?: string\n): string {\n const lines: string[] = [];\n for (const name of unknown) {\n lines.push(`Tag \"${name}\" not found.`);\n const suggestions = tags\n .map((t) => ({ tag: t, dist: levenshtein(name.toLowerCase(), t.name.toLowerCase()) }))\n .filter((s) => s.dist <= 2)\n .sort((a, b) => a.dist - b.dist)\n .slice(0, 3);\n if (suggestions.length > 0) {\n lines.push('');\n lines.push('Did you mean one of these existing tags?');\n for (const s of suggestions) {\n lines.push(` - ${s.tag.name} (id: ${s.tag.id})`);\n }\n }\n lines.push('');\n }\n lines.push('List all tags: canary tag list');\n lines.push(`Create this tag: canary tag create --name \"${unknown[0]}\" --color blue`);\n if (exampleWorkflowId) {\n lines.push(\n `Then retry with: canary workflow patch ${exampleWorkflowId} --tags ${unknown.join(',')}`\n );\n }\n return lines.join('\\n');\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const withStats = hasFlag(argv, '--with-stats');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (withStats) {\n const result = await apiRequest<StatsResponse>(apiUrl, token, 'GET', '/org/tags/stats');\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n if (jsonOutput) {\n console.log(JSON.stringify({ data: result.data }, null, 2));\n return;\n }\n if (!result.data || result.data.length === 0) {\n console.log('No tags found.');\n return;\n }\n const idW = 36;\n const nameW = 24;\n const colorW = 8;\n const countW = 6;\n console.log(\n ['ID'.padEnd(idW), 'Name'.padEnd(nameW), 'Color'.padEnd(colorW), 'Uses'.padEnd(countW)].join(\n ' '\n )\n );\n for (const t of result.data) {\n console.log(\n [\n t.id.padEnd(idW),\n t.name.padEnd(nameW),\n t.color.padEnd(colorW),\n String(t.assignmentCount).padEnd(countW),\n ].join(' ')\n );\n }\n return;\n }\n\n const tags = await fetchAllTags(apiUrl, token);\n if (jsonOutput) {\n console.log(JSON.stringify({ data: tags }, null, 2));\n return;\n }\n if (tags.length === 0) {\n console.log('No tags found.');\n return;\n }\n const idW = 36;\n const nameW = 24;\n const colorW = 8;\n console.log(['ID'.padEnd(idW), 'Name'.padEnd(nameW), 'Color'.padEnd(colorW)].join(' '));\n for (const t of tags) {\n console.log([t.id.padEnd(idW), t.name.padEnd(nameW), t.color.padEnd(colorW)].join(' '));\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = getArgValue(argv, '--name');\n const color = getArgValue(argv, '--color') as TagColor | undefined;\n const description = getArgValue(argv, '--description');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!name) {\n console.error('Error: --name is required.');\n process.exit(1);\n }\n if (!color) {\n console.error(`Error: --color is required. Options: ${VALID_COLORS.join(', ')}`);\n process.exit(1);\n }\n if (!VALID_COLORS.includes(color)) {\n console.error(`Error: invalid color \"${color}\". Must be one of: ${VALID_COLORS.join(', ')}`);\n process.exit(1);\n }\n\n const body: Record<string, unknown> = { name, color };\n if (description) body.description = description;\n\n const result = await apiRequest<MutateResponse>(apiUrl, token, 'POST', '/org/tags', body);\n if (!result.ok || !result.tag) {\n console.error(`Error: ${result.error ?? 'create failed'}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result.tag, null, 2));\n return;\n }\n console.log(`\\u2713 Created tag \"${result.tag.name}\"`);\n console.log(` ID: ${result.tag.id}`);\n console.log(` Color: ${result.tag.color}`);\n}\n\nasync function handleUpdate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const id = argv.find((a) => !a.startsWith('-'));\n if (!id) {\n console.error('Error: missing tag ID. Usage: canary tag update <id> [--name] [--color] [--description]');\n process.exit(1);\n }\n\n const name = getArgValue(argv, '--name');\n const color = getArgValue(argv, '--color') as TagColor | undefined;\n const description = getArgValue(argv, '--description');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!name && !color && description === undefined) {\n console.error('Error: provide at least one of: --name, --color, --description');\n process.exit(1);\n }\n if (color && !VALID_COLORS.includes(color)) {\n console.error(`Error: invalid color \"${color}\". Must be one of: ${VALID_COLORS.join(', ')}`);\n process.exit(1);\n }\n\n const body: Record<string, unknown> = {};\n if (name) body.name = name;\n if (color) body.color = color;\n if (description !== undefined) body.description = description;\n\n const result = await apiRequest<MutateResponse>(apiUrl, token, 'PUT', `/org/tags/${id}`, body);\n if (!result.ok || !result.tag) {\n console.error(`Error: ${result.error ?? 'update failed'}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result.tag, null, 2));\n return;\n }\n console.log(`\\u2713 Updated tag ${result.tag.id}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const id = argv.find((a) => !a.startsWith('-'));\n if (!id) {\n console.error('Error: missing tag ID.');\n process.exit(1);\n }\n const jsonOutput = hasFlag(argv, '--json');\n\n const result = await apiRequest<OkResponse>(apiUrl, token, 'DELETE', `/org/tags/${id}`);\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'delete failed'}`);\n process.exit(1);\n }\n if (jsonOutput) {\n console.log(JSON.stringify({ ok: true, id }, null, 2));\n return;\n }\n console.log(`\\u2713 Deleted tag ${id}`);\n}\n\nfunction parseEntityType(raw: string | undefined): TagEntityType {\n if (!raw || !VALID_ENTITY_TYPES.includes(raw as TagEntityType)) {\n console.error(\n `Error: --entity-type required, must be one of: ${VALID_ENTITY_TYPES.join(', ')}`\n );\n process.exit(1);\n }\n return raw as TagEntityType;\n}\n\nasync function handleAssign(argv: string[], apiUrl: string, token: string): Promise<void> {\n const entityType = parseEntityType(getArgValue(argv, '--entity-type'));\n const entityId = getArgValue(argv, '--entity-id');\n const tagsArg = getArgValue(argv, '--tags');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!entityId) {\n console.error('Error: --entity-id is required.');\n process.exit(1);\n }\n if (!tagsArg) {\n console.error('Error: --tags is required (comma-separated tag IDs, or use `canary tag for` to inspect current tags).');\n process.exit(1);\n }\n\n const tagIds = tagsArg.split(',').map((s) => s.trim()).filter(Boolean);\n\n const result = await apiRequest<OkResponse>(apiUrl, token, 'PUT', '/org/tags/entity', {\n entityType,\n entityId,\n tagIds,\n });\n if (!result.ok) {\n console.error(`Error: ${result.error ?? 'assign failed'}`);\n process.exit(1);\n }\n if (jsonOutput) {\n console.log(JSON.stringify({ ok: true, entityType, entityId, tagIds }, null, 2));\n return;\n }\n console.log(`\\u2713 Set ${tagIds.length} tag(s) on ${entityType} ${entityId}`);\n}\n\nasync function handleFor(argv: string[], apiUrl: string, token: string): Promise<void> {\n const entityType = parseEntityType(getArgValue(argv, '--entity-type'));\n const entityId = getArgValue(argv, '--entity-id');\n const jsonOutput = hasFlag(argv, '--json');\n\n if (!entityId) {\n console.error('Error: --entity-id is required.');\n process.exit(1);\n }\n\n const result = await apiRequest<ListResponse>(\n apiUrl,\n token,\n 'GET',\n `/org/tags/entity/${entityType}/${entityId}`\n );\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n if (jsonOutput) {\n console.log(JSON.stringify({ data: result.data }, null, 2));\n return;\n }\n if (!result.data || result.data.length === 0) {\n console.log('(no tags)');\n return;\n }\n for (const t of result.data) {\n console.log(` ${t.id} ${t.name} [${t.color}]`);\n }\n}\n\n/**\n * Apply --tags / --tags-add / --tags-remove / --tag-id flags to a workflow.\n *\n * --tags Replace the workflow's tag set with the given names.\n * --tags-add Merge these names into the existing set.\n * --tags-remove Remove these names from the existing set.\n * --tag-id Raw tag IDs (comma-separated), bypasses name resolution.\n *\n * --tags and (--tags-add | --tags-remove | --tag-id) are mutually exclusive.\n * Throws on unknown names with a helpful \"did you mean\" message before any\n * mutation occurs.\n */\nexport async function applyWorkflowTagFlags(opts: {\n apiUrl: string;\n token: string;\n argv: string[];\n workflowId: string;\n}): Promise<{ applied: boolean; tagIds: string[] } | null> {\n const { apiUrl, token, argv, workflowId } = opts;\n\n const replace = getArgValue(argv, '--tags');\n const add = getArgValue(argv, '--tags-add');\n const remove = getArgValue(argv, '--tags-remove');\n const rawIds = getArgValue(argv, '--tag-id');\n\n if (!replace && !add && !remove && !rawIds) return null;\n\n if (replace && (add || remove)) {\n throw new Error('--tags cannot be combined with --tags-add or --tags-remove');\n }\n\n const splitCsv = (s: string | undefined) =>\n s ? s.split(',').map((x) => x.trim()).filter(Boolean) : [];\n\n const replaceNames = splitCsv(replace);\n const addNames = splitCsv(add);\n const removeNames = splitCsv(remove);\n const extraIds = splitCsv(rawIds);\n\n const allNames = [...replaceNames, ...addNames, ...removeNames];\n const allTags = allNames.length > 0 ? await fetchAllTags(apiUrl, token) : [];\n\n const resolveOrThrow = (names: string[]): string[] => {\n if (names.length === 0) return [];\n const { tagIds, unknown } = resolveTagNames(allTags, names);\n if (unknown.length > 0) {\n throw new Error(formatUnknownTagsError(unknown, allTags, workflowId));\n }\n return tagIds;\n };\n\n let finalIds: string[];\n\n if (replace !== undefined) {\n finalIds = [...resolveOrThrow(replaceNames), ...extraIds];\n } else {\n // add/remove: merge with current tags\n const currentRes = await apiRequest<ListResponse>(\n apiUrl,\n token,\n 'GET',\n `/org/tags/entity/workflow/${workflowId}`\n );\n if (!currentRes.ok) {\n throw new Error(currentRes.error ?? 'failed to read current tags');\n }\n const current = new Set((currentRes.data ?? []).map((t) => t.id));\n for (const id of resolveOrThrow(addNames)) current.add(id);\n for (const id of extraIds) current.add(id);\n const removeIds = new Set(resolveOrThrow(removeNames));\n for (const id of removeIds) current.delete(id);\n finalIds = Array.from(current);\n }\n\n // De-dupe while preserving order\n const uniq = Array.from(new Set(finalIds));\n\n const result = await apiRequest<OkResponse>(apiUrl, token, 'PUT', '/org/tags/entity', {\n entityType: 'workflow',\n entityId: workflowId,\n tagIds: uniq,\n });\n if (!result.ok) {\n throw new Error(result.error ?? 'failed to assign tags');\n }\n return { applied: true, tagIds: uniq };\n}\n\nexport async function runTag(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printTagHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(rest);\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token);\n return;\n case 'create':\n await handleCreate(rest, apiUrl, token);\n return;\n case 'update':\n await handleUpdate(rest, apiUrl, token);\n return;\n case 'delete':\n await handleDelete(rest, apiUrl, token);\n return;\n case 'assign':\n await handleAssign(rest, apiUrl, token);\n return;\n case 'for':\n await handleFor(rest, apiUrl, token);\n return;\n default:\n console.error(`Unknown tag sub-command: ${subCommand}`);\n printTagHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["idW","nameW","colorW"]}
@@ -0,0 +1,94 @@
1
+ import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
+
3
+ // ../browser-core/src/pdf-extract.ts
4
+ import * as fs from "fs/promises";
5
+
6
+ // ../browser-core/src/logger.ts
7
+ var consoleLogger = {
8
+ debug: (msg, data) => {
9
+ if (data) console.debug(msg, data);
10
+ else console.debug(msg);
11
+ },
12
+ info: (msg, data) => {
13
+ if (data) console.info(msg, data);
14
+ else console.info(msg);
15
+ },
16
+ warn: (msg, data) => {
17
+ if (data) console.warn(msg, data);
18
+ else console.warn(msg);
19
+ },
20
+ error: (msg, data) => {
21
+ if (data) console.error(msg, data);
22
+ else console.error(msg);
23
+ }
24
+ };
25
+
26
+ // ../browser-core/src/pdf-extract.ts
27
+ var _logger = consoleLogger;
28
+ function setPdfExtractLogger(l) {
29
+ _logger = l;
30
+ }
31
+ var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
32
+ var MAX_OUTPUT_CHARS = 1e5;
33
+ async function extractPdfTextFromBuffer(buffer) {
34
+ if (buffer.length > MAX_FILE_SIZE_BYTES) {
35
+ _logger.warn("[PdfExtract] PDF too large for text extraction", {
36
+ sizeBytes: buffer.length,
37
+ maxBytes: MAX_FILE_SIZE_BYTES
38
+ });
39
+ return {
40
+ text: `[PDF too large for text extraction: ${formatBytes(buffer.length)} exceeds ${formatBytes(MAX_FILE_SIZE_BYTES)} limit]`,
41
+ totalPages: 0
42
+ };
43
+ }
44
+ const { extractText } = await import("./dist-44PZR7BQ.js");
45
+ const uint8 = new Uint8Array(buffer);
46
+ const result = await extractText(uint8, { mergePages: true });
47
+ let text = result.text ?? "";
48
+ const totalPages = result.totalPages ?? 0;
49
+ if (text.length > MAX_OUTPUT_CHARS) {
50
+ _logger.info("[PdfExtract] Truncating extracted text", {
51
+ originalLength: text.length,
52
+ truncatedTo: MAX_OUTPUT_CHARS,
53
+ totalPages
54
+ });
55
+ text = text.slice(0, MAX_OUTPUT_CHARS) + `
56
+
57
+ [Text truncated at ${MAX_OUTPUT_CHARS} characters]`;
58
+ }
59
+ _logger.info("[PdfExtract] Text extracted successfully", {
60
+ textLength: text.length,
61
+ totalPages,
62
+ sizeBytes: buffer.length
63
+ });
64
+ return { text, totalPages };
65
+ }
66
+ async function extractPdfText(filePath) {
67
+ const stat2 = await fs.stat(filePath);
68
+ if (stat2.size > MAX_FILE_SIZE_BYTES) {
69
+ _logger.warn("[PdfExtract] PDF file too large for text extraction", {
70
+ filePath,
71
+ sizeBytes: stat2.size,
72
+ maxBytes: MAX_FILE_SIZE_BYTES
73
+ });
74
+ return {
75
+ text: `[PDF too large for text extraction: ${formatBytes(stat2.size)} exceeds ${formatBytes(MAX_FILE_SIZE_BYTES)} limit]`,
76
+ totalPages: 0
77
+ };
78
+ }
79
+ const buffer = await fs.readFile(filePath);
80
+ return extractPdfTextFromBuffer(Buffer.from(buffer));
81
+ }
82
+ function formatBytes(bytes) {
83
+ if (bytes < 1024) return `${bytes}B`;
84
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
85
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
86
+ }
87
+
88
+ export {
89
+ consoleLogger,
90
+ setPdfExtractLogger,
91
+ extractPdfTextFromBuffer,
92
+ extractPdfText
93
+ };
94
+ //# sourceMappingURL=chunk-ZD3KHESI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../browser-core/src/pdf-extract.ts","../../browser-core/src/logger.ts"],"sourcesContent":["/**\n * PDF text extraction utility.\n *\n * Uses `unpdf` to extract text content from PDF files and buffers.\n * Includes size guards to prevent excessive memory usage.\n *\n * @module pdf-extract\n */\n\nimport * as fs from 'fs/promises';\nimport { consoleLogger, type BrowserLogger } from './logger.js';\n\nlet _logger: BrowserLogger = consoleLogger;\n\nexport function setPdfExtractLogger(l: BrowserLogger): void {\n _logger = l;\n}\n\nconst MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB\nconst MAX_OUTPUT_CHARS = 100_000;\n\n/**\n * Extract text content from a PDF buffer.\n * Returns the extracted text and total page count.\n */\nexport async function extractPdfTextFromBuffer(\n buffer: Buffer\n): Promise<{ text: string; totalPages: number }> {\n if (buffer.length > MAX_FILE_SIZE_BYTES) {\n _logger.warn('[PdfExtract] PDF too large for text extraction', {\n sizeBytes: buffer.length,\n maxBytes: MAX_FILE_SIZE_BYTES,\n });\n return {\n text: `[PDF too large for text extraction: ${formatBytes(buffer.length)} exceeds ${formatBytes(MAX_FILE_SIZE_BYTES)} limit]`,\n totalPages: 0,\n };\n }\n\n const { extractText } = await import('unpdf');\n const uint8 = new Uint8Array(buffer);\n const result = await extractText(uint8, { mergePages: true });\n\n let text = result.text ?? '';\n const totalPages = result.totalPages ?? 0;\n\n if (text.length > MAX_OUTPUT_CHARS) {\n _logger.info('[PdfExtract] Truncating extracted text', {\n originalLength: text.length,\n truncatedTo: MAX_OUTPUT_CHARS,\n totalPages,\n });\n text = text.slice(0, MAX_OUTPUT_CHARS) + `\\n\\n[Text truncated at ${MAX_OUTPUT_CHARS} characters]`;\n }\n\n _logger.info('[PdfExtract] Text extracted successfully', {\n textLength: text.length,\n totalPages,\n sizeBytes: buffer.length,\n });\n\n return { text, totalPages };\n}\n\n/**\n * Extract text content from a PDF file on disk.\n */\nexport async function extractPdfText(\n filePath: string\n): Promise<{ text: string; totalPages: number }> {\n const stat = await fs.stat(filePath);\n\n if (stat.size > MAX_FILE_SIZE_BYTES) {\n _logger.warn('[PdfExtract] PDF file too large for text extraction', {\n filePath,\n sizeBytes: stat.size,\n maxBytes: MAX_FILE_SIZE_BYTES,\n });\n return {\n text: `[PDF too large for text extraction: ${formatBytes(stat.size)} exceeds ${formatBytes(MAX_FILE_SIZE_BYTES)} limit]`,\n totalPages: 0,\n };\n }\n\n const buffer = await fs.readFile(filePath);\n return extractPdfTextFromBuffer(Buffer.from(buffer));\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n","/**\n * Browser Logger Interface\n *\n * Abstracts logging so browser-core works in any environment:\n * - Cloud (apps/api): Wraps pino logger\n * - CLI (canary-cli): Uses console logger\n *\n * @module logger\n */\n\nexport interface BrowserLogger {\n debug(msg: string, data?: Record<string, unknown>): void;\n info(msg: string, data?: Record<string, unknown>): void;\n warn(msg: string, data?: Record<string, unknown>): void;\n error(msg: string, data?: Record<string, unknown>): void;\n}\n\n/**\n * Default console-based logger. Works everywhere without dependencies.\n */\nexport const consoleLogger: BrowserLogger = {\n debug: (msg, data) => {\n if (data) console.debug(msg, data);\n else console.debug(msg);\n },\n info: (msg, data) => {\n if (data) console.info(msg, data);\n else console.info(msg);\n },\n warn: (msg, data) => {\n if (data) console.warn(msg, data);\n else console.warn(msg);\n },\n error: (msg, data) => {\n if (data) console.error(msg, data);\n else console.error(msg);\n },\n};\n"],"mappings":";;;AASA,YAAY,QAAQ;;;ACWb,IAAM,gBAA+B;AAAA,EAC1C,OAAO,CAAC,KAAK,SAAS;AACpB,QAAI,KAAM,SAAQ,MAAM,KAAK,IAAI;AAAA,QAC5B,SAAQ,MAAM,GAAG;AAAA,EACxB;AAAA,EACA,MAAM,CAAC,KAAK,SAAS;AACnB,QAAI,KAAM,SAAQ,KAAK,KAAK,IAAI;AAAA,QAC3B,SAAQ,KAAK,GAAG;AAAA,EACvB;AAAA,EACA,MAAM,CAAC,KAAK,SAAS;AACnB,QAAI,KAAM,SAAQ,KAAK,KAAK,IAAI;AAAA,QAC3B,SAAQ,KAAK,GAAG;AAAA,EACvB;AAAA,EACA,OAAO,CAAC,KAAK,SAAS;AACpB,QAAI,KAAM,SAAQ,MAAM,KAAK,IAAI;AAAA,QAC5B,SAAQ,MAAM,GAAG;AAAA,EACxB;AACF;;;ADzBA,IAAI,UAAyB;AAEtB,SAAS,oBAAoB,GAAwB;AAC1D,YAAU;AACZ;AAEA,IAAM,sBAAsB,KAAK,OAAO;AACxC,IAAM,mBAAmB;AAMzB,eAAsB,yBACpB,QAC+C;AAC/C,MAAI,OAAO,SAAS,qBAAqB;AACvC,YAAQ,KAAK,kDAAkD;AAAA,MAC7D,WAAW,OAAO;AAAA,MAClB,UAAU;AAAA,IACZ,CAAC;AACD,WAAO;AAAA,MACL,MAAM,uCAAuC,YAAY,OAAO,MAAM,CAAC,YAAY,YAAY,mBAAmB,CAAC;AAAA,MACnH,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,oBAAO;AAC5C,QAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,QAAM,SAAS,MAAM,YAAY,OAAO,EAAE,YAAY,KAAK,CAAC;AAE5D,MAAI,OAAO,OAAO,QAAQ;AAC1B,QAAM,aAAa,OAAO,cAAc;AAExC,MAAI,KAAK,SAAS,kBAAkB;AAClC,YAAQ,KAAK,0CAA0C;AAAA,MACrD,gBAAgB,KAAK;AAAA,MACrB,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AACD,WAAO,KAAK,MAAM,GAAG,gBAAgB,IAAI;AAAA;AAAA,qBAA0B,gBAAgB;AAAA,EACrF;AAEA,UAAQ,KAAK,4CAA4C;AAAA,IACvD,YAAY,KAAK;AAAA,IACjB;AAAA,IACA,WAAW,OAAO;AAAA,EACpB,CAAC;AAED,SAAO,EAAE,MAAM,WAAW;AAC5B;AAKA,eAAsB,eACpB,UAC+C;AAC/C,QAAMA,QAAO,MAAS,QAAK,QAAQ;AAEnC,MAAIA,MAAK,OAAO,qBAAqB;AACnC,YAAQ,KAAK,uDAAuD;AAAA,MAClE;AAAA,MACA,WAAWA,MAAK;AAAA,MAChB,UAAU;AAAA,IACZ,CAAC;AACD,WAAO;AAAA,MACL,MAAM,uCAAuC,YAAYA,MAAK,IAAI,CAAC,YAAY,YAAY,mBAAmB,CAAC;AAAA,MAC/G,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,SAAS,MAAS,YAAS,QAAQ;AACzC,SAAO,yBAAyB,OAAO,KAAK,MAAM,CAAC;AACrD;AAEA,SAAS,YAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;","names":["stat"]}