@canaryai/cli 0.1.13 → 0.2.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.
- package/dist/chunk-UEOXNF5X.js +371 -0
- package/dist/chunk-UEOXNF5X.js.map +1 -0
- package/dist/{feature-flag-MFTRYRYX.js → feature-flag-ESPSOSKG.js} +102 -16
- package/dist/feature-flag-ESPSOSKG.js.map +1 -0
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/{knobs-T3O4Z3ZB.js → knobs-HKONHY55.js} +148 -62
- package/dist/knobs-HKONHY55.js.map +1 -0
- package/dist/{local-browser-SYPTG6IQ.js → local-browser-MKKPBTYI.js} +2 -2
- package/dist/{mcp-TMD2R5Z6.js → mcp-4F4HI7L2.js} +2 -2
- package/package.json +2 -1
- package/dist/chunk-L26U3BST.js +0 -770
- package/dist/chunk-L26U3BST.js.map +0 -1
- package/dist/feature-flag-MFTRYRYX.js.map +0 -1
- package/dist/knobs-T3O4Z3ZB.js.map +0 -1
- /package/dist/{local-browser-SYPTG6IQ.js.map → local-browser-MKKPBTYI.js.map} +0 -0
- /package/dist/{mcp-TMD2R5Z6.js.map → mcp-4F4HI7L2.js.map} +0 -0
|
@@ -20,6 +20,63 @@ function getArgValue(argv, key) {
|
|
|
20
20
|
function hasFlag(argv, ...flags) {
|
|
21
21
|
return flags.some((flag) => argv.includes(flag));
|
|
22
22
|
}
|
|
23
|
+
function toLifecycleLabel(stage) {
|
|
24
|
+
switch (stage) {
|
|
25
|
+
case "deprecated":
|
|
26
|
+
return "deprecated";
|
|
27
|
+
case "ready_for_cleanup":
|
|
28
|
+
return "ready_for_cleanup";
|
|
29
|
+
default:
|
|
30
|
+
return "active";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function parseLifecycleStage(argv) {
|
|
34
|
+
const stage = getArgValue(argv, "--stage");
|
|
35
|
+
if (!stage || !["active", "deprecated", "ready_for_cleanup"].includes(stage)) {
|
|
36
|
+
console.error("Error: --stage is required and must be one of: active, deprecated, ready_for_cleanup");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return stage;
|
|
40
|
+
}
|
|
41
|
+
function formatValue(valueType, value) {
|
|
42
|
+
if (valueType === "json") {
|
|
43
|
+
return JSON.stringify(value);
|
|
44
|
+
}
|
|
45
|
+
return String(value);
|
|
46
|
+
}
|
|
47
|
+
function formatFinalValue(knob) {
|
|
48
|
+
if (knob.lifecycleStage === "active") {
|
|
49
|
+
return "(none)";
|
|
50
|
+
}
|
|
51
|
+
return formatValue(knob.valueType, knob.finalValue);
|
|
52
|
+
}
|
|
53
|
+
function parseTypedValue(raw, valueType) {
|
|
54
|
+
switch (valueType) {
|
|
55
|
+
case "boolean":
|
|
56
|
+
if (raw !== "true" && raw !== "false") {
|
|
57
|
+
console.error('Error: Boolean value must be "true" or "false".');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
return raw === "true";
|
|
61
|
+
case "string":
|
|
62
|
+
return raw;
|
|
63
|
+
case "number": {
|
|
64
|
+
const num = parseFloat(raw);
|
|
65
|
+
if (Number.isNaN(num)) {
|
|
66
|
+
console.error(`Error: Invalid number: ${raw}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
return num;
|
|
70
|
+
}
|
|
71
|
+
case "json":
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(raw);
|
|
74
|
+
} catch {
|
|
75
|
+
console.error(`Error: Invalid JSON: ${raw}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
23
80
|
async function resolveConfig(argv) {
|
|
24
81
|
const storedApiUrl = await readStoredApiUrl();
|
|
25
82
|
const env = getArgValue(argv, "--env");
|
|
@@ -54,14 +111,7 @@ async function apiRequest(apiUrl, token, method, path, body) {
|
|
|
54
111
|
const json = await res.json();
|
|
55
112
|
return json;
|
|
56
113
|
}
|
|
57
|
-
function
|
|
58
|
-
if (knob.valueType === "json") {
|
|
59
|
-
return JSON.stringify(knob.value);
|
|
60
|
-
}
|
|
61
|
-
return String(knob.value);
|
|
62
|
-
}
|
|
63
|
-
async function handleList(argv, apiUrl, token) {
|
|
64
|
-
const jsonOutput = hasFlag(argv, "--json");
|
|
114
|
+
async function fetchKnobs(apiUrl, token) {
|
|
65
115
|
const res = await fetch(`${apiUrl}/superadmin/knobs`, {
|
|
66
116
|
headers: { Authorization: `Bearer ${token}` }
|
|
67
117
|
});
|
|
@@ -75,7 +125,11 @@ async function handleList(argv, apiUrl, token) {
|
|
|
75
125
|
console.error(`Error: ${json.error}`);
|
|
76
126
|
process.exit(1);
|
|
77
127
|
}
|
|
78
|
-
|
|
128
|
+
return json.knobs ?? [];
|
|
129
|
+
}
|
|
130
|
+
async function handleList(argv, apiUrl, token) {
|
|
131
|
+
const jsonOutput = hasFlag(argv, "--json");
|
|
132
|
+
const knobs = await fetchKnobs(apiUrl, token);
|
|
79
133
|
if (jsonOutput) {
|
|
80
134
|
console.log(JSON.stringify(knobs, null, 2));
|
|
81
135
|
return;
|
|
@@ -86,7 +140,11 @@ async function handleList(argv, apiUrl, token) {
|
|
|
86
140
|
}
|
|
87
141
|
for (const knob of knobs) {
|
|
88
142
|
const desc = knob.description ? ` ${knob.description}` : "";
|
|
89
|
-
|
|
143
|
+
const lifecycle = `lifecycle=${toLifecycleLabel(knob.lifecycleStage)}`;
|
|
144
|
+
const finalValue = knob.lifecycleStage === "active" ? "" : ` final=${formatFinalValue(knob)}`;
|
|
145
|
+
console.log(
|
|
146
|
+
` ${knob.key} [${knob.valueType}] = ${formatValue(knob.valueType, knob.value)} (${lifecycle}${finalValue})${desc}`
|
|
147
|
+
);
|
|
90
148
|
}
|
|
91
149
|
}
|
|
92
150
|
async function handleGet(argv, apiUrl, token) {
|
|
@@ -97,20 +155,8 @@ async function handleGet(argv, apiUrl, token) {
|
|
|
97
155
|
process.exit(1);
|
|
98
156
|
}
|
|
99
157
|
const jsonOutput = hasFlag(argv, "--json");
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
});
|
|
103
|
-
if (res.status === 401) {
|
|
104
|
-
console.error("Error: Unauthorized. Your session may have expired.");
|
|
105
|
-
console.error("Run: canary login");
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
const json = await res.json();
|
|
109
|
-
if (!json.ok) {
|
|
110
|
-
console.error(`Error: ${json.error}`);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
const knob = (json.knobs ?? []).find((k) => k.key === key);
|
|
158
|
+
const knobs = await fetchKnobs(apiUrl, token);
|
|
159
|
+
const knob = knobs.find((k) => k.key === key);
|
|
114
160
|
if (!knob) {
|
|
115
161
|
console.error(`Knob not found: ${key}`);
|
|
116
162
|
process.exit(1);
|
|
@@ -121,7 +167,9 @@ async function handleGet(argv, apiUrl, token) {
|
|
|
121
167
|
}
|
|
122
168
|
console.log(` Key: ${knob.key}`);
|
|
123
169
|
console.log(` Type: ${knob.valueType}`);
|
|
124
|
-
console.log(` Value: ${formatValue(knob)}`);
|
|
170
|
+
console.log(` Value: ${formatValue(knob.valueType, knob.value)}`);
|
|
171
|
+
console.log(` Lifecycle: ${toLifecycleLabel(knob.lifecycleStage)}`);
|
|
172
|
+
console.log(` Final value: ${formatFinalValue(knob)}`);
|
|
125
173
|
console.log(` Description: ${knob.description ?? "(none)"}`);
|
|
126
174
|
console.log(` Updated: ${knob.updatedAt ?? "(never)"}`);
|
|
127
175
|
}
|
|
@@ -147,36 +195,7 @@ async function handleSet(argv, apiUrl, token) {
|
|
|
147
195
|
console.error("Error: --type is required and must be one of: boolean, string, number, json");
|
|
148
196
|
process.exit(1);
|
|
149
197
|
}
|
|
150
|
-
|
|
151
|
-
switch (valueType) {
|
|
152
|
-
case "boolean":
|
|
153
|
-
if (rawValue !== "true" && rawValue !== "false") {
|
|
154
|
-
console.error('Error: Boolean value must be "true" or "false".');
|
|
155
|
-
process.exit(1);
|
|
156
|
-
}
|
|
157
|
-
value = rawValue === "true";
|
|
158
|
-
break;
|
|
159
|
-
case "string":
|
|
160
|
-
value = rawValue;
|
|
161
|
-
break;
|
|
162
|
-
case "number": {
|
|
163
|
-
const num = parseFloat(rawValue);
|
|
164
|
-
if (Number.isNaN(num)) {
|
|
165
|
-
console.error(`Error: Invalid number: ${rawValue}`);
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
value = num;
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
case "json":
|
|
172
|
-
try {
|
|
173
|
-
value = JSON.parse(rawValue);
|
|
174
|
-
} catch {
|
|
175
|
-
console.error(`Error: Invalid JSON: ${rawValue}`);
|
|
176
|
-
process.exit(1);
|
|
177
|
-
}
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
198
|
+
const value = parseTypedValue(rawValue, valueType);
|
|
180
199
|
const description = getArgValue(argv, "--description") ?? void 0;
|
|
181
200
|
const result = await apiRequest(apiUrl, token, "POST", "/superadmin/knobs", {
|
|
182
201
|
key,
|
|
@@ -188,7 +207,7 @@ async function handleSet(argv, apiUrl, token) {
|
|
|
188
207
|
console.error(`Error: ${result.error}`);
|
|
189
208
|
process.exit(1);
|
|
190
209
|
}
|
|
191
|
-
console.log(`Set knob: ${key} = ${formatValue(result.knob)}`);
|
|
210
|
+
console.log(`Set knob: ${key} = ${formatValue(valueType, result.knob?.value)}`);
|
|
192
211
|
}
|
|
193
212
|
async function handleDelete(argv, apiUrl, token) {
|
|
194
213
|
const key = argv[0];
|
|
@@ -226,7 +245,66 @@ async function handleToggle(argv, apiUrl, token) {
|
|
|
226
245
|
console.error(`Error: ${result.error}`);
|
|
227
246
|
process.exit(1);
|
|
228
247
|
}
|
|
229
|
-
|
|
248
|
+
const knob = result.knob;
|
|
249
|
+
console.log(`Toggled knob: ${key} -> ${formatValue(knob?.valueType ?? "boolean", knob?.value)}`);
|
|
250
|
+
}
|
|
251
|
+
async function handleLifecycle(argv, apiUrl, token) {
|
|
252
|
+
const key = argv[0];
|
|
253
|
+
if (!key || key.startsWith("--")) {
|
|
254
|
+
console.error("Error: Missing knob key.");
|
|
255
|
+
console.error(
|
|
256
|
+
"Usage: canary knobs lifecycle <key> --stage <active|deprecated|ready_for_cleanup> [--final-value <value>]"
|
|
257
|
+
);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
const stage = parseLifecycleStage(argv);
|
|
261
|
+
const rawFinalValue = getArgValue(argv, "--final-value");
|
|
262
|
+
const clearFinalValue = hasFlag(argv, "--clear-final-value");
|
|
263
|
+
if (rawFinalValue !== void 0 && clearFinalValue) {
|
|
264
|
+
console.error("Error: use either --final-value or --clear-final-value, not both.");
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
const knobs = await fetchKnobs(apiUrl, token);
|
|
268
|
+
const knob = knobs.find((k) => k.key === key);
|
|
269
|
+
if (!knob) {
|
|
270
|
+
console.error(`Knob not found: ${key}`);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
let finalValue = void 0;
|
|
274
|
+
if (stage === "active") {
|
|
275
|
+
if (rawFinalValue !== void 0) {
|
|
276
|
+
console.error("Error: active stage does not accept --final-value. Use --stage deprecated|ready_for_cleanup.");
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
finalValue = clearFinalValue ? void 0 : void 0;
|
|
280
|
+
} else {
|
|
281
|
+
if (clearFinalValue) {
|
|
282
|
+
console.error("Error: --clear-final-value can only be used with --stage active.");
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
if (rawFinalValue === void 0) {
|
|
286
|
+
console.error("Error: --final-value is required when stage is deprecated or ready_for_cleanup.");
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
finalValue = parseTypedValue(rawFinalValue, knob.valueType);
|
|
290
|
+
}
|
|
291
|
+
const result = await apiRequest(
|
|
292
|
+
apiUrl,
|
|
293
|
+
token,
|
|
294
|
+
"POST",
|
|
295
|
+
`/superadmin/knobs/${encodeURIComponent(key)}/lifecycle`,
|
|
296
|
+
{
|
|
297
|
+
stage,
|
|
298
|
+
finalValue
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
if (!result.ok || !result.knob) {
|
|
302
|
+
console.error(`Error: ${result.error ?? "Failed to update lifecycle"}`);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
console.log(
|
|
306
|
+
`Updated lifecycle for ${key}: stage=${toLifecycleLabel(result.knob.lifecycleStage)}, final=${formatFinalValue(result.knob)}`
|
|
307
|
+
);
|
|
230
308
|
}
|
|
231
309
|
function printKnobsHelp() {
|
|
232
310
|
console.log(
|
|
@@ -240,14 +318,19 @@ function printKnobsHelp() {
|
|
|
240
318
|
" Set a knob value",
|
|
241
319
|
" delete <key> Delete a knob",
|
|
242
320
|
" toggle <key> Toggle a boolean knob",
|
|
321
|
+
" lifecycle <key> --stage <stage> [--final-value <value>]",
|
|
322
|
+
" Mark knob lifecycle + final value",
|
|
243
323
|
"",
|
|
244
324
|
"Types: boolean, string, number, json",
|
|
325
|
+
"Stages: active, deprecated, ready_for_cleanup",
|
|
245
326
|
"",
|
|
246
327
|
"Options:",
|
|
247
|
-
" --
|
|
248
|
-
" --
|
|
249
|
-
" --
|
|
250
|
-
" --
|
|
328
|
+
" --final-value <value> Final value for deprecated/ready_for_cleanup",
|
|
329
|
+
" --clear-final-value Clear final value (only valid with --stage active)",
|
|
330
|
+
" --env <env> Target environment (prod, dev, local)",
|
|
331
|
+
" --json Output as JSON (list/get only)",
|
|
332
|
+
" --api-url <url> API URL override (takes precedence over --env)",
|
|
333
|
+
" --token <key> API token override"
|
|
251
334
|
].join("\n")
|
|
252
335
|
);
|
|
253
336
|
}
|
|
@@ -274,6 +357,9 @@ async function runKnobs(argv) {
|
|
|
274
357
|
case "toggle":
|
|
275
358
|
await handleToggle(rest, apiUrl, token);
|
|
276
359
|
break;
|
|
360
|
+
case "lifecycle":
|
|
361
|
+
await handleLifecycle(rest, apiUrl, token);
|
|
362
|
+
break;
|
|
277
363
|
default:
|
|
278
364
|
console.error(`Unknown sub-command: ${subCommand}`);
|
|
279
365
|
printKnobsHelp();
|
|
@@ -283,4 +369,4 @@ async function runKnobs(argv) {
|
|
|
283
369
|
export {
|
|
284
370
|
runKnobs
|
|
285
371
|
};
|
|
286
|
-
//# sourceMappingURL=knobs-
|
|
372
|
+
//# sourceMappingURL=knobs-HKONHY55.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/knobs.ts"],"sourcesContent":["/**\n * CLI Knobs Management\n *\n * Allows superadmins to manage knobs (global config) via the CLI.\n */\n\nimport process from \"node:process\";\nimport { readStoredToken, readStoredApiUrl } from \"./auth.js\";\n\nconst ENV_URLS: Record<string, string> = {\n prod: \"https://api.trycanary.ai\",\n production: \"https://api.trycanary.ai\",\n dev: \"https://api.dev.trycanary.ai\",\n local: \"http://localhost:3000\",\n};\n\ntype LifecycleStage = \"active\" | \"deprecated\" | \"ready_for_cleanup\";\n\ntype SerializedKnob = {\n key: string;\n description: string | null;\n valueType: \"boolean\" | \"string\" | \"number\" | \"json\";\n value: unknown;\n lifecycleStage: LifecycleStage;\n finalValue: unknown;\n updatedAt: string | null;\n updatedBy: string | null;\n createdAt: string | null;\n};\n\ntype KnobListResponse = {\n ok: boolean;\n knobs?: SerializedKnob[];\n error?: string;\n};\n\ntype ApiResponse = {\n ok: boolean;\n error?: string;\n knob?: SerializedKnob;\n};\n\nfunction getArgValue(argv: string[], key: string): string | undefined {\n const index = argv.indexOf(key);\n if (index === -1 || index >= argv.length - 1) return undefined;\n return argv[index + 1];\n}\n\nfunction hasFlag(argv: string[], ...flags: string[]): boolean {\n return flags.some((flag) => argv.includes(flag));\n}\n\nfunction toLifecycleLabel(stage: LifecycleStage): string {\n switch (stage) {\n case \"deprecated\":\n return \"deprecated\";\n case \"ready_for_cleanup\":\n return \"ready_for_cleanup\";\n default:\n return \"active\";\n }\n}\n\nfunction parseLifecycleStage(argv: string[]): LifecycleStage {\n const stage = getArgValue(argv, \"--stage\");\n if (!stage || ![\"active\", \"deprecated\", \"ready_for_cleanup\"].includes(stage)) {\n console.error(\"Error: --stage is required and must be one of: active, deprecated, ready_for_cleanup\");\n process.exit(1);\n }\n return stage as LifecycleStage;\n}\n\nfunction formatValue(valueType: SerializedKnob[\"valueType\"], value: unknown): string {\n if (valueType === \"json\") {\n return JSON.stringify(value);\n }\n return String(value);\n}\n\nfunction formatFinalValue(knob: SerializedKnob): string {\n if (knob.lifecycleStage === \"active\") {\n return \"(none)\";\n }\n return formatValue(knob.valueType, knob.finalValue);\n}\n\nfunction parseTypedValue(raw: string, valueType: SerializedKnob[\"valueType\"]): unknown {\n switch (valueType) {\n case \"boolean\":\n if (raw !== \"true\" && raw !== \"false\") {\n console.error('Error: Boolean value must be \"true\" or \"false\".');\n process.exit(1);\n }\n return raw === \"true\";\n case \"string\":\n return raw;\n case \"number\": {\n const num = parseFloat(raw);\n if (Number.isNaN(num)) {\n console.error(`Error: Invalid number: ${raw}`);\n process.exit(1);\n }\n return num;\n }\n case \"json\":\n try {\n return JSON.parse(raw);\n } catch {\n console.error(`Error: Invalid JSON: ${raw}`);\n process.exit(1);\n }\n }\n}\n\nasync function resolveConfig(argv: string[]) {\n const storedApiUrl = await readStoredApiUrl();\n const env = getArgValue(argv, \"--env\");\n\n if (env && !ENV_URLS[env]) {\n console.error(`Unknown environment: ${env}`);\n console.error(\"Valid environments: prod, dev, local\");\n process.exit(1);\n }\n\n const apiUrl =\n getArgValue(argv, \"--api-url\") ??\n (env ? ENV_URLS[env] : undefined) ??\n process.env.CANARY_API_URL ??\n storedApiUrl ??\n \"https://api.trycanary.ai\";\n\n const token =\n getArgValue(argv, \"--token\") ?? process.env.CANARY_API_TOKEN ?? (await readStoredToken());\n\n if (!token) {\n console.error(\"Error: No API token found.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n return { apiUrl, token };\n}\n\nasync function apiRequest(\n apiUrl: string,\n token: string,\n method: string,\n path: string,\n body?: Record<string, unknown>\n): Promise<ApiResponse> {\n const res = await fetch(`${apiUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Your session may have expired.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n const json = (await res.json()) as ApiResponse;\n return json;\n}\n\nasync function fetchKnobs(apiUrl: string, token: string): Promise<SerializedKnob[]> {\n const res = await fetch(`${apiUrl}/superadmin/knobs`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (res.status === 401) {\n console.error(\"Error: Unauthorized. Your session may have expired.\");\n console.error(\"Run: canary login\");\n process.exit(1);\n }\n\n const json = (await res.json()) as KnobListResponse;\n\n if (!json.ok) {\n console.error(`Error: ${json.error}`);\n process.exit(1);\n }\n\n return json.knobs ?? [];\n}\n\nasync function handleList(argv: string[], apiUrl: string, token: string): Promise<void> {\n const jsonOutput = hasFlag(argv, \"--json\");\n const knobs = await fetchKnobs(apiUrl, token);\n\n if (jsonOutput) {\n console.log(JSON.stringify(knobs, null, 2));\n return;\n }\n\n if (knobs.length === 0) {\n console.log(\"No knobs found.\");\n return;\n }\n\n for (const knob of knobs) {\n const desc = knob.description ? ` ${knob.description}` : \"\";\n const lifecycle = `lifecycle=${toLifecycleLabel(knob.lifecycleStage)}`;\n const finalValue =\n knob.lifecycleStage === \"active\" ? \"\" : ` final=${formatFinalValue(knob)}`;\n console.log(\n ` ${knob.key} [${knob.valueType}] = ${formatValue(knob.valueType, knob.value)} (${lifecycle}${finalValue})${desc}`\n );\n }\n}\n\nasync function handleGet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const key = argv[0];\n if (!key || key.startsWith(\"--\")) {\n console.error(\"Error: Missing knob key.\");\n console.error(\"Usage: canary knobs get <key>\");\n process.exit(1);\n }\n\n const jsonOutput = hasFlag(argv, \"--json\");\n const knobs = await fetchKnobs(apiUrl, token);\n\n const knob = knobs.find((k) => k.key === key);\n\n if (!knob) {\n console.error(`Knob not found: ${key}`);\n process.exit(1);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(knob, null, 2));\n return;\n }\n\n console.log(` Key: ${knob.key}`);\n console.log(` Type: ${knob.valueType}`);\n console.log(` Value: ${formatValue(knob.valueType, knob.value)}`);\n console.log(` Lifecycle: ${toLifecycleLabel(knob.lifecycleStage)}`);\n console.log(` Final value: ${formatFinalValue(knob)}`);\n console.log(` Description: ${knob.description ?? \"(none)\"}`);\n console.log(` Updated: ${knob.updatedAt ?? \"(never)\"}`);\n}\n\nasync function handleSet(argv: string[], apiUrl: string, token: string): Promise<void> {\n const key = argv[0];\n if (!key || key.startsWith(\"--\")) {\n console.error(\"Error: Missing knob key.\");\n console.error(\n \"Usage: canary knobs set <key> <value> --type <boolean|string|number|json> [--description <text>]\"\n );\n process.exit(1);\n }\n\n const rawValue = argv[1];\n if (rawValue === undefined || rawValue.startsWith(\"--\")) {\n console.error(\"Error: Missing knob value.\");\n console.error(\n \"Usage: canary knobs set <key> <value> --type <boolean|string|number|json> [--description <text>]\"\n );\n process.exit(1);\n }\n\n const valueType = getArgValue(argv, \"--type\") as SerializedKnob[\"valueType\"] | undefined;\n if (!valueType || ![\"boolean\", \"string\", \"number\", \"json\"].includes(valueType)) {\n console.error(\"Error: --type is required and must be one of: boolean, string, number, json\");\n process.exit(1);\n }\n\n const value = parseTypedValue(rawValue, valueType);\n const description = getArgValue(argv, \"--description\") ?? undefined;\n\n const result = await apiRequest(apiUrl, token, \"POST\", \"/superadmin/knobs\", {\n key,\n valueType,\n value,\n description,\n });\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Set knob: ${key} = ${formatValue(valueType, result.knob?.value)}`);\n}\n\nasync function handleDelete(argv: string[], apiUrl: string, token: string): Promise<void> {\n const key = argv[0];\n if (!key || key.startsWith(\"--\")) {\n console.error(\"Error: Missing knob key.\");\n console.error(\"Usage: canary knobs delete <key>\");\n process.exit(1);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"DELETE\",\n `/superadmin/knobs/${encodeURIComponent(key)}`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n console.log(`Deleted knob: ${key}`);\n}\n\nasync function handleToggle(argv: string[], apiUrl: string, token: string): Promise<void> {\n const key = argv[0];\n if (!key || key.startsWith(\"--\")) {\n console.error(\"Error: Missing knob key.\");\n console.error(\"Usage: canary knobs toggle <key>\");\n process.exit(1);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"POST\",\n `/superadmin/knobs/${encodeURIComponent(key)}/toggle`\n );\n\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n process.exit(1);\n }\n\n const knob = result.knob;\n console.log(`Toggled knob: ${key} -> ${formatValue(knob?.valueType ?? \"boolean\", knob?.value)}`);\n}\n\nasync function handleLifecycle(argv: string[], apiUrl: string, token: string): Promise<void> {\n const key = argv[0];\n if (!key || key.startsWith(\"--\")) {\n console.error(\"Error: Missing knob key.\");\n console.error(\n \"Usage: canary knobs lifecycle <key> --stage <active|deprecated|ready_for_cleanup> [--final-value <value>]\"\n );\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 const knobs = await fetchKnobs(apiUrl, token);\n const knob = knobs.find((k) => k.key === key);\n\n if (!knob) {\n console.error(`Knob not found: ${key}`);\n process.exit(1);\n }\n\n let finalValue: unknown = undefined;\n\n if (stage === \"active\") {\n if (rawFinalValue !== undefined) {\n console.error(\"Error: active stage does not accept --final-value. Use --stage deprecated|ready_for_cleanup.\");\n process.exit(1);\n }\n finalValue = clearFinalValue ? undefined : 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 === undefined) {\n console.error(\"Error: --final-value is required when stage is deprecated or ready_for_cleanup.\");\n process.exit(1);\n }\n finalValue = parseTypedValue(rawFinalValue, knob.valueType);\n }\n\n const result = await apiRequest(\n apiUrl,\n token,\n \"POST\",\n `/superadmin/knobs/${encodeURIComponent(key)}/lifecycle`,\n {\n stage,\n finalValue,\n }\n );\n\n if (!result.ok || !result.knob) {\n console.error(`Error: ${result.error ?? \"Failed to update lifecycle\"}`);\n process.exit(1);\n }\n\n console.log(\n `Updated lifecycle for ${key}: stage=${toLifecycleLabel(result.knob.lifecycleStage)}, final=${formatFinalValue(result.knob)}`\n );\n}\n\nfunction printKnobsHelp(): void {\n console.log(\n [\n \"Usage: canary knobs <sub-command> [options]\",\n \"\",\n \"Sub-commands:\",\n \" list List all knobs\",\n \" get <key> Get a knob value\",\n \" set <key> <value> --type <type> [--description <text>]\",\n \" Set a knob value\",\n \" delete <key> Delete a knob\",\n \" toggle <key> Toggle a boolean knob\",\n \" lifecycle <key> --stage <stage> [--final-value <value>]\",\n \" Mark knob lifecycle + final value\",\n \"\",\n \"Types: boolean, string, number, json\",\n \"Stages: active, deprecated, ready_for_cleanup\",\n \"\",\n \"Options:\",\n \" --final-value <value> 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/get 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 runKnobs(argv: string[]): Promise<void> {\n const [subCommand, ...rest] = argv;\n\n if (!subCommand || subCommand === \"help\" || hasFlag(argv, \"--help\", \"-h\")) {\n printKnobsHelp();\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 case \"set\":\n await handleSet(rest, apiUrl, token);\n break;\n case \"delete\":\n await handleDelete(rest, apiUrl, token);\n break;\n case \"toggle\":\n await handleToggle(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 printKnobsHelp();\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LocalBrowserHost
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UEOXNF5X.js";
|
|
4
4
|
import {
|
|
5
5
|
readStoredToken
|
|
6
6
|
} from "./chunk-2T64Z2NI.js";
|
|
@@ -137,4 +137,4 @@ async function runLocalBrowser(args) {
|
|
|
137
137
|
export {
|
|
138
138
|
runLocalBrowser
|
|
139
139
|
};
|
|
140
|
-
//# sourceMappingURL=local-browser-
|
|
140
|
+
//# sourceMappingURL=local-browser-MKKPBTYI.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-V7U52ISX.js";
|
|
6
6
|
import {
|
|
7
7
|
LocalBrowserHost
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UEOXNF5X.js";
|
|
9
9
|
import {
|
|
10
10
|
readStoredToken
|
|
11
11
|
} from "./chunk-2T64Z2NI.js";
|
|
@@ -381,4 +381,4 @@ function formatReport(input) {
|
|
|
381
381
|
export {
|
|
382
382
|
runMcp
|
|
383
383
|
};
|
|
384
|
-
//# sourceMappingURL=mcp-
|
|
384
|
+
//# sourceMappingURL=mcp-4F4HI7L2.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canaryai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"ai": "^5.0.60",
|
|
46
46
|
"dotenv": "^17.2.3",
|
|
47
47
|
"eventsource-parser": "^3.0.0",
|
|
48
|
+
"@chatsdet/browser-core": "workspace:*",
|
|
48
49
|
"zod": "^4.1.12"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|