@canaryai/cli 0.2.8 → 0.2.12
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/README.md +77 -92
- package/dist/chunk-CEW4BDXD.js +186 -0
- package/dist/chunk-CEW4BDXD.js.map +1 -0
- package/dist/chunk-ERSNYLMZ.js +229 -0
- package/dist/chunk-ERSNYLMZ.js.map +1 -0
- package/dist/{chunk-FK3EZADZ.js → chunk-MSMC6UXW.js} +2021 -873
- package/dist/chunk-MSMC6UXW.js.map +1 -0
- package/dist/{chunk-K2OB72B6.js → chunk-Q7WFBG5C.js} +2 -2
- package/dist/{debug-workflow-55G4Y6YT.js → debug-workflow-53ULOFJC.js} +57 -36
- package/dist/debug-workflow-53ULOFJC.js.map +1 -0
- package/dist/{docs-RPFT7ZJB.js → docs-BEE3LOCO.js} +2 -2
- package/dist/{feature-flag-2FDSKOVX.js → feature-flag-CYTDV4ZB.js} +3 -2
- package/dist/{feature-flag-2FDSKOVX.js.map → feature-flag-CYTDV4ZB.js.map} +1 -1
- package/dist/index.js +72 -137
- package/dist/index.js.map +1 -1
- package/dist/init-M6I3MG3D.js +146 -0
- package/dist/init-M6I3MG3D.js.map +1 -0
- package/dist/{issues-6ZDNDSD6.js → issues-NLM72HLU.js} +3 -2
- package/dist/{issues-6ZDNDSD6.js.map → issues-NLM72HLU.js.map} +1 -1
- package/dist/{knobs-MZRTYS3P.js → knobs-O35GAU5M.js} +3 -2
- package/dist/{knobs-MZRTYS3P.js.map → knobs-O35GAU5M.js.map} +1 -1
- package/dist/list-4K4EIGAT.js +57 -0
- package/dist/list-4K4EIGAT.js.map +1 -0
- package/dist/local-NHXXPHZ3.js +63 -0
- package/dist/local-NHXXPHZ3.js.map +1 -0
- package/dist/{local-browser-X7J27IGS.js → local-browser-VAZORCO3.js} +3 -3
- package/dist/login-ZLP64YQP.js +130 -0
- package/dist/login-ZLP64YQP.js.map +1 -0
- package/dist/mcp-ZF5G5DCB.js +377 -0
- package/dist/mcp-ZF5G5DCB.js.map +1 -0
- package/dist/{record-4OX7HXWQ.js → record-V6QKFFH3.js} +133 -72
- package/dist/record-V6QKFFH3.js.map +1 -0
- package/dist/{release-L4IXOHDF.js → release-7TI7EIGD.js} +8 -4
- package/dist/release-7TI7EIGD.js.map +1 -0
- package/dist/session-UGNJXRUW.js +819 -0
- package/dist/session-UGNJXRUW.js.map +1 -0
- package/dist/skill-ORWAPBDW.js +424 -0
- package/dist/skill-ORWAPBDW.js.map +1 -0
- package/dist/{src-I4EXB5OD.js → src-4VIDSK4A.js} +18 -2
- package/dist/start-E532F3BU.js +112 -0
- package/dist/start-E532F3BU.js.map +1 -0
- package/dist/workflow-HXIUXRFI.js +613 -0
- package/dist/workflow-HXIUXRFI.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6WWHXWCS.js +0 -65
- package/dist/chunk-6WWHXWCS.js.map +0 -1
- package/dist/chunk-DXIAHB72.js +0 -340
- package/dist/chunk-DXIAHB72.js.map +0 -1
- package/dist/chunk-FK3EZADZ.js.map +0 -1
- package/dist/debug-workflow-55G4Y6YT.js.map +0 -1
- package/dist/mcp-4JVLADZL.js +0 -688
- package/dist/mcp-4JVLADZL.js.map +0 -1
- package/dist/record-4OX7HXWQ.js.map +0 -1
- package/dist/release-L4IXOHDF.js.map +0 -1
- /package/dist/{chunk-K2OB72B6.js.map → chunk-Q7WFBG5C.js.map} +0 -0
- /package/dist/{docs-RPFT7ZJB.js.map → docs-BEE3LOCO.js.map} +0 -0
- /package/dist/{local-browser-X7J27IGS.js.map → local-browser-VAZORCO3.js.map} +0 -0
- /package/dist/{src-I4EXB5OD.js.map → src-4VIDSK4A.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
PlaywrightClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MSMC6UXW.js";
|
|
5
5
|
|
|
6
6
|
// src/local-browser/host.ts
|
|
7
7
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
@@ -370,4 +370,4 @@ var LocalBrowserHost = class {
|
|
|
370
370
|
export {
|
|
371
371
|
LocalBrowserHost
|
|
372
372
|
};
|
|
373
|
-
//# sourceMappingURL=chunk-
|
|
373
|
+
//# sourceMappingURL=chunk-Q7WFBG5C.js.map
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
downloadStorageState
|
|
4
|
+
} from "./chunk-ERSNYLMZ.js";
|
|
2
5
|
import {
|
|
3
6
|
LocalBrowserHost
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Q7WFBG5C.js";
|
|
5
8
|
import {
|
|
6
9
|
getArgValue,
|
|
7
10
|
hasFlag,
|
|
8
11
|
resolveConfig
|
|
9
12
|
} from "./chunk-PWWQGYFG.js";
|
|
10
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-MSMC6UXW.js";
|
|
11
14
|
import "./chunk-XAA5VQ5N.js";
|
|
12
15
|
import "./chunk-P5Z2Y5VV.js";
|
|
13
16
|
import "./chunk-VKVL7WBN.js";
|
|
14
17
|
|
|
15
18
|
// src/debug-workflow.ts
|
|
19
|
+
import fs from "fs/promises";
|
|
16
20
|
import process from "process";
|
|
17
21
|
import { createParser } from "eventsource-parser";
|
|
18
22
|
async function runDebugWorkflow(argv) {
|
|
@@ -54,6 +58,51 @@ async function runDebugWorkflow(argv) {
|
|
|
54
58
|
console.error(`Failed to connect to API: ${err}`);
|
|
55
59
|
process.exit(1);
|
|
56
60
|
}
|
|
61
|
+
console.log("Loading workflow...");
|
|
62
|
+
let debugSession;
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch(`${apiUrl}/cli/debug/sessions`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
Authorization: `Bearer ${token}`
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
workflowId,
|
|
72
|
+
localBrowserSessionId: localSession.sessionId
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const text = await res.text();
|
|
77
|
+
console.error(`Failed to create debug session: ${res.status} ${text}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
debugSession = await res.json();
|
|
81
|
+
if (!debugSession.ok || !debugSession.sessionId) {
|
|
82
|
+
console.error(`Failed to create debug session: ${debugSession.error}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error(`Failed to create debug session: ${err}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
let debugSessionId = debugSession.sessionId;
|
|
90
|
+
let storageStatePath;
|
|
91
|
+
if (debugSession.isAuthenticated && debugSession.credential) {
|
|
92
|
+
console.log("Downloading storage state...");
|
|
93
|
+
storageStatePath = await downloadStorageState({
|
|
94
|
+
apiUrl,
|
|
95
|
+
token,
|
|
96
|
+
propertyId: debugSession.credential.propertyId,
|
|
97
|
+
credentialId: debugSession.credential.credentialId,
|
|
98
|
+
prefix: "canary-debug-ss"
|
|
99
|
+
});
|
|
100
|
+
if (storageStatePath) {
|
|
101
|
+
console.log("Storage state loaded.");
|
|
102
|
+
} else {
|
|
103
|
+
console.warn("Could not download storage state, continuing without it.");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
57
106
|
console.log("Launching headed browser...");
|
|
58
107
|
const host = new LocalBrowserHost({
|
|
59
108
|
apiUrl,
|
|
@@ -61,6 +110,7 @@ async function runDebugWorkflow(argv) {
|
|
|
61
110
|
sessionId: localSession.sessionId,
|
|
62
111
|
browserMode: "playwright",
|
|
63
112
|
headless: false,
|
|
113
|
+
storageStatePath,
|
|
64
114
|
onLog: (level, message, data) => {
|
|
65
115
|
if (verbose) {
|
|
66
116
|
const prefix = `[${level.toUpperCase()}]`;
|
|
@@ -72,7 +122,6 @@ async function runDebugWorkflow(argv) {
|
|
|
72
122
|
}
|
|
73
123
|
}
|
|
74
124
|
});
|
|
75
|
-
let debugSessionId = null;
|
|
76
125
|
const cleanup = async () => {
|
|
77
126
|
console.log("\nShutting down...");
|
|
78
127
|
if (debugSessionId) {
|
|
@@ -84,6 +133,10 @@ async function runDebugWorkflow(argv) {
|
|
|
84
133
|
} catch {
|
|
85
134
|
}
|
|
86
135
|
}
|
|
136
|
+
if (storageStatePath) {
|
|
137
|
+
await fs.unlink(storageStatePath).catch(() => {
|
|
138
|
+
});
|
|
139
|
+
}
|
|
87
140
|
await host.stop();
|
|
88
141
|
process.exit(0);
|
|
89
142
|
};
|
|
@@ -98,38 +151,6 @@ async function runDebugWorkflow(argv) {
|
|
|
98
151
|
}
|
|
99
152
|
console.log("Browser connected.");
|
|
100
153
|
console.log();
|
|
101
|
-
console.log("Loading workflow...");
|
|
102
|
-
let debugSession;
|
|
103
|
-
try {
|
|
104
|
-
const res = await fetch(`${apiUrl}/cli/debug/sessions`, {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers: {
|
|
107
|
-
"Content-Type": "application/json",
|
|
108
|
-
Authorization: `Bearer ${token}`
|
|
109
|
-
},
|
|
110
|
-
body: JSON.stringify({
|
|
111
|
-
workflowId,
|
|
112
|
-
localBrowserSessionId: localSession.sessionId
|
|
113
|
-
})
|
|
114
|
-
});
|
|
115
|
-
if (!res.ok) {
|
|
116
|
-
const text = await res.text();
|
|
117
|
-
console.error(`Failed to create debug session: ${res.status} ${text}`);
|
|
118
|
-
await host.stop();
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
debugSession = await res.json();
|
|
122
|
-
if (!debugSession.ok || !debugSession.sessionId) {
|
|
123
|
-
console.error(`Failed to create debug session: ${debugSession.error}`);
|
|
124
|
-
await host.stop();
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
} catch (err) {
|
|
128
|
-
console.error(`Failed to create debug session: ${err}`);
|
|
129
|
-
await host.stop();
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
debugSessionId = debugSession.sessionId;
|
|
133
154
|
const nodes = debugSession.nodes ?? [];
|
|
134
155
|
const totalSteps = nodes.length;
|
|
135
156
|
const effectiveToStep = toStep ? Math.min(toStep, totalSteps) : totalSteps;
|
|
@@ -241,4 +262,4 @@ async function runDebugWorkflow(argv) {
|
|
|
241
262
|
export {
|
|
242
263
|
runDebugWorkflow
|
|
243
264
|
};
|
|
244
|
-
//# sourceMappingURL=debug-workflow-
|
|
265
|
+
//# sourceMappingURL=debug-workflow-53ULOFJC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/debug-workflow.ts"],"sourcesContent":["/**\n * Debug Workflow Command\n *\n * Runs a workflow in a local headed browser for debugging. Replays cached\n * actions where possible and falls back to the agent for uncached steps.\n * The browser stays open after execution so the user can inspect page state.\n *\n * Usage:\n * canary debug <workflowId> [--to-step N] [--api-url URL] [--env local|dev|prod]\n *\n * @module debug-workflow\n */\n\nimport fs from \"node:fs/promises\";\nimport process from \"node:process\";\nimport { createParser, type EventSourceMessage } from \"eventsource-parser\";\nimport { resolveConfig, getArgValue, hasFlag } from \"./auth\";\nimport { downloadStorageState } from \"./cli-helpers.js\";\nimport { LocalBrowserHost } from \"./local-browser/host\";\n\ninterface CreateSessionResponse {\n ok: boolean;\n sessionId: string;\n wsToken: string;\n wsUrl: string;\n expiresAt: string;\n error?: string;\n}\n\ninterface DebugSessionResponse {\n ok: boolean;\n sessionId?: string;\n workflowName?: string;\n nodes?: Array<{\n index: number;\n id: string;\n name: string;\n type: string;\n }>;\n isAuthenticated?: boolean;\n credential?: { credentialId: string; propertyId: string } | null;\n error?: string;\n}\n\ninterface StepStartedEvent {\n type: \"step-started\";\n stepIndex: number;\n totalSteps: number;\n stepName: string;\n nodeType: string;\n nodeId: string;\n}\n\ninterface NodeCompletedEvent {\n type: \"completed\";\n stepIndex?: number;\n result: { success: boolean; errorMessage?: string; source?: string };\n}\n\ninterface RunCompleteEvent {\n type: \"run-complete\";\n stepsExecuted: number;\n totalSteps: number;\n stoppedEarly: boolean;\n reason?: string;\n}\n\ntype DebugEvent =\n | StepStartedEvent\n | NodeCompletedEvent\n | RunCompleteEvent\n | { type: string; [key: string]: unknown };\n\nexport async function runDebugWorkflow(argv: string[]): Promise<void> {\n const workflowId = argv.find((arg) => !arg.startsWith(\"-\"));\n\n if (!workflowId) {\n console.error(\"Usage: canary debug <workflowId> [--to-step N] [--env local|dev|prod]\");\n process.exit(1);\n }\n\n const toStepStr = getArgValue(argv, \"--to-step\");\n const toStep = toStepStr ? parseInt(toStepStr, 10) : undefined;\n const verbose = hasFlag(argv, \"--verbose\", \"-v\");\n\n if (toStep !== undefined && (isNaN(toStep) || toStep < 1)) {\n console.error(\"Error: --to-step must be a positive integer\");\n process.exit(1);\n }\n\n const { apiUrl, token } = await resolveConfig(argv);\n\n // 1. Create local browser session\n console.log(\"Creating local browser session...\");\n\n let localSession: CreateSessionResponse;\n try {\n const res = await fetch(`${apiUrl}/local-browser/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ browserMode: \"playwright\" }),\n });\n\n if (!res.ok) {\n const text = await res.text();\n console.error(`Failed to create local browser session: ${res.status} ${text}`);\n process.exit(1);\n }\n\n localSession = (await res.json()) as CreateSessionResponse;\n if (!localSession.ok) {\n console.error(`Failed to create session: ${localSession.error}`);\n process.exit(1);\n }\n } catch (err) {\n console.error(`Failed to connect to API: ${err}`);\n process.exit(1);\n }\n\n // 2. Create debug session (before browser launch so we can download storage state)\n console.log(\"Loading workflow...\");\n\n let debugSession: DebugSessionResponse;\n try {\n const res = await fetch(`${apiUrl}/cli/debug/sessions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n workflowId,\n localBrowserSessionId: localSession.sessionId,\n }),\n });\n\n if (!res.ok) {\n const text = await res.text();\n console.error(`Failed to create debug session: ${res.status} ${text}`);\n process.exit(1);\n }\n\n debugSession = (await res.json()) as DebugSessionResponse;\n if (!debugSession.ok || !debugSession.sessionId) {\n console.error(`Failed to create debug session: ${debugSession.error}`);\n process.exit(1);\n }\n } catch (err) {\n console.error(`Failed to create debug session: ${err}`);\n process.exit(1);\n }\n\n let debugSessionId: string | null = debugSession.sessionId;\n\n // 3. Download storage state if the workflow has valid credentials\n let storageStatePath: string | undefined;\n if (debugSession.isAuthenticated && debugSession.credential) {\n console.log(\"Downloading storage state...\");\n storageStatePath = await downloadStorageState({\n apiUrl,\n token,\n propertyId: debugSession.credential.propertyId,\n credentialId: debugSession.credential.credentialId,\n prefix: \"canary-debug-ss\",\n });\n if (storageStatePath) {\n console.log(\"Storage state loaded.\");\n } else {\n console.warn(\"Could not download storage state, continuing without it.\");\n }\n }\n\n // 4. Launch headed browser with storage state\n console.log(\"Launching headed browser...\");\n\n const host = new LocalBrowserHost({\n apiUrl,\n wsToken: localSession.wsToken,\n sessionId: localSession.sessionId,\n browserMode: \"playwright\",\n headless: false,\n storageStatePath,\n onLog: (level, message, data) => {\n if (verbose) {\n const prefix = `[${level.toUpperCase()}]`;\n if (data) {\n console.log(prefix, message, data);\n } else {\n console.log(prefix, message);\n }\n }\n },\n });\n\n // Set up cleanup\n const cleanup = async () => {\n console.log(\"\\nShutting down...\");\n\n if (debugSessionId) {\n try {\n await fetch(`${apiUrl}/cli/debug/sessions/${debugSessionId}`, {\n method: \"DELETE\",\n headers: { Authorization: `Bearer ${token}` },\n });\n } catch {\n // Ignore cleanup errors\n }\n }\n\n if (storageStatePath) {\n await fs.unlink(storageStatePath).catch(() => {});\n }\n\n await host.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => void cleanup());\n process.on(\"SIGTERM\", () => void cleanup());\n\n try {\n await host.start();\n } catch (err) {\n console.error(`Failed to start local browser: ${err}`);\n await host.stop();\n process.exit(1);\n }\n\n console.log(\"Browser connected.\");\n console.log();\n\n const nodes = debugSession.nodes ?? [];\n const totalSteps = nodes.length;\n const effectiveToStep = toStep ? Math.min(toStep, totalSteps) : totalSteps;\n\n console.log(`Debugging: \"${debugSession.workflowName}\" (${totalSteps} steps)`);\n if (toStep) {\n console.log(`Running steps 1-${effectiveToStep} of ${totalSteps}`);\n }\n console.log();\n\n // 5. Run steps via SSE\n let runRes: Response;\n try {\n runRes = await fetch(`${apiUrl}/cli/debug/sessions/${debugSessionId}/run`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({ toStep: effectiveToStep }),\n });\n } catch (err) {\n console.error(`Failed to start execution: ${err}`);\n await cleanup();\n return;\n }\n\n if (!runRes.ok || !runRes.body) {\n console.error(`Failed to start execution: ${runRes.status}`);\n await cleanup();\n return;\n }\n\n // Track execution state\n let currentStep = 0;\n let hasError = false;\n const stepResults = new Map<number, { name: string; success: boolean; source?: string }>();\n\n const parser = createParser({\n onEvent: (event: EventSourceMessage) => {\n if (!event.data) return;\n\n try {\n const data = JSON.parse(event.data) as DebugEvent;\n\n if (verbose) {\n console.log(`[SSE] ${JSON.stringify(data)}`);\n }\n\n if (data.type === \"step-started\") {\n const e = data as StepStartedEvent;\n currentStep = e.stepIndex;\n process.stdout.write(`[${e.stepIndex}/${e.totalSteps}] ${e.stepName} `);\n }\n\n if (data.type === \"completed\") {\n const e = data as NodeCompletedEvent;\n const stepIndex = e.stepIndex ?? currentStep;\n const success = e.result.success;\n const source = e.result.source;\n\n if (success) {\n const sourceLabel = source === \"cache\" ? \"(cache)\" : source === \"agent\" ? \"(agent)\" : \"\";\n console.log(`\\u2713 ${sourceLabel}`);\n } else {\n console.log(\"\\u2717\");\n if (e.result.errorMessage) {\n console.log(` Error: ${e.result.errorMessage.slice(0, 200)}`);\n }\n hasError = true;\n }\n\n stepResults.set(stepIndex, {\n name: `Step ${stepIndex}`,\n success,\n source,\n });\n }\n\n if (data.type === \"run-complete\") {\n const e = data as RunCompleteEvent;\n console.log();\n if (e.stoppedEarly) {\n console.log(\n `Stopped at step ${e.stepsExecuted} of ${e.totalSteps}. ${e.reason === \"step-failed\" ? \"Step failed.\" : \"Error occurred.\"}`\n );\n } else {\n console.log(\n `All ${e.stepsExecuted} step(s) completed.`\n );\n }\n }\n\n if (data.type === \"run-error\") {\n const errorData = data as { error?: string };\n console.log(`\\u2717`);\n if (errorData.error) {\n console.log(` Error: ${String(errorData.error).slice(0, 200)}`);\n }\n hasError = true;\n }\n } catch {\n // Ignore parse errors\n }\n },\n });\n\n const reader = runRes.body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n parser.feed(decoder.decode(value, { stream: true }));\n }\n } finally {\n reader.releaseLock();\n }\n\n // 6. Keep browser open for inspection\n console.log();\n console.log(\"Browser is open for inspection.\");\n console.log(\"Press Ctrl+C to close.\");\n\n // Keep the process running until Ctrl+C\n await new Promise(() => {});\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@ import { createRequire as __cr } from "module"; const require = __cr(import.meta
|
|
|
2
2
|
import {
|
|
3
3
|
apiRequest,
|
|
4
4
|
fetchList
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ERSNYLMZ.js";
|
|
6
6
|
import {
|
|
7
7
|
getArgValue,
|
|
8
8
|
hasFlag,
|
|
@@ -270,4 +270,4 @@ async function runDocs(argv) {
|
|
|
270
270
|
export {
|
|
271
271
|
runDocs
|
|
272
272
|
};
|
|
273
|
-
//# sourceMappingURL=docs-
|
|
273
|
+
//# sourceMappingURL=docs-BEE3LOCO.js.map
|
|
@@ -4,12 +4,13 @@ import {
|
|
|
4
4
|
fetchList,
|
|
5
5
|
parseLifecycleStage,
|
|
6
6
|
toLifecycleLabel
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ERSNYLMZ.js";
|
|
8
8
|
import {
|
|
9
9
|
getArgValue,
|
|
10
10
|
hasFlag,
|
|
11
11
|
resolveConfig
|
|
12
12
|
} from "./chunk-PWWQGYFG.js";
|
|
13
|
+
import "./chunk-XAA5VQ5N.js";
|
|
13
14
|
import "./chunk-VKVL7WBN.js";
|
|
14
15
|
|
|
15
16
|
// src/feature-flag.ts
|
|
@@ -276,4 +277,4 @@ async function runFeatureFlag(argv) {
|
|
|
276
277
|
export {
|
|
277
278
|
runFeatureFlag
|
|
278
279
|
};
|
|
279
|
-
//# sourceMappingURL=feature-flag-
|
|
280
|
+
//# sourceMappingURL=feature-flag-CYTDV4ZB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feature-flag.ts"],"sourcesContent":["/**\n * CLI Feature Flag Management\n *\n * Allows superadmins to manage feature flags via the CLI.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig, getArgValue, hasFlag } from \"./auth.js\";\nimport {\n type LifecycleStage,\n toLifecycleLabel,\n parseLifecycleStage,\n apiRequest,\n fetchList,\n} from \"./cli-helpers.js\";\n\ntype FeatureFlag = {\n id: string;\n name: string;\n description: string | null;\n lifecycleStage: LifecycleStage;\n finalValue: boolean | null;\n createdAt: string;\n organizations?: Array<{\n gateId: string;\n orgId: string;\n orgName: string;\n createdAt: string;\n }>;\n users?: Array<{\n gateId: string;\n userId: string;\n userEmail: string | null;\n createdAt: string;\n }>;\n};\n\ntype FlagApiResponse = {\n ok: boolean;\n error?: string;\n flag?: FeatureFlag;\n};\n\nfunction fetchFlags(apiUrl: string, token: string): Promise<FeatureFlag[]> {\n return fetchList<FeatureFlag>(apiUrl, token, \"/superadmin/feature-flags\", \"flags\");\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, \"--json\");\n const flags = await fetchFlags(apiUrl, token);\n\n if (jsonOutput) {\n console.log(JSON.stringify(flags, null, 2));\n return;\n }\n\n if (flags.length === 0) {\n console.log(\"No feature flags found.\");\n return;\n }\n\n for (const flag of flags) {\n const orgCount = flag.organizations?.length ?? 0;\n const userCount = flag.users?.length ?? 0;\n const lifecycle = `lifecycle=${toLifecycleLabel(flag.lifecycleStage)}`;\n const finalValue =\n flag.lifecycleStage === \"active\" ? \"\" : ` final=${flag.finalValue === true ? \"true\" : \"false\"}`;\n console.log(` ${flag.name} ${flag.description ?? \"\"} (${lifecycle}${finalValue}) [orgs=${orgCount}, users=${userCount}]`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag create <name> [--description <text>]\");\n process.exit(1);\n }\n\n const description = getArgValue(argv, \"--description\") ?? null;\n const result = await apiRequest<FlagApiResponse>(apiUrl, token, \"POST\", \"/superadmin/feature-flags\", {\n name,\n description,\n });\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created feature flag: ${name}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag delete <name>\");\n process.exit(1);\n }\n\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\", `/superadmin/feature-flags/${encodeURIComponent(name)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted feature flag: ${name}`);\n}\n\nasync function handleEnable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n const userId = getArgValue(argv, \"--user\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag enable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId && userId) {\n console.error(\"Error: Provide either --org or --user, not both.\");\n process.exit(1);\n }\n\n if (!orgId && !userId) {\n console.error(\"Error: Provide either --org <orgId> or --user <userId>.\");\n console.error(\"Usage: canary feature-flag enable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId) {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Enabled ${name} for org ${orgId}`);\n } else {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/users/${encodeURIComponent(userId!)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Enabled ${name} for user ${userId}`);\n }\n}\n\nasync function handleDisable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n const userId = getArgValue(argv, \"--user\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag disable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId && userId) {\n console.error(\"Error: Provide either --org or --user, not both.\");\n process.exit(1);\n }\n\n if (!orgId && !userId) {\n console.error(\"Error: Provide either --org <orgId> or --user <userId>.\");\n console.error(\"Usage: canary feature-flag disable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId) {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Disabled ${name} for org ${orgId}`);\n } else {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/users/${encodeURIComponent(userId!)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Disabled ${name} for user ${userId}`);\n }\n}\n\nasync function handleLifecycle(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag lifecycle <name> --stage <active|deprecated|ready_for_cleanup> [--final-value true|false]\");\n process.exit(1);\n }\n\n const stage = parseLifecycleStage(argv);\n const rawFinalValue = getArgValue(argv, \"--final-value\");\n const clearFinalValue = hasFlag(argv, \"--clear-final-value\");\n\n if (rawFinalValue !== undefined && clearFinalValue) {\n console.error(\"Error: use either --final-value or --clear-final-value, not both.\");\n process.exit(1);\n }\n\n let finalValue: boolean | undefined = undefined;\n\n if (stage === \"active\") {\n if (rawFinalValue !== undefined) {\n console.error(\"Error: active stage does not accept --final-value.\");\n process.exit(1);\n }\n finalValue = undefined;\n } else {\n if (clearFinalValue) {\n console.error(\"Error: --clear-final-value can only be used with --stage active.\");\n process.exit(1);\n }\n if (!rawFinalValue) {\n console.error(\"Error: --final-value true|false is required for deprecated or ready_for_cleanup.\");\n process.exit(1);\n }\n if (rawFinalValue !== \"true\" && rawFinalValue !== \"false\") {\n console.error(\"Error: --final-value must be true or false.\");\n process.exit(1);\n }\n finalValue = rawFinalValue === \"true\";\n }\n\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/lifecycle`,\n { stage, finalValue }\n );\n\n if (!result.ok || !result.flag) {\n console.error(`Error: ${result.error ?? \"Failed to update lifecycle\"}`);\n process.exit(1);\n }\n\n const final =\n result.flag.lifecycleStage === \"active\"\n ? \"(none)\"\n : result.flag.finalValue === true\n ? \"true\"\n : \"false\";\n console.log(`Updated lifecycle for ${name}: stage=${toLifecycleLabel(result.flag.lifecycleStage)}, final=${final}`);\n}\n\nfunction printFeatureFlagHelp(): void {\n console.log(\n [\n \"Usage: canary feature-flag <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" list List all feature flags\",\n \" create <name> [--description <text>] Create a new flag\",\n \" delete <name> Delete a flag and all its gates\",\n \" enable <name> (--org <orgId> | --user <userId>)\",\n \" Enable a flag for an org or user\",\n \" disable <name> (--org <orgId> | --user <userId>)\",\n \" Disable a flag for an org or user\",\n \" lifecycle <name> --stage <stage> [--final-value true|false]\",\n \" Mark lifecycle + final value\",\n \"\",\n \"Stages: active, deprecated, ready_for_cleanup\",\n \"\",\n \"Options:\",\n \" --org <orgId> Target organization\",\n \" --user <userId> Target user\",\n \" --final-value <true|false> Final value for deprecated/ready_for_cleanup\",\n \" --clear-final-value Clear final value (only valid with --stage active)\",\n \" --env <env> Target environment (prod, dev, local)\",\n \" --json Output as JSON (list only)\",\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 runFeatureFlag(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printFeatureFlagHelp();\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 \"create\":\n await handleCreate(rest, apiUrl, token);\n break;\n case \"delete\":\n await handleDelete(rest, apiUrl, token);\n break;\n case \"enable\":\n await handleEnable(rest, apiUrl, token);\n break;\n case \"disable\":\n await handleDisable(rest, apiUrl, token);\n break;\n case \"lifecycle\":\n await handleLifecycle(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printFeatureFlagHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/feature-flag.ts"],"sourcesContent":["/**\n * CLI Feature Flag Management\n *\n * Allows superadmins to manage feature flags via the CLI.\n */\n\nimport process from \"node:process\";\nimport { resolveConfig, getArgValue, hasFlag } from \"./auth.js\";\nimport {\n type LifecycleStage,\n toLifecycleLabel,\n parseLifecycleStage,\n apiRequest,\n fetchList,\n} from \"./cli-helpers.js\";\n\ntype FeatureFlag = {\n id: string;\n name: string;\n description: string | null;\n lifecycleStage: LifecycleStage;\n finalValue: boolean | null;\n createdAt: string;\n organizations?: Array<{\n gateId: string;\n orgId: string;\n orgName: string;\n createdAt: string;\n }>;\n users?: Array<{\n gateId: string;\n userId: string;\n userEmail: string | null;\n createdAt: string;\n }>;\n};\n\ntype FlagApiResponse = {\n ok: boolean;\n error?: string;\n flag?: FeatureFlag;\n};\n\nfunction fetchFlags(apiUrl: string, token: string): Promise<FeatureFlag[]> {\n return fetchList<FeatureFlag>(apiUrl, token, \"/superadmin/feature-flags\", \"flags\");\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, \"--json\");\n const flags = await fetchFlags(apiUrl, token);\n\n if (jsonOutput) {\n console.log(JSON.stringify(flags, null, 2));\n return;\n }\n\n if (flags.length === 0) {\n console.log(\"No feature flags found.\");\n return;\n }\n\n for (const flag of flags) {\n const orgCount = flag.organizations?.length ?? 0;\n const userCount = flag.users?.length ?? 0;\n const lifecycle = `lifecycle=${toLifecycleLabel(flag.lifecycleStage)}`;\n const finalValue =\n flag.lifecycleStage === \"active\" ? \"\" : ` final=${flag.finalValue === true ? \"true\" : \"false\"}`;\n console.log(` ${flag.name} ${flag.description ?? \"\"} (${lifecycle}${finalValue}) [orgs=${orgCount}, users=${userCount}]`);\n }\n}\n\nasync function handleCreate(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag create <name> [--description <text>]\");\n process.exit(1);\n }\n\n const description = getArgValue(argv, \"--description\") ?? null;\n const result = await apiRequest<FlagApiResponse>(apiUrl, token, \"POST\", \"/superadmin/feature-flags\", {\n name,\n description,\n });\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Created feature flag: ${name}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag delete <name>\");\n process.exit(1);\n }\n\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\", `/superadmin/feature-flags/${encodeURIComponent(name)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted feature flag: ${name}`);\n}\n\nasync function handleEnable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n const userId = getArgValue(argv, \"--user\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag enable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId && userId) {\n console.error(\"Error: Provide either --org or --user, not both.\");\n process.exit(1);\n }\n\n if (!orgId && !userId) {\n console.error(\"Error: Provide either --org <orgId> or --user <userId>.\");\n console.error(\"Usage: canary feature-flag enable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId) {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Enabled ${name} for org ${orgId}`);\n } else {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/users/${encodeURIComponent(userId!)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Enabled ${name} for user ${userId}`);\n }\n}\n\nasync function handleDisable(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n const orgId = getArgValue(argv, \"--org\");\n const userId = getArgValue(argv, \"--user\");\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag disable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId && userId) {\n console.error(\"Error: Provide either --org or --user, not both.\");\n process.exit(1);\n }\n\n if (!orgId && !userId) {\n console.error(\"Error: Provide either --org <orgId> or --user <userId>.\");\n console.error(\"Usage: canary feature-flag disable <name> (--org <orgId> | --user <userId>)\");\n process.exit(1);\n }\n\n if (orgId) {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/organizations/${encodeURIComponent(orgId)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Disabled ${name} for org ${orgId}`);\n } else {\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"DELETE\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/users/${encodeURIComponent(userId!)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Disabled ${name} for user ${userId}`);\n }\n}\n\nasync function handleLifecycle(argv: string[], apiUrl: string, token: string): Promise<void> {\n const name = argv[0];\n\n if (!name || name.startsWith(\"--\")) {\n console.error(\"Error: Missing flag name.\");\n console.error(\"Usage: canary feature-flag lifecycle <name> --stage <active|deprecated|ready_for_cleanup> [--final-value true|false]\");\n process.exit(1);\n }\n\n const stage = parseLifecycleStage(argv);\n const rawFinalValue = getArgValue(argv, \"--final-value\");\n const clearFinalValue = hasFlag(argv, \"--clear-final-value\");\n\n if (rawFinalValue !== undefined && clearFinalValue) {\n console.error(\"Error: use either --final-value or --clear-final-value, not both.\");\n process.exit(1);\n }\n\n let finalValue: boolean | undefined = undefined;\n\n if (stage === \"active\") {\n if (rawFinalValue !== undefined) {\n console.error(\"Error: active stage does not accept --final-value.\");\n process.exit(1);\n }\n finalValue = undefined;\n } else {\n if (clearFinalValue) {\n console.error(\"Error: --clear-final-value can only be used with --stage active.\");\n process.exit(1);\n }\n if (!rawFinalValue) {\n console.error(\"Error: --final-value true|false is required for deprecated or ready_for_cleanup.\");\n process.exit(1);\n }\n if (rawFinalValue !== \"true\" && rawFinalValue !== \"false\") {\n console.error(\"Error: --final-value must be true or false.\");\n process.exit(1);\n }\n finalValue = rawFinalValue === \"true\";\n }\n\n const result = await apiRequest<FlagApiResponse>(\n apiUrl, token, \"POST\",\n `/superadmin/feature-flags/${encodeURIComponent(name)}/lifecycle`,\n { stage, finalValue }\n );\n\n if (!result.ok || !result.flag) {\n console.error(`Error: ${result.error ?? \"Failed to update lifecycle\"}`);\n process.exit(1);\n }\n\n const final =\n result.flag.lifecycleStage === \"active\"\n ? \"(none)\"\n : result.flag.finalValue === true\n ? \"true\"\n : \"false\";\n console.log(`Updated lifecycle for ${name}: stage=${toLifecycleLabel(result.flag.lifecycleStage)}, final=${final}`);\n}\n\nfunction printFeatureFlagHelp(): void {\n console.log(\n [\n \"Usage: canary feature-flag <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" list List all feature flags\",\n \" create <name> [--description <text>] Create a new flag\",\n \" delete <name> Delete a flag and all its gates\",\n \" enable <name> (--org <orgId> | --user <userId>)\",\n \" Enable a flag for an org or user\",\n \" disable <name> (--org <orgId> | --user <userId>)\",\n \" Disable a flag for an org or user\",\n \" lifecycle <name> --stage <stage> [--final-value true|false]\",\n \" Mark lifecycle + final value\",\n \"\",\n \"Stages: active, deprecated, ready_for_cleanup\",\n \"\",\n \"Options:\",\n \" --org <orgId> Target organization\",\n \" --user <userId> Target user\",\n \" --final-value <true|false> Final value for deprecated/ready_for_cleanup\",\n \" --clear-final-value Clear final value (only valid with --stage active)\",\n \" --env <env> Target environment (prod, dev, local)\",\n \" --json Output as JSON (list only)\",\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 runFeatureFlag(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printFeatureFlagHelp();\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 \"create\":\n await handleCreate(rest, apiUrl, token);\n break;\n case \"delete\":\n await handleDelete(rest, apiUrl, token);\n break;\n case \"enable\":\n await handleEnable(rest, apiUrl, token);\n break;\n case \"disable\":\n await handleDisable(rest, apiUrl, token);\n break;\n case \"lifecycle\":\n await handleLifecycle(rest, apiUrl, token);\n break;\n default:\n console.error(`Unknown sub-command: ${subCommand}`);\n printFeatureFlagHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|