@canaryai/cli 0.2.9 → 0.2.13
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.
- package/dist/{chunk-PWWQGYFG.js → chunk-ACRIE2YR.js} +5 -2
- package/dist/chunk-ACRIE2YR.js.map +1 -0
- package/dist/chunk-BOS2YLKH.js +233 -0
- package/dist/chunk-BOS2YLKH.js.map +1 -0
- package/dist/{chunk-XGO62PO2.js → chunk-IFOJT3A5.js} +1198 -262
- package/dist/chunk-IFOJT3A5.js.map +1 -0
- package/dist/{chunk-LC7ZVXPH.js → chunk-SVU2XTYZ.js} +19 -5
- package/dist/chunk-SVU2XTYZ.js.map +1 -0
- package/dist/{chunk-A44B2PEA.js → chunk-SYPQF57S.js} +40 -8
- package/dist/chunk-SYPQF57S.js.map +1 -0
- package/dist/{chunk-C2PGZRYK.js → chunk-Z3F373YR.js} +37 -11
- package/dist/chunk-Z3F373YR.js.map +1 -0
- package/dist/{debug-workflow-I3F36JBL.js → debug-workflow-K2LL6CO4.js} +10 -12
- package/dist/debug-workflow-K2LL6CO4.js.map +1 -0
- package/dist/{docs-REHST3YB.js → docs-SR7CW24Y.js} +19 -14
- package/dist/docs-SR7CW24Y.js.map +1 -0
- package/dist/{feature-flag-3HB5NTMY.js → feature-flag-BIPFVVNC.js} +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +83 -155
- package/dist/index.js.map +1 -1
- package/dist/init-KXAVWHYE.js +146 -0
- package/dist/init-KXAVWHYE.js.map +1 -0
- package/dist/{issues-YU57CHXS.js → issues-EWVB52CA.js} +37 -18
- package/dist/issues-EWVB52CA.js.map +1 -0
- package/dist/{knobs-QJ4IBLCT.js → knobs-VYABZESR.js} +3 -3
- package/dist/list-RCPYLS36.js +57 -0
- package/dist/list-RCPYLS36.js.map +1 -0
- package/dist/local-34FX3M5K.js +63 -0
- package/dist/local-34FX3M5K.js.map +1 -0
- package/dist/{local-browser-MKTJ36KY.js → local-browser-VPOSJS52.js} +4 -4
- package/dist/login-MSIM2VIH.js +130 -0
- package/dist/login-MSIM2VIH.js.map +1 -0
- package/dist/{mcp-ZOKM2AUE.js → mcp-YBR7G254.js} +7 -132
- package/dist/mcp-YBR7G254.js.map +1 -0
- package/dist/{psql-2YPIRMDY.js → psql-XO5BB5L5.js} +2 -2
- package/dist/{record-TNDBT3NY.js → record-DXXQHPGT.js} +10 -51
- package/dist/record-DXXQHPGT.js.map +1 -0
- package/dist/{redis-A7GWM23E.js → redis-CQTBPZ6F.js} +2 -2
- package/dist/{release-L4IXOHDF.js → release-DW7RPQSQ.js} +9 -5
- package/dist/release-DW7RPQSQ.js.map +1 -0
- package/dist/runner/preload.js +1 -1
- package/dist/{session-RNLKFS2Z.js → session-XQGCLWNC.js} +164 -75
- package/dist/session-XQGCLWNC.js.map +1 -0
- package/dist/skill-2TXI3IKP.js +424 -0
- package/dist/skill-2TXI3IKP.js.map +1 -0
- package/dist/{src-2WSMYBMJ.js → src-F7LQ5PY2.js} +8 -2
- package/dist/start-ZOMUD6LW.js +112 -0
- package/dist/start-ZOMUD6LW.js.map +1 -0
- package/dist/test.js +1 -1
- package/dist/test.js.map +1 -1
- package/dist/workflow-5UZTKX7X.js +624 -0
- package/dist/workflow-5UZTKX7X.js.map +1 -0
- package/package.json +1 -2
- package/dist/chunk-A44B2PEA.js.map +0 -1
- package/dist/chunk-C2PGZRYK.js.map +0 -1
- package/dist/chunk-DXIAHB72.js +0 -340
- package/dist/chunk-DXIAHB72.js.map +0 -1
- package/dist/chunk-LC7ZVXPH.js.map +0 -1
- package/dist/chunk-PWWQGYFG.js.map +0 -1
- package/dist/chunk-QLFSJG5O.js +0 -93
- package/dist/chunk-QLFSJG5O.js.map +0 -1
- package/dist/chunk-XGO62PO2.js.map +0 -1
- package/dist/debug-workflow-I3F36JBL.js.map +0 -1
- package/dist/docs-REHST3YB.js.map +0 -1
- package/dist/issues-YU57CHXS.js.map +0 -1
- package/dist/mcp-ZOKM2AUE.js.map +0 -1
- package/dist/record-TNDBT3NY.js.map +0 -1
- package/dist/release-L4IXOHDF.js.map +0 -1
- package/dist/session-RNLKFS2Z.js.map +0 -1
- package/dist/skill-CZ7SHI3P.js +0 -156
- package/dist/skill-CZ7SHI3P.js.map +0 -1
- /package/dist/{feature-flag-3HB5NTMY.js.map → feature-flag-BIPFVVNC.js.map} +0 -0
- /package/dist/{knobs-QJ4IBLCT.js.map → knobs-VYABZESR.js.map} +0 -0
- /package/dist/{local-browser-MKTJ36KY.js.map → local-browser-VPOSJS52.js.map} +0 -0
- /package/dist/{psql-2YPIRMDY.js.map → psql-XO5BB5L5.js.map} +0 -0
- /package/dist/{redis-A7GWM23E.js.map → redis-CQTBPZ6F.js.map} +0 -0
- /package/dist/{src-2WSMYBMJ.js.map → src-F7LQ5PY2.js.map} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
apiRequest
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BOS2YLKH.js";
|
|
5
5
|
import {
|
|
6
6
|
getArgValue,
|
|
7
7
|
hasFlag,
|
|
8
8
|
resolveConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ACRIE2YR.js";
|
|
10
10
|
import "./chunk-XAA5VQ5N.js";
|
|
11
11
|
import "./chunk-VKVL7WBN.js";
|
|
12
12
|
|
|
@@ -92,7 +92,9 @@ ${reproSteps}`);
|
|
|
92
92
|
const diagParts = [];
|
|
93
93
|
const categoryLabel = DIAGNOSTIC_CATEGORY_LABELS[diagnostic.category] ?? diagnostic.category;
|
|
94
94
|
diagParts.push("## Diagnostic Analysis");
|
|
95
|
-
diagParts.push(
|
|
95
|
+
diagParts.push(
|
|
96
|
+
`**Category:** ${categoryLabel} (${Math.round(diagnostic.confidence * 100)}% confidence)`
|
|
97
|
+
);
|
|
96
98
|
diagParts.push(`**${diagnostic.title}**`);
|
|
97
99
|
diagParts.push(diagnostic.analysis);
|
|
98
100
|
if (diagnostic.smokingGun) {
|
|
@@ -119,7 +121,7 @@ ${logLines.join("\n")}
|
|
|
119
121
|
if (networkErrors.length > 0) {
|
|
120
122
|
const rows = networkErrors.map((entry) => {
|
|
121
123
|
const status = entry.status === null || entry.status === 0 ? "0 (failed)" : String(entry.status);
|
|
122
|
-
const duration = entry.durationMs
|
|
124
|
+
const duration = entry.durationMs !== null && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "\u2014";
|
|
123
125
|
return `| ${entry.method} | ${entry.url} | ${status} | ${duration} |`;
|
|
124
126
|
});
|
|
125
127
|
sections.push(
|
|
@@ -133,7 +135,9 @@ ${rows.join("\n")}`
|
|
|
133
135
|
}
|
|
134
136
|
function formatIssueListMarkdown(data, pagination) {
|
|
135
137
|
const sections = [];
|
|
136
|
-
sections.push(
|
|
138
|
+
sections.push(
|
|
139
|
+
`# Issues (page ${pagination.page} of ${pagination.totalPages}, ${pagination.totalItems} total)`
|
|
140
|
+
);
|
|
137
141
|
if (data.length === 0) {
|
|
138
142
|
sections.push("No issues found.");
|
|
139
143
|
return sections.join("\n\n");
|
|
@@ -177,15 +181,19 @@ async function fetchDiagnostics(apiUrl, token, issue) {
|
|
|
177
181
|
} catch {
|
|
178
182
|
}
|
|
179
183
|
if (consoleErrors.length === 0 && occ.consoleLogExcerpt?.trim()) {
|
|
180
|
-
consoleErrors = [
|
|
184
|
+
consoleErrors = [
|
|
185
|
+
{ type: "error", text: occ.consoleLogExcerpt.trim(), timestamp: null, location: null }
|
|
186
|
+
];
|
|
181
187
|
}
|
|
182
188
|
if (networkErrors.length === 0 && occ.networkFailureUrl) {
|
|
183
|
-
networkErrors = [
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
networkErrors = [
|
|
190
|
+
{
|
|
191
|
+
url: occ.networkFailureUrl,
|
|
192
|
+
method: "GET",
|
|
193
|
+
status: occ.networkFailureStatus,
|
|
194
|
+
durationMs: null
|
|
195
|
+
}
|
|
196
|
+
];
|
|
189
197
|
}
|
|
190
198
|
return { consoleErrors, networkErrors };
|
|
191
199
|
}
|
|
@@ -221,8 +229,10 @@ async function handleList(argv, apiUrl, token) {
|
|
|
221
229
|
return;
|
|
222
230
|
}
|
|
223
231
|
const { data, pagination } = result;
|
|
224
|
-
console.log(
|
|
225
|
-
`)
|
|
232
|
+
console.log(
|
|
233
|
+
`Issues: ${pagination.totalItems} total (page ${pagination.page}/${pagination.totalPages})
|
|
234
|
+
`
|
|
235
|
+
);
|
|
226
236
|
if (data.length === 0) {
|
|
227
237
|
console.log("No issues found.");
|
|
228
238
|
return;
|
|
@@ -231,7 +241,9 @@ async function handleList(argv, apiUrl, token) {
|
|
|
231
241
|
const icon = SEVERITY_ICONS[issue.severity] ?? "?";
|
|
232
242
|
const statusLabel = formatStatusLabel(issue.status);
|
|
233
243
|
const lastSeen = formatRelative(issue.lastSeenAt);
|
|
234
|
-
console.log(
|
|
244
|
+
console.log(
|
|
245
|
+
` [${icon}] ${truncate(issue.title, 60)} ${statusLabel} ${lastSeen} (${issue.occurrenceCount}x) ${issue.id}`
|
|
246
|
+
);
|
|
235
247
|
}
|
|
236
248
|
}
|
|
237
249
|
async function handleGet(argv, apiUrl, token) {
|
|
@@ -243,7 +255,12 @@ async function handleGet(argv, apiUrl, token) {
|
|
|
243
255
|
}
|
|
244
256
|
const jsonOutput = hasFlag(argv, "--json");
|
|
245
257
|
const markdownOutput = getArgValue(argv, "--format") === "markdown";
|
|
246
|
-
const result = await apiRequest(
|
|
258
|
+
const result = await apiRequest(
|
|
259
|
+
apiUrl,
|
|
260
|
+
token,
|
|
261
|
+
"GET",
|
|
262
|
+
`/v2/issues/${issueId}`
|
|
263
|
+
);
|
|
247
264
|
if (!result.ok) {
|
|
248
265
|
console.error(`Error: ${result.error}`);
|
|
249
266
|
process.exit(1);
|
|
@@ -271,7 +288,9 @@ async function handleGet(argv, apiUrl, token) {
|
|
|
271
288
|
console.log(` URL: ${occ.primaryUrl}`);
|
|
272
289
|
}
|
|
273
290
|
if (issue.assignedTo) {
|
|
274
|
-
console.log(
|
|
291
|
+
console.log(
|
|
292
|
+
` Assigned to: ${issue.assignedTo.displayName ?? issue.assignedTo.primaryEmail ?? issue.assignedTo.id}`
|
|
293
|
+
);
|
|
275
294
|
}
|
|
276
295
|
const summary = occ?.ticketUserFacingSummary?.trim();
|
|
277
296
|
if (summary) {
|
|
@@ -361,4 +380,4 @@ async function runIssues(argv) {
|
|
|
361
380
|
export {
|
|
362
381
|
runIssues
|
|
363
382
|
};
|
|
364
|
-
//# sourceMappingURL=issues-
|
|
383
|
+
//# sourceMappingURL=issues-EWVB52CA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/issues.ts"],"sourcesContent":["/**\n * CLI Issues Management\n *\n * Search, list, and view issues with full diagnostics from the terminal.\n */\n\nimport process from 'node:process';\nimport { resolveConfig, getArgValue, hasFlag } from './auth.js';\nimport { apiRequest } from './cli-helpers.js';\n\n/* ── Types ────────────────────────────────────────────────────────────── */\n\ntype IssueCategorySummary = {\n id: string;\n key: string;\n label: string;\n description: string | null;\n instructions: string | null;\n};\n\ntype IssueAssignee = {\n id: string;\n displayName: string | null;\n primaryEmail: string | null;\n};\n\ntype FailureDiagnostic = {\n category: string;\n confidence: number;\n title: string;\n analysis: string;\n recommendation: string;\n smokingGun?: { description: string; detail?: string } | null;\n};\n\ntype IssueOccurrence = {\n id: string;\n primaryUrl: string;\n ticketUserFacingSummary: string | null;\n ticketReproSteps: string | null;\n diagnosticJson: FailureDiagnostic | null;\n consoleLogExcerpt: string | null;\n networkFailureUrl: string | null;\n networkFailureStatus: number | null;\n};\n\ntype IssueSummary = {\n id: string;\n title: string;\n severity: 'low' | 'medium' | 'high' | 'unknown';\n status: 'open' | 'closed' | 'not_a_bug';\n category: IssueCategorySummary;\n firstSeenAt: string;\n lastSeenAt: string;\n occurrenceCount: number;\n assignedTo: IssueAssignee | null;\n latestOccurrence: IssueOccurrence | null;\n};\n\ntype ConsoleLogEntry = {\n type: string;\n text: string;\n timestamp: number | null;\n location: string | null;\n};\n\ntype NetworkRequestEntry = {\n url: string;\n method: string;\n status: number | null;\n durationMs: number | null;\n};\n\ntype Pagination = {\n page: number;\n pageSize: number;\n totalItems: number;\n totalPages: number;\n};\n\ntype IssueListResponse = {\n ok: boolean;\n error?: string;\n data: IssueSummary[];\n pagination: Pagination;\n};\n\ntype IssueDetailResponse = {\n ok: boolean;\n error?: string;\n data: {\n issue: IssueSummary;\n occurrences: IssueOccurrence[];\n commentCount: number;\n };\n};\n\ntype DiagnosticsDataResponse = {\n ok: boolean;\n data: ConsoleLogEntry[] | NetworkRequestEntry[];\n};\n\n/* ── Formatting Helpers ───────────────────────────────────────────────── */\n\nconst SEVERITY_ICONS: Record<string, string> = {\n high: '!!!',\n medium: '!!',\n low: '!',\n unknown: '?',\n};\n\nconst DIAGNOSTIC_CATEGORY_LABELS: Record<string, string> = {\n software_bug: 'Software Bug',\n dependency_issue: 'Dependency Issue',\n agent_confusion: 'Agent Confusion',\n};\n\nfunction formatStatusLabel(status: string): string {\n switch (status) {\n case 'open':\n return 'Open';\n case 'closed':\n return 'Closed';\n case 'not_a_bug':\n return 'Not a Bug';\n default:\n return status;\n }\n}\n\nfunction formatSeverity(severity: string): string {\n return severity.charAt(0).toUpperCase() + severity.slice(1);\n}\n\nfunction formatRelative(value: string | null): string {\n if (!value) return '—';\n try {\n const date = new Date(value);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n if (diffMins < 1) return 'just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n const diffHours = Math.floor(diffMins / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 30) return `${diffDays}d ago`;\n return date.toISOString().slice(0, 10);\n } catch {\n return value;\n }\n}\n\nfunction truncate(text: string, max: number): string {\n if (text.length <= max) return text;\n return text.slice(0, max - 1) + '…';\n}\n\n/* ── Markdown Formatters ──────────────────────────────────────────────── */\n\nfunction formatIssueDetailMarkdown(\n issue: IssueSummary,\n consoleErrors: ConsoleLogEntry[],\n networkErrors: NetworkRequestEntry[]\n): string {\n const sections: string[] = [];\n const occ = issue.latestOccurrence;\n\n sections.push(`# ${issue.title}`);\n\n const meta: string[] = [];\n meta.push(`**Status:** ${formatStatusLabel(issue.status)}`);\n meta.push(`**Severity:** ${formatSeverity(issue.severity)}`);\n meta.push(`**Category:** ${issue.category.label}`);\n sections.push(meta.join(' | '));\n\n if (occ?.primaryUrl) {\n sections.push(`**URL:** ${occ.primaryUrl}`);\n }\n\n const timeParts: string[] = [];\n timeParts.push(`**First seen:** ${formatRelative(issue.firstSeenAt)}`);\n timeParts.push(`**Last seen:** ${formatRelative(issue.lastSeenAt)}`);\n timeParts.push(`**Occurrences:** ${issue.occurrenceCount}`);\n sections.push(timeParts.join(' | '));\n\n const summary = occ?.ticketUserFacingSummary?.trim();\n if (summary) {\n sections.push(`## Summary\\n${summary}`);\n }\n\n const reproSteps = occ?.ticketReproSteps?.trim();\n if (reproSteps) {\n sections.push(`## Reproduction Steps\\n${reproSteps}`);\n }\n\n const diagnostic = occ?.diagnosticJson;\n if (diagnostic) {\n const diagParts: string[] = [];\n const categoryLabel = DIAGNOSTIC_CATEGORY_LABELS[diagnostic.category] ?? diagnostic.category;\n diagParts.push('## Diagnostic Analysis');\n diagParts.push(\n `**Category:** ${categoryLabel} (${Math.round(diagnostic.confidence * 100)}% confidence)`\n );\n diagParts.push(`**${diagnostic.title}**`);\n diagParts.push(diagnostic.analysis);\n\n if (diagnostic.smokingGun) {\n const gun = diagnostic.smokingGun;\n const gunLines = [`> **Key Evidence:** ${gun.description}`];\n if (gun.detail) {\n gunLines.push(`> \\`${gun.detail}\\``);\n }\n diagParts.push(gunLines.join('\\n'));\n }\n\n diagParts.push(`**Recommendation:** ${diagnostic.recommendation}`);\n sections.push(diagParts.join('\\n\\n'));\n }\n\n if (consoleErrors.length > 0) {\n const logLines = consoleErrors.map((entry) => {\n const loc = entry.location ? ` (${entry.location})` : '';\n return `[${entry.type}] ${entry.text}${loc}`;\n });\n sections.push(`## Console Errors\\n\\`\\`\\`\\n${logLines.join('\\n')}\\n\\`\\`\\``);\n }\n\n if (networkErrors.length > 0) {\n const rows = networkErrors.map((entry) => {\n const status =\n entry.status === null || entry.status === 0 ? '0 (failed)' : String(entry.status);\n const duration =\n entry.durationMs !== null && entry.durationMs !== undefined ? `${entry.durationMs}ms` : '—';\n return `| ${entry.method} | ${entry.url} | ${status} | ${duration} |`;\n });\n sections.push(\n `## Network Errors\\n| Method | URL | Status | Duration |\\n|--------|-----|--------|----------|\\n${rows.join('\\n')}`\n );\n }\n\n return sections.join('\\n\\n');\n}\n\nfunction formatIssueListMarkdown(data: IssueSummary[], pagination: Pagination): string {\n const sections: string[] = [];\n sections.push(\n `# Issues (page ${pagination.page} of ${pagination.totalPages}, ${pagination.totalItems} total)`\n );\n\n if (data.length === 0) {\n sections.push('No issues found.');\n return sections.join('\\n\\n');\n }\n\n const header = '| Severity | Title | Status | Last Seen | Occurrences |';\n const divider = '|----------|-------|--------|-----------|-------------|';\n const rows = data.map(\n (issue) =>\n `| ${issue.severity} | ${truncate(issue.title, 60)} | ${issue.status} | ${formatRelative(issue.lastSeenAt)} | ${issue.occurrenceCount} |`\n );\n sections.push([header, divider, ...rows].join('\\n'));\n\n return sections.join('\\n\\n');\n}\n\n/* ── Diagnostics Fetching ─────────────────────────────────────────────── */\n\nasync function fetchDiagnostics(\n apiUrl: string,\n token: string,\n issue: IssueSummary\n): Promise<{ consoleErrors: ConsoleLogEntry[]; networkErrors: NetworkRequestEntry[] }> {\n const occ = issue.latestOccurrence;\n if (!occ) return { consoleErrors: [], networkErrors: [] };\n\n let consoleErrors: ConsoleLogEntry[] = [];\n let networkErrors: NetworkRequestEntry[] = [];\n\n try {\n const [consoleRes, networkRes] = await Promise.all([\n apiRequest<DiagnosticsDataResponse>(\n apiUrl,\n token,\n 'GET',\n `/v2/issues/${issue.id}/occurrences/${occ.id}/console-logs`\n ),\n apiRequest<DiagnosticsDataResponse>(\n apiUrl,\n token,\n 'GET',\n `/v2/issues/${issue.id}/occurrences/${occ.id}/network-requests`\n ),\n ]);\n\n if (consoleRes.ok && Array.isArray(consoleRes.data)) {\n consoleErrors = (consoleRes.data as ConsoleLogEntry[]).filter((e) => e.type === 'error');\n }\n\n if (networkRes.ok && Array.isArray(networkRes.data)) {\n networkErrors = (networkRes.data as NetworkRequestEntry[]).filter(\n (e) => e.status === null || e.status === 0 || e.status >= 400\n );\n }\n } catch {\n // Diagnostics are best-effort; continue without them\n }\n\n // Fallback to legacy fields\n if (consoleErrors.length === 0 && occ.consoleLogExcerpt?.trim()) {\n consoleErrors = [\n { type: 'error', text: occ.consoleLogExcerpt.trim(), timestamp: null, location: null },\n ];\n }\n\n if (networkErrors.length === 0 && occ.networkFailureUrl) {\n networkErrors = [\n {\n url: occ.networkFailureUrl,\n method: 'GET',\n status: occ.networkFailureStatus,\n durationMs: null,\n },\n ];\n }\n\n return { consoleErrors, networkErrors };\n}\n\n/* ── Sub-command Handlers ─────────────────────────────────────────────── */\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, '--json');\n const markdownOutput = getArgValue(argv, '--format') === 'markdown';\n\n const params = new URLSearchParams();\n const search = getArgValue(argv, '--search');\n const severity = getArgValue(argv, '--severity');\n const status = getArgValue(argv, '--status');\n const propertyId = getArgValue(argv, '--property-id');\n const page = getArgValue(argv, '--page');\n const pageSize = getArgValue(argv, '--page-size');\n\n if (search) params.set('search', search);\n if (severity) params.set('severity', severity);\n if (status) params.set('statuses', status);\n if (propertyId) params.set('propertyId', propertyId);\n if (page) params.set('page', page);\n if (pageSize) params.set('pageSize', pageSize);\n\n const qs = params.toString();\n const path = `/v2/issues${qs ? `?${qs}` : ''}`;\n\n const result = await apiRequest<IssueListResponse>(apiUrl, token, 'GET', path);\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify({ data: result.data, pagination: result.pagination }, null, 2));\n return;\n }\n\n if (markdownOutput) {\n console.log(formatIssueListMarkdown(result.data, result.pagination));\n return;\n }\n\n // Default compact output\n const { data, pagination } = result;\n console.log(\n `Issues: ${pagination.totalItems} total (page ${pagination.page}/${pagination.totalPages})\\n`\n );\n\n if (data.length === 0) {\n console.log('No issues found.');\n return;\n }\n\n for (const issue of data) {\n const icon = SEVERITY_ICONS[issue.severity] ?? '?';\n const statusLabel = formatStatusLabel(issue.status);\n const lastSeen = formatRelative(issue.lastSeenAt);\n console.log(\n ` [${icon}] ${truncate(issue.title, 60)} ${statusLabel} ${lastSeen} (${issue.occurrenceCount}x) ${issue.id}`\n );\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const issueId = argv[0];\n if (!issueId || issueId.startsWith('--')) {\n console.error('Error: Missing issue ID.');\n console.error('Usage: canary issues get <issueId>');\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, '--json');\n const markdownOutput = getArgValue(argv, '--format') === 'markdown';\n\n const result = await apiRequest<IssueDetailResponse>(\n apiUrl,\n token,\n 'GET',\n `/v2/issues/${issueId}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n const { issue } = result.data;\n const { consoleErrors, networkErrors } = await fetchDiagnostics(apiUrl, token, issue);\n\n if (jsonOutput) {\n console.log(JSON.stringify({ ...result.data, consoleErrors, networkErrors }, null, 2));\n return;\n }\n\n if (markdownOutput) {\n console.log(formatIssueDetailMarkdown(issue, consoleErrors, networkErrors));\n return;\n }\n\n // Default human-readable output\n const occ = issue.latestOccurrence;\n console.log(` Title: ${issue.title}`);\n console.log(` ID: ${issue.id}`);\n console.log(` Status: ${formatStatusLabel(issue.status)}`);\n console.log(` Severity: ${formatSeverity(issue.severity)}`);\n console.log(` Category: ${issue.category.label}`);\n console.log(` Occurrences: ${issue.occurrenceCount}`);\n console.log(` First seen: ${formatRelative(issue.firstSeenAt)}`);\n console.log(` Last seen: ${formatRelative(issue.lastSeenAt)}`);\n\n if (occ?.primaryUrl) {\n console.log(` URL: ${occ.primaryUrl}`);\n }\n\n if (issue.assignedTo) {\n console.log(\n ` Assigned to: ${issue.assignedTo.displayName ?? issue.assignedTo.primaryEmail ?? issue.assignedTo.id}`\n );\n }\n\n const summary = occ?.ticketUserFacingSummary?.trim();\n if (summary) {\n console.log(`\\n Summary:\\n ${summary.split('\\n').join('\\n ')}`);\n }\n\n const diagnostic = occ?.diagnosticJson;\n if (diagnostic) {\n const categoryLabel = DIAGNOSTIC_CATEGORY_LABELS[diagnostic.category] ?? diagnostic.category;\n console.log(`\\n Diagnostic: ${categoryLabel} (${Math.round(diagnostic.confidence * 100)}%)`);\n console.log(` ${diagnostic.title}`);\n console.log(` Recommendation: ${diagnostic.recommendation}`);\n }\n\n if (consoleErrors.length > 0) {\n console.log(`\\n Console Errors (${consoleErrors.length}):`);\n for (const entry of consoleErrors.slice(0, 5)) {\n const loc = entry.location ? ` (${entry.location})` : '';\n console.log(` [${entry.type}] ${truncate(entry.text, 100)}${loc}`);\n }\n if (consoleErrors.length > 5) {\n console.log(` ... and ${consoleErrors.length - 5} more`);\n }\n }\n\n if (networkErrors.length > 0) {\n console.log(`\\n Network Errors (${networkErrors.length}):`);\n for (const entry of networkErrors.slice(0, 5)) {\n const status = entry.status === null || entry.status === 0 ? 'failed' : String(entry.status);\n console.log(` ${entry.method} ${truncate(entry.url, 80)} -> ${status}`);\n }\n if (networkErrors.length > 5) {\n console.log(` ... and ${networkErrors.length - 5} more`);\n }\n }\n}\n\n/* ── Help & Entry Point ───────────────────────────────────────────────── */\n\nfunction printIssuesHelp(): void {\n console.log(\n [\n 'Usage: canary issues <sub-command> [options]',\n '',\n 'Sub-commands:',\n ' list [options] List and search issues',\n ' get <issueId> [options] Get issue detail with diagnostics',\n '',\n 'List options:',\n ' --search <query> Full-text search',\n ' --severity <level> Filter: low, medium, high, unknown',\n ' --status <statuses> Filter: open, closed, not_a_bug (comma-separated)',\n ' --property-id <uuid> Filter by property',\n ' --page <n> Page number (default: 1)',\n ' --page-size <n> Page size (default: 25)',\n '',\n 'Output options:',\n ' --json Output raw JSON',\n ' --format markdown Output as markdown',\n '',\n 'Common options:',\n ' --env <env> Target environment (prod, dev, local)',\n ' --api-url <url> API URL override (takes precedence over --env)',\n ' --token <key> API token override',\n ].join('\\n')\n );\n}\n\nexport async function runIssues(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printIssuesHelp();\n return;\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n switch (subCommand) {\n case 'list':\n await handleList(rest, apiUrl, token);\n break;\n case 'get':\n await handleGet(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printIssuesHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
fetchList,
|
|
5
5
|
parseLifecycleStage,
|
|
6
6
|
toLifecycleLabel
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BOS2YLKH.js";
|
|
8
8
|
import {
|
|
9
9
|
getArgValue,
|
|
10
10
|
hasFlag,
|
|
11
11
|
resolveConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ACRIE2YR.js";
|
|
13
13
|
import "./chunk-XAA5VQ5N.js";
|
|
14
14
|
import "./chunk-VKVL7WBN.js";
|
|
15
15
|
|
|
@@ -286,4 +286,4 @@ async function runKnobs(argv) {
|
|
|
286
286
|
export {
|
|
287
287
|
runKnobs
|
|
288
288
|
};
|
|
289
|
-
//# sourceMappingURL=knobs-
|
|
289
|
+
//# sourceMappingURL=knobs-VYABZESR.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
fetchList,
|
|
4
|
+
fetchProperties
|
|
5
|
+
} from "./chunk-BOS2YLKH.js";
|
|
6
|
+
import {
|
|
7
|
+
resolveConfig
|
|
8
|
+
} from "./chunk-ACRIE2YR.js";
|
|
9
|
+
import "./chunk-XAA5VQ5N.js";
|
|
10
|
+
import "./chunk-VKVL7WBN.js";
|
|
11
|
+
|
|
12
|
+
// src/local/list.ts
|
|
13
|
+
async function runLocalList(argv) {
|
|
14
|
+
const config = await resolveConfig(argv);
|
|
15
|
+
const properties = await fetchProperties(config.apiUrl, config.token);
|
|
16
|
+
if (properties.length === 0) {
|
|
17
|
+
console.log("No properties found.");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const rows = [];
|
|
21
|
+
for (const property of properties) {
|
|
22
|
+
const envs = await fetchList(
|
|
23
|
+
config.apiUrl,
|
|
24
|
+
config.token,
|
|
25
|
+
`/org/properties/${property.id}/environments/local`,
|
|
26
|
+
"items"
|
|
27
|
+
);
|
|
28
|
+
for (const env of envs) {
|
|
29
|
+
rows.push({
|
|
30
|
+
envId: env.id,
|
|
31
|
+
property: property.name,
|
|
32
|
+
name: env.name,
|
|
33
|
+
url: env.url
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (rows.length === 0) {
|
|
38
|
+
console.log("No local environments found. Run `canary local init` to create one.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const headers = ["ENV ID", "PROPERTY", "NAME", "URL"];
|
|
42
|
+
const widths = headers.map((h, i) => {
|
|
43
|
+
const col = [h, ...rows.map((r) => Object.values(r)[i])];
|
|
44
|
+
return Math.max(...col.map((v) => v.length));
|
|
45
|
+
});
|
|
46
|
+
const sep = widths.map((w) => "-".repeat(w)).join(" ");
|
|
47
|
+
const formatRow = (vals) => vals.map((v, i) => v.padEnd(widths[i])).join(" ");
|
|
48
|
+
console.log(formatRow(headers));
|
|
49
|
+
console.log(sep);
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
console.log(formatRow([row.envId, row.property, row.name, row.url]));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
runLocalList
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=list-RCPYLS36.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/local/list.ts"],"sourcesContent":["/**\n * `canary local list` — List all local environments for the current user.\n *\n * @module\n */\n\nimport { resolveConfig } from '../auth.js';\nimport { fetchProperties, fetchList } from '../cli-helpers.js';\n\ninterface LocalEnvironment {\n id: string;\n name: string;\n url: string;\n propertyId: string;\n}\n\nexport async function runLocalList(argv: string[]) {\n const config = await resolveConfig(argv);\n\n const properties = await fetchProperties(config.apiUrl, config.token);\n\n if (properties.length === 0) {\n console.log('No properties found.');\n return;\n }\n\n const rows: Array<{ envId: string; property: string; name: string; url: string }> = [];\n\n for (const property of properties) {\n const envs = await fetchList<LocalEnvironment>(\n config.apiUrl,\n config.token,\n `/org/properties/${property.id}/environments/local`,\n 'items'\n );\n\n for (const env of envs) {\n rows.push({\n envId: env.id,\n property: property.name,\n name: env.name,\n url: env.url,\n });\n }\n }\n\n if (rows.length === 0) {\n console.log('No local environments found. Run `canary local init` to create one.');\n return;\n }\n\n // Print table\n const headers = ['ENV ID', 'PROPERTY', 'NAME', 'URL'];\n const widths = headers.map((h, i) => {\n const col = [h, ...rows.map((r) => Object.values(r)[i])];\n return Math.max(...col.map((v) => v.length));\n });\n\n const sep = widths.map((w) => '-'.repeat(w)).join(' ');\n const formatRow = (vals: string[]) => vals.map((v, i) => v.padEnd(widths[i])).join(' ');\n\n console.log(formatRow(headers));\n console.log(sep);\n for (const row of rows) {\n console.log(formatRow([row.envId, row.property, row.name, row.url]));\n }\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,eAAsB,aAAa,MAAgB;AACjD,QAAM,SAAS,MAAM,cAAc,IAAI;AAEvC,QAAM,aAAa,MAAM,gBAAgB,OAAO,QAAQ,OAAO,KAAK;AAEpE,MAAI,WAAW,WAAW,GAAG;AAC3B,YAAQ,IAAI,sBAAsB;AAClC;AAAA,EACF;AAEA,QAAM,OAA8E,CAAC;AAErF,aAAW,YAAY,YAAY;AACjC,UAAM,OAAO,MAAM;AAAA,MACjB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,mBAAmB,SAAS,EAAE;AAAA,MAC9B;AAAA,IACF;AAEA,eAAW,OAAO,MAAM;AACtB,WAAK,KAAK;AAAA,QACR,OAAO,IAAI;AAAA,QACX,UAAU,SAAS;AAAA,QACnB,MAAM,IAAI;AAAA,QACV,KAAK,IAAI;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,YAAQ,IAAI,qEAAqE;AACjF;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,UAAU,YAAY,QAAQ,KAAK;AACpD,QAAM,SAAS,QAAQ,IAAI,CAAC,GAAG,MAAM;AACnC,UAAM,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACvD,WAAO,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAAA,EAC7C,CAAC;AAED,QAAM,MAAM,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI;AACtD,QAAM,YAAY,CAAC,SAAmB,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAEvF,UAAQ,IAAI,UAAU,OAAO,CAAC;AAC9B,UAAQ,IAAI,GAAG;AACf,aAAW,OAAO,MAAM;AACtB,YAAQ,IAAI,UAAU,CAAC,IAAI,OAAO,IAAI,UAAU,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC;AAAA,EACrE;AACF;","names":[]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
hasFlag
|
|
4
|
+
} from "./chunk-ACRIE2YR.js";
|
|
5
|
+
import "./chunk-VKVL7WBN.js";
|
|
6
|
+
|
|
7
|
+
// src/local/index.ts
|
|
8
|
+
import process from "process";
|
|
9
|
+
function printHelp() {
|
|
10
|
+
console.log(
|
|
11
|
+
[
|
|
12
|
+
"canary local \u2014 Manage local testing environments",
|
|
13
|
+
"",
|
|
14
|
+
"Sub-commands:",
|
|
15
|
+
" init Set up a new local testing environment",
|
|
16
|
+
" start Start a browser session for a local environment",
|
|
17
|
+
" list List local environments",
|
|
18
|
+
" login Re-login / refresh credentials",
|
|
19
|
+
"",
|
|
20
|
+
"Options:",
|
|
21
|
+
" --env <env> Environment (local, dev, prod)",
|
|
22
|
+
" --api-url <url> API URL override",
|
|
23
|
+
" -h, --help Show this help"
|
|
24
|
+
].join("\n")
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
async function runLocal(argv) {
|
|
28
|
+
const [subcommand, ...rest] = argv;
|
|
29
|
+
if (!subcommand || subcommand === "help" || hasFlag(argv, "--help", "-h")) {
|
|
30
|
+
printHelp();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
switch (subcommand) {
|
|
34
|
+
case "init": {
|
|
35
|
+
const { runLocalInit } = await import("./init-KXAVWHYE.js");
|
|
36
|
+
await runLocalInit(rest);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case "start": {
|
|
40
|
+
const { runLocalStart } = await import("./start-ZOMUD6LW.js");
|
|
41
|
+
await runLocalStart(rest);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "list": {
|
|
45
|
+
const { runLocalList } = await import("./list-RCPYLS36.js");
|
|
46
|
+
await runLocalList(rest);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case "login": {
|
|
50
|
+
const { runLocalLogin } = await import("./login-MSIM2VIH.js");
|
|
51
|
+
await runLocalLogin(rest);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
console.error(`Unknown sub-command: ${subcommand}`);
|
|
56
|
+
printHelp();
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
runLocal
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=local-34FX3M5K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/local/index.ts"],"sourcesContent":["/**\n * CLI local command — `canary local <subcommand>`.\n *\n * @module\n */\n\nimport process from 'node:process';\nimport { hasFlag } from '../auth.js';\n\nfunction printHelp() {\n console.log(\n [\n 'canary local — Manage local testing environments',\n '',\n 'Sub-commands:',\n ' init Set up a new local testing environment',\n ' start Start a browser session for a local environment',\n ' list List local environments',\n ' login Re-login / refresh credentials',\n '',\n 'Options:',\n ' --env <env> Environment (local, dev, prod)',\n ' --api-url <url> API URL override',\n ' -h, --help Show this help',\n ].join('\\n')\n );\n}\n\nexport async function runLocal(argv: string[]) {\n const [subcommand, ...rest] = argv;\n\n if (!subcommand || subcommand === 'help' || hasFlag(argv, '--help', '-h')) {\n printHelp();\n return;\n }\n\n switch (subcommand) {\n case 'init': {\n const { runLocalInit } = await import('./init.js');\n await runLocalInit(rest);\n break;\n }\n case 'start': {\n const { runLocalStart } = await import('./start.js');\n await runLocalStart(rest);\n break;\n }\n case 'list': {\n const { runLocalList } = await import('./list.js');\n await runLocalList(rest);\n break;\n }\n case 'login': {\n const { runLocalLogin } = await import('./login.js');\n await runLocalLogin(rest);\n break;\n }\n default:\n console.error(`Unknown sub-command: ${subcommand}`);\n printHelp();\n process.exitCode = 1;\n }\n}\n"],"mappings":";;;;;;;AAMA,OAAO,aAAa;AAGpB,SAAS,YAAY;AACnB,UAAQ;AAAA,IACN;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAEA,eAAsB,SAAS,MAAgB;AAC7C,QAAM,CAAC,YAAY,GAAG,IAAI,IAAI;AAE9B,MAAI,CAAC,cAAc,eAAe,UAAU,QAAQ,MAAM,UAAU,IAAI,GAAG;AACzE,cAAU;AACV;AAAA,EACF;AAEA,UAAQ,YAAY;AAAA,IAClB,KAAK,QAAQ;AACX,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,oBAAW;AACjD,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,qBAAY;AACnD,YAAM,cAAc,IAAI;AACxB;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,oBAAW;AACjD,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,qBAAY;AACnD,YAAM,cAAc,IAAI;AACxB;AAAA,IACF;AAAA,IACA;AACE,cAAQ,MAAM,wBAAwB,UAAU,EAAE;AAClD,gBAAU;AACV,cAAQ,WAAW;AAAA,EACvB;AACF;","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
LocalBrowserHost
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SVU2XTYZ.js";
|
|
5
5
|
import {
|
|
6
6
|
readStoredToken
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-ACRIE2YR.js";
|
|
8
|
+
import "./chunk-IFOJT3A5.js";
|
|
9
9
|
import "./chunk-XAA5VQ5N.js";
|
|
10
10
|
import "./chunk-P5Z2Y5VV.js";
|
|
11
11
|
import "./chunk-VKVL7WBN.js";
|
|
@@ -141,4 +141,4 @@ async function runLocalBrowser(args) {
|
|
|
141
141
|
export {
|
|
142
142
|
runLocalBrowser
|
|
143
143
|
};
|
|
144
|
-
//# sourceMappingURL=local-browser-
|
|
144
|
+
//# sourceMappingURL=local-browser-VPOSJS52.js.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
fetchList,
|
|
4
|
+
promptChoice,
|
|
5
|
+
selectProperty,
|
|
6
|
+
uploadStorageState
|
|
7
|
+
} from "./chunk-BOS2YLKH.js";
|
|
8
|
+
import {
|
|
9
|
+
createSession,
|
|
10
|
+
deleteSession,
|
|
11
|
+
getSessionStorageState
|
|
12
|
+
} from "./chunk-Z3F373YR.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveConfig
|
|
15
|
+
} from "./chunk-ACRIE2YR.js";
|
|
16
|
+
import "./chunk-XAA5VQ5N.js";
|
|
17
|
+
import "./chunk-VKVL7WBN.js";
|
|
18
|
+
|
|
19
|
+
// src/local/login.ts
|
|
20
|
+
import process from "process";
|
|
21
|
+
async function runLocalLogin(argv) {
|
|
22
|
+
const config = await resolveConfig(argv);
|
|
23
|
+
const property = await selectProperty(config.apiUrl, config.token);
|
|
24
|
+
if (!property) {
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const envs = await fetchList(
|
|
29
|
+
config.apiUrl,
|
|
30
|
+
config.token,
|
|
31
|
+
`/org/properties/${property.id}/environments/local`,
|
|
32
|
+
"items"
|
|
33
|
+
);
|
|
34
|
+
if (envs.length === 0) {
|
|
35
|
+
console.error("No local environments found. Run `canary local init` first.");
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let selectedEnv;
|
|
40
|
+
if (envs.length === 1) {
|
|
41
|
+
selectedEnv = envs[0];
|
|
42
|
+
} else {
|
|
43
|
+
const picked = await promptChoice(
|
|
44
|
+
"Select a local environment:",
|
|
45
|
+
envs.map((e) => ({ label: `${e.name} \u2014 ${e.url}`, value: e }))
|
|
46
|
+
);
|
|
47
|
+
if (!picked) {
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
selectedEnv = picked;
|
|
52
|
+
}
|
|
53
|
+
const allCredentials = await fetchList(
|
|
54
|
+
config.apiUrl,
|
|
55
|
+
config.token,
|
|
56
|
+
"/org/credentials",
|
|
57
|
+
"items"
|
|
58
|
+
);
|
|
59
|
+
const envCredentials = allCredentials.filter(
|
|
60
|
+
(c) => c.propertyId === property.id
|
|
61
|
+
);
|
|
62
|
+
if (envCredentials.length === 0) {
|
|
63
|
+
console.error("No credentials found for this property.");
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let credential;
|
|
68
|
+
if (envCredentials.length === 1) {
|
|
69
|
+
credential = envCredentials[0];
|
|
70
|
+
} else {
|
|
71
|
+
const picked = await promptChoice(
|
|
72
|
+
"Select a credential to refresh:",
|
|
73
|
+
envCredentials.map((c) => ({ label: c.name, value: c }))
|
|
74
|
+
);
|
|
75
|
+
if (!picked) {
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
credential = picked;
|
|
80
|
+
}
|
|
81
|
+
console.log(`
|
|
82
|
+
Opening browser at ${selectedEnv.url}...`);
|
|
83
|
+
const sessionResult = await createSession({
|
|
84
|
+
name: "local-login",
|
|
85
|
+
url: selectedEnv.url
|
|
86
|
+
});
|
|
87
|
+
if (!sessionResult.ok || !sessionResult.data) {
|
|
88
|
+
console.error(`Failed to start browser: ${sessionResult.error ?? "Unknown error"}`);
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const sessionId = sessionResult.data.id;
|
|
93
|
+
console.log("Log in, then press Enter when done.");
|
|
94
|
+
const readline = await import("readline");
|
|
95
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
96
|
+
await new Promise((resolve) => {
|
|
97
|
+
rl.question("", () => {
|
|
98
|
+
rl.close();
|
|
99
|
+
resolve();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
console.log("Extracting login state...");
|
|
103
|
+
const storageResult = await getSessionStorageState(sessionId);
|
|
104
|
+
if (!storageResult.ok || !storageResult.data) {
|
|
105
|
+
console.error(`Failed to extract storage state: ${storageResult.error ?? "Unknown error"}`);
|
|
106
|
+
await deleteSession(sessionId);
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
console.log("Saving login state...");
|
|
111
|
+
const uploadResult = await uploadStorageState({
|
|
112
|
+
apiUrl: config.apiUrl,
|
|
113
|
+
token: config.token,
|
|
114
|
+
propertyId: property.id,
|
|
115
|
+
credentialId: credential.id,
|
|
116
|
+
storageState: storageResult.data
|
|
117
|
+
});
|
|
118
|
+
if (!uploadResult.ok) {
|
|
119
|
+
console.error(`Failed to save login state: ${uploadResult.error ?? "Unknown error"}`);
|
|
120
|
+
await deleteSession(sessionId);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await deleteSession(sessionId);
|
|
125
|
+
console.log("\nLogin state refreshed! Run `canary local start` to begin.");
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
runLocalLogin
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=login-MSIM2VIH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/local/login.ts"],"sourcesContent":["/**\n * `canary local login` — Re-login / refresh credentials for a local environment.\n *\n * @module\n */\n\nimport process from 'node:process';\nimport { resolveConfig } from '../auth.js';\nimport {\n selectProperty,\n promptChoice,\n fetchList,\n uploadStorageState,\n} from '../cli-helpers.js';\nimport {\n createSession,\n deleteSession,\n getSessionStorageState,\n} from '../session/daemon-client.js';\nimport type { CredentialListItem } from '../cli-helpers.js';\n\ninterface LocalEnvironment {\n id: string;\n name: string;\n url: string;\n propertyId: string;\n}\n\nexport async function runLocalLogin(argv: string[]) {\n const config = await resolveConfig(argv);\n\n // Select property\n const property = await selectProperty(config.apiUrl, config.token);\n if (!property) {\n process.exitCode = 1;\n return;\n }\n\n // Get local environments\n const envs = await fetchList<LocalEnvironment>(\n config.apiUrl,\n config.token,\n `/org/properties/${property.id}/environments/local`,\n 'items'\n );\n\n if (envs.length === 0) {\n console.error('No local environments found. Run `canary local init` first.');\n process.exitCode = 1;\n return;\n }\n\n let selectedEnv: LocalEnvironment;\n if (envs.length === 1) {\n selectedEnv = envs[0];\n } else {\n const picked = await promptChoice(\n 'Select a local environment:',\n envs.map((e) => ({ label: `${e.name} — ${e.url}`, value: e }))\n );\n if (!picked) {\n process.exitCode = 1;\n return;\n }\n selectedEnv = picked;\n }\n\n // Find credentials for this property\n const allCredentials = await fetchList<CredentialListItem>(\n config.apiUrl,\n config.token,\n '/org/credentials',\n 'items'\n );\n\n const envCredentials = allCredentials.filter(\n (c) => c.propertyId === property.id\n );\n\n if (envCredentials.length === 0) {\n console.error('No credentials found for this property.');\n process.exitCode = 1;\n return;\n }\n\n let credential: CredentialListItem;\n if (envCredentials.length === 1) {\n credential = envCredentials[0];\n } else {\n const picked = await promptChoice(\n 'Select a credential to refresh:',\n envCredentials.map((c) => ({ label: c.name, value: c }))\n );\n if (!picked) {\n process.exitCode = 1;\n return;\n }\n credential = picked;\n }\n\n // Open headed session for login\n console.log(`\\nOpening browser at ${selectedEnv.url}...`);\n const sessionResult = await createSession({\n name: 'local-login',\n url: selectedEnv.url,\n });\n\n if (!sessionResult.ok || !sessionResult.data) {\n console.error(`Failed to start browser: ${sessionResult.error ?? 'Unknown error'}`);\n process.exitCode = 1;\n return;\n }\n\n const sessionId = sessionResult.data.id;\n\n console.log('Log in, then press Enter when done.');\n\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n await new Promise<void>((resolve) => {\n rl.question('', () => {\n rl.close();\n resolve();\n });\n });\n\n // Extract and upload storage state\n console.log('Extracting login state...');\n const storageResult = await getSessionStorageState(sessionId);\n\n if (!storageResult.ok || !storageResult.data) {\n console.error(`Failed to extract storage state: ${storageResult.error ?? 'Unknown error'}`);\n await deleteSession(sessionId);\n process.exitCode = 1;\n return;\n }\n\n console.log('Saving login state...');\n const uploadResult = await uploadStorageState({\n apiUrl: config.apiUrl,\n token: config.token,\n propertyId: property.id,\n credentialId: credential.id,\n storageState: storageResult.data,\n });\n\n if (!uploadResult.ok) {\n console.error(`Failed to save login state: ${uploadResult.error ?? 'Unknown error'}`);\n await deleteSession(sessionId);\n process.exitCode = 1;\n return;\n }\n\n await deleteSession(sessionId);\n console.log('\\nLogin state refreshed! Run `canary local start` to begin.');\n}\n"],"mappings":"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","names":[]}
|