donebear 0.3.7 → 0.3.8
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/cli.mjs +240 -75
- package/dist/cli.mjs.map +1 -1
- package/dist/context-store-CK4yIl9e.mjs +3 -0
- package/dist/{context-store-DH561Z1u.mjs → context-store-DuCNavgl.mjs} +3 -3
- package/dist/{context-store-DH561Z1u.mjs.map → context-store-DuCNavgl.mjs.map} +1 -1
- package/dist/prompt-B7mDo4K7.mjs +3 -0
- package/dist/{prompt-BrfcK2Ry.mjs → prompt-GfcWO85b.mjs} +2 -2
- package/dist/prompt-GfcWO85b.mjs.map +1 -0
- package/package.json +8 -8
- package/dist/context-store-D0Z9vbaU.mjs +0 -3
- package/dist/prompt-BrfcK2Ry.mjs.map +0 -1
- package/dist/prompt-FRvfbinv.mjs +0 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as toCliError, b as DONEBEAR_TOKEN_ENV, d as DEFAULT_OAUTH_CALLBACK_PATH, f as DEFAULT_OAUTH_CALLBACK_PORT, i as EXIT_CODES, l as CONFIG_DIR, n as setCurrentWorkspace, o as AUTH_FILE_PATH, r as CliError, s as CLI_NAME, t as ensureLocalContext } from "./context-store-
|
|
3
|
-
import { n as readStdin, t as promptForValue } from "./prompt-
|
|
2
|
+
import { a as toCliError, b as DONEBEAR_TOKEN_ENV, d as DEFAULT_OAUTH_CALLBACK_PATH, f as DEFAULT_OAUTH_CALLBACK_PORT, i as EXIT_CODES, l as CONFIG_DIR, n as setCurrentWorkspace, o as AUTH_FILE_PATH, r as CliError, s as CLI_NAME, t as ensureLocalContext } from "./context-store-DuCNavgl.mjs";
|
|
3
|
+
import { n as readStdin, t as promptForValue } from "./prompt-GfcWO85b.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { Command, InvalidArgumentError } from "commander";
|
|
6
6
|
import { homedir } from "node:os";
|
|
@@ -18,13 +18,13 @@ import { fileURLToPath } from "node:url";
|
|
|
18
18
|
import Database from "better-sqlite3";
|
|
19
19
|
import { createInterface } from "node:readline";
|
|
20
20
|
//#region \0rolldown/runtime.js
|
|
21
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
21
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/jwt.ts
|
|
24
24
|
const parseJwtBase64Url = (input) => {
|
|
25
25
|
const normalized = input.replaceAll("-", "+").replaceAll("_", "/");
|
|
26
26
|
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
|
|
27
|
-
return Buffer.from(padded, "base64").toString("
|
|
27
|
+
return Buffer.from(padded, "base64").toString("utf-8");
|
|
28
28
|
};
|
|
29
29
|
const parseJwtClaims = (token) => {
|
|
30
30
|
const payloadPart = token.split(".").at(1);
|
|
@@ -115,7 +115,7 @@ const parseAuthFile = (payload) => {
|
|
|
115
115
|
};
|
|
116
116
|
const readStoredAuthSession = async () => {
|
|
117
117
|
try {
|
|
118
|
-
return parseAuthFile(await readFile(AUTH_FILE_PATH, "
|
|
118
|
+
return parseAuthFile(await readFile(AUTH_FILE_PATH, "utf-8")).session;
|
|
119
119
|
} catch (error) {
|
|
120
120
|
if (isRecord(error) && error.code === "ENOENT") return null;
|
|
121
121
|
if (error instanceof CliError) throw error;
|
|
@@ -132,7 +132,7 @@ const writeStoredAuthSession = async (session) => {
|
|
|
132
132
|
recursive: true
|
|
133
133
|
});
|
|
134
134
|
await writeFile(AUTH_FILE_PATH, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
135
|
-
encoding: "
|
|
135
|
+
encoding: "utf-8",
|
|
136
136
|
mode: 384
|
|
137
137
|
});
|
|
138
138
|
};
|
|
@@ -199,19 +199,6 @@ const tokenResponseToStoredSession = (response) => {
|
|
|
199
199
|
} : null
|
|
200
200
|
};
|
|
201
201
|
};
|
|
202
|
-
const getSupabaseUser = async (supabaseUrl, publishableKey, accessToken) => {
|
|
203
|
-
const response = await fetch(`${supabaseUrl}/auth/v1/user`, { headers: {
|
|
204
|
-
apikey: publishableKey,
|
|
205
|
-
authorization: `Bearer ${accessToken}`
|
|
206
|
-
} });
|
|
207
|
-
if (!response.ok) throw new CliError(`Failed to load user (${response.status})`, EXIT_CODES.ERROR);
|
|
208
|
-
const data = await response.json();
|
|
209
|
-
if (typeof data.id !== "string") throw new CliError("No user returned for current token", EXIT_CODES.ERROR);
|
|
210
|
-
return {
|
|
211
|
-
email: typeof data.email === "string" ? data.email : null,
|
|
212
|
-
id: data.id
|
|
213
|
-
};
|
|
214
|
-
};
|
|
215
202
|
//#endregion
|
|
216
203
|
//#region src/auth-session.ts
|
|
217
204
|
const expiryFromClaims = (claims) => {
|
|
@@ -346,8 +333,8 @@ const requestNdjson = async (context, endpoint, options) => {
|
|
|
346
333
|
};
|
|
347
334
|
//#endregion
|
|
348
335
|
//#region src/date-codecs.ts
|
|
349
|
-
const ISO_DATE_ONLY_REGEX = /^(\d{4})-(\d{2})-(\d{2})
|
|
350
|
-
const ISO_INSTANT_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})
|
|
336
|
+
const ISO_DATE_ONLY_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/u;
|
|
337
|
+
const ISO_INSTANT_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/u;
|
|
351
338
|
const pad = (value, length = 2) => String(value).padStart(length, "0");
|
|
352
339
|
const isFiniteEpoch = (value) => typeof value === "number" && Number.isFinite(value);
|
|
353
340
|
const isValidDateOnlyParts = (parts) => {
|
|
@@ -681,17 +668,17 @@ const WORKSPACE_HISTORY_QUERY = `
|
|
|
681
668
|
}
|
|
682
669
|
`;
|
|
683
670
|
const API_KEY_CREATE_MUTATION = `
|
|
684
|
-
mutation ApiKeyCreate($label: String!) {
|
|
685
|
-
apiKeyCreate(label: $label) {
|
|
671
|
+
mutation ApiKeyCreate($label: String!, $scopes: [String!], $workspaceIds: [ID!], $expiresAt: DateTime) {
|
|
672
|
+
apiKeyCreate(label: $label, scopes: $scopes, workspaceIds: $workspaceIds, expiresAt: $expiresAt) {
|
|
686
673
|
success lastSyncId
|
|
687
|
-
apiKey { id label keyPrefix createdAt }
|
|
674
|
+
apiKey { id label keyPrefix scopes workspaceIds expiresAt createdAt }
|
|
688
675
|
token
|
|
689
676
|
}
|
|
690
677
|
}
|
|
691
678
|
`;
|
|
692
679
|
const API_KEYS_QUERY = `
|
|
693
680
|
query ApiKeys {
|
|
694
|
-
apiKeys { id label keyPrefix lastUsedAt revokedAt createdAt }
|
|
681
|
+
apiKeys { id label keyPrefix scopes workspaceIds expiresAt lastUsedAt revokedAt createdAt }
|
|
695
682
|
}
|
|
696
683
|
`;
|
|
697
684
|
const API_KEY_REVOKE_MUTATION = `
|
|
@@ -875,11 +862,14 @@ const toWorkspaceHistoryEntryFromGraphqlNode = (node) => ({
|
|
|
875
862
|
});
|
|
876
863
|
const toApiKeyRecordFromGraphqlNode = (node) => ({
|
|
877
864
|
createdAt: node.createdAt,
|
|
865
|
+
expiresAt: node.expiresAt,
|
|
878
866
|
id: node.id,
|
|
879
867
|
keyPrefix: node.keyPrefix,
|
|
880
868
|
label: node.label,
|
|
881
869
|
lastUsedAt: node.lastUsedAt,
|
|
882
|
-
revokedAt: node.revokedAt
|
|
870
|
+
revokedAt: node.revokedAt,
|
|
871
|
+
scopes: node.scopes,
|
|
872
|
+
workspaceIds: node.workspaceIds
|
|
883
873
|
});
|
|
884
874
|
const toChecklistItemRecord = (value) => {
|
|
885
875
|
if (typeof value !== "object" || value === null) return null;
|
|
@@ -903,6 +893,26 @@ const resolveApiBaseUrl = (context) => {
|
|
|
903
893
|
if (fromContext) return normalizeApiUrl(fromContext);
|
|
904
894
|
return normalizeApiUrl(readEnvValue("DONEBEAR_API_URL") ?? "https://api.donebear.com");
|
|
905
895
|
};
|
|
896
|
+
const VIEWER_QUERY = `
|
|
897
|
+
query Viewer {
|
|
898
|
+
viewer {
|
|
899
|
+
id
|
|
900
|
+
email
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
`;
|
|
904
|
+
const loadViewer = async (context, options) => {
|
|
905
|
+
const data = await requestGraphql(context, `${options.baseUrl}/graphql`, {
|
|
906
|
+
query: VIEWER_QUERY,
|
|
907
|
+
token: options.token,
|
|
908
|
+
variables: {}
|
|
909
|
+
});
|
|
910
|
+
if (!data.viewer) throw new CliError("Could not resolve current user. The token may be invalid or revoked.", EXIT_CODES.AUTH_REQUIRED);
|
|
911
|
+
return {
|
|
912
|
+
email: data.viewer.email ?? null,
|
|
913
|
+
id: data.viewer.id
|
|
914
|
+
};
|
|
915
|
+
};
|
|
906
916
|
const listWorkspaces = async (context, options) => {
|
|
907
917
|
return (await requestGraphql(context, `${options.baseUrl}/graphql`, {
|
|
908
918
|
query: MY_WORKSPACES_QUERY,
|
|
@@ -1089,10 +1099,15 @@ const listWorkspaceHistory = async (context, options) => {
|
|
|
1089
1099
|
})).workspaceHistory.map(toWorkspaceHistoryEntryFromGraphqlNode);
|
|
1090
1100
|
};
|
|
1091
1101
|
const createApiKey = async (context, options) => {
|
|
1092
|
-
const
|
|
1102
|
+
const endpoint = `${options.baseUrl}/graphql`;
|
|
1103
|
+
const variables = { label: options.label };
|
|
1104
|
+
if (options.scopes !== void 0) variables.scopes = options.scopes;
|
|
1105
|
+
if (options.workspaceIds !== void 0) variables.workspaceIds = options.workspaceIds;
|
|
1106
|
+
if (options.expiresAt !== void 0) variables.expiresAt = options.expiresAt;
|
|
1107
|
+
const data = await requestGraphql(context, endpoint, {
|
|
1093
1108
|
query: API_KEY_CREATE_MUTATION,
|
|
1094
1109
|
token: options.token,
|
|
1095
|
-
variables
|
|
1110
|
+
variables
|
|
1096
1111
|
});
|
|
1097
1112
|
return {
|
|
1098
1113
|
...toApiKeyRecordFromGraphqlNode(data.apiKeyCreate.apiKey),
|
|
@@ -1140,10 +1155,13 @@ const resolveCommandContext = async (context) => {
|
|
|
1140
1155
|
token
|
|
1141
1156
|
};
|
|
1142
1157
|
};
|
|
1143
|
-
const requireUserId = (
|
|
1144
|
-
const
|
|
1145
|
-
if (
|
|
1146
|
-
return
|
|
1158
|
+
const requireUserId = async (context, commandContext) => {
|
|
1159
|
+
const claimUserId = commandContext.resolvedToken.user?.id ?? null;
|
|
1160
|
+
if (typeof claimUserId === "string" && claimUserId.length > 0) return claimUserId;
|
|
1161
|
+
return (await loadViewer(context, {
|
|
1162
|
+
baseUrl: commandContext.apiBaseUrl,
|
|
1163
|
+
token: commandContext.token
|
|
1164
|
+
})).id;
|
|
1147
1165
|
};
|
|
1148
1166
|
//#endregion
|
|
1149
1167
|
//#region src/options.ts
|
|
@@ -1238,20 +1256,68 @@ const runWithErrorHandling = async (context, action) => {
|
|
|
1238
1256
|
};
|
|
1239
1257
|
//#endregion
|
|
1240
1258
|
//#region src/commands/api-key.ts
|
|
1241
|
-
const
|
|
1259
|
+
const PERMISSION_SCOPES = {
|
|
1260
|
+
"full-access": [
|
|
1261
|
+
"read",
|
|
1262
|
+
"write",
|
|
1263
|
+
"admin"
|
|
1264
|
+
],
|
|
1265
|
+
"read-only": ["read"]
|
|
1266
|
+
};
|
|
1267
|
+
const parseDuration = (duration) => {
|
|
1268
|
+
const match = duration.match(/^(\d+)(d|y)$/u);
|
|
1269
|
+
if (!match) throw new CliError(`Invalid duration "${duration}". Use a format like "30d", "90d", or "1y".`, EXIT_CODES.VALIDATION);
|
|
1270
|
+
const [, rawAmount, unit] = match;
|
|
1271
|
+
const amount = Number(rawAmount);
|
|
1272
|
+
const now = /* @__PURE__ */ new Date();
|
|
1273
|
+
if (unit === "d") now.setDate(now.getDate() + amount);
|
|
1274
|
+
else now.setDate(now.getDate() + amount * 365);
|
|
1275
|
+
return now;
|
|
1276
|
+
};
|
|
1277
|
+
const runCreate = async (context, label, options) => {
|
|
1242
1278
|
const { token } = await requireAuthToken(context);
|
|
1279
|
+
const baseUrl = resolveApiBaseUrl(context);
|
|
1280
|
+
let scopes;
|
|
1281
|
+
if (options.permissions !== void 0) {
|
|
1282
|
+
const level = options.permissions;
|
|
1283
|
+
if (!PERMISSION_SCOPES[level]) throw new CliError(`Invalid permissions "${options.permissions}". Use "full-access" or "read-only".`, EXIT_CODES.VALIDATION);
|
|
1284
|
+
scopes = PERMISSION_SCOPES[level];
|
|
1285
|
+
}
|
|
1286
|
+
let workspaceIds;
|
|
1287
|
+
if (options.workspaces !== void 0) {
|
|
1288
|
+
const slugs = options.workspaces.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1289
|
+
if (slugs.length === 0) throw new CliError("No workspace slugs provided for --workspaces.", EXIT_CODES.VALIDATION);
|
|
1290
|
+
const allWorkspaces = await listWorkspaces(context, {
|
|
1291
|
+
baseUrl,
|
|
1292
|
+
token
|
|
1293
|
+
});
|
|
1294
|
+
workspaceIds = [];
|
|
1295
|
+
for (const slug of slugs) {
|
|
1296
|
+
const match = allWorkspaces.find((ws) => ws.urlKey === slug || ws.id === slug || ws.name.toLowerCase() === slug.toLowerCase());
|
|
1297
|
+
if (!match) throw new CliError(`Workspace "${slug}" not found. Run \`donebear workspace list\` to see available workspaces.`, EXIT_CODES.VALIDATION);
|
|
1298
|
+
workspaceIds.push(match.id);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
let expiresAt;
|
|
1302
|
+
if (options.expires !== void 0) expiresAt = parseDuration(options.expires).toISOString();
|
|
1243
1303
|
const key = await createApiKey(context, {
|
|
1244
|
-
baseUrl
|
|
1304
|
+
baseUrl,
|
|
1305
|
+
expiresAt,
|
|
1245
1306
|
label,
|
|
1246
|
-
|
|
1307
|
+
scopes,
|
|
1308
|
+
token,
|
|
1309
|
+
workspaceIds
|
|
1247
1310
|
});
|
|
1248
1311
|
if (context.json) {
|
|
1249
1312
|
writeOutput(context, {
|
|
1250
1313
|
createdAt: key.createdAt,
|
|
1314
|
+
expiresAt: key.expiresAt,
|
|
1251
1315
|
id: key.id,
|
|
1252
1316
|
keyPrefix: key.keyPrefix,
|
|
1253
1317
|
label: key.label,
|
|
1254
|
-
|
|
1318
|
+
scopes: key.scopes,
|
|
1319
|
+
token: key.token,
|
|
1320
|
+
workspaceIds: key.workspaceIds
|
|
1255
1321
|
});
|
|
1256
1322
|
return;
|
|
1257
1323
|
}
|
|
@@ -1259,6 +1325,10 @@ const runCreate = async (context, label) => {
|
|
|
1259
1325
|
writeInfo(context, "");
|
|
1260
1326
|
writeInfo(context, ` ${key.token}`);
|
|
1261
1327
|
writeInfo(context, "");
|
|
1328
|
+
writeInfo(context, ` Scopes: ${key.scopes.join(", ")}`);
|
|
1329
|
+
if (key.workspaceIds && key.workspaceIds.length > 0) writeInfo(context, ` Restricted to workspaces: ${key.workspaceIds.join(", ")}`);
|
|
1330
|
+
if (key.expiresAt) writeInfo(context, ` Expires: ${new Date(key.expiresAt).toLocaleDateString()}`);
|
|
1331
|
+
writeInfo(context, "");
|
|
1262
1332
|
writeWarning(context, "Save this key now — it will not be shown again.");
|
|
1263
1333
|
};
|
|
1264
1334
|
const runList = async (context) => {
|
|
@@ -1278,7 +1348,10 @@ const runList = async (context) => {
|
|
|
1278
1348
|
for (const key of keys) {
|
|
1279
1349
|
const status = key.revokedAt ? " (revoked)" : "";
|
|
1280
1350
|
const lastUsed = key.lastUsedAt ? `Last used: ${new Date(key.lastUsedAt).toLocaleDateString()}` : "Never used";
|
|
1281
|
-
|
|
1351
|
+
const scopeStr = `[${key.scopes.join(",")}]`;
|
|
1352
|
+
const wsStr = key.workspaceIds && key.workspaceIds.length > 0 ? ` ws:${key.workspaceIds.length}` : "";
|
|
1353
|
+
const expStr = key.expiresAt ? ` exp:${new Date(key.expiresAt).toLocaleDateString()}` : "";
|
|
1354
|
+
writeInfo(context, `${key.keyPrefix}... ${key.label} ${scopeStr}${wsStr}${expStr} ${lastUsed}${status} [${key.id}]`);
|
|
1282
1355
|
}
|
|
1283
1356
|
};
|
|
1284
1357
|
const runRevoke = async (context, keyId) => {
|
|
@@ -1301,6 +1374,8 @@ const registerApiKeyCommands = (program) => {
|
|
|
1301
1374
|
const apiKey = program.command("api-key").alias("key").description("Manage personal API keys").addHelpText("after", `
|
|
1302
1375
|
Examples:
|
|
1303
1376
|
donebear api-key create "Raycast"
|
|
1377
|
+
donebear api-key create "CI" --permissions read-only --expires 90d
|
|
1378
|
+
donebear api-key create "Scoped" --workspaces my-org,side-project --expires 1y
|
|
1304
1379
|
donebear api-key list
|
|
1305
1380
|
donebear api-key revoke <key-id>
|
|
1306
1381
|
`).action(async (_options, command) => {
|
|
@@ -1309,10 +1384,10 @@ Examples:
|
|
|
1309
1384
|
await runList(context);
|
|
1310
1385
|
});
|
|
1311
1386
|
});
|
|
1312
|
-
apiKey.command("create <label>").description("Create a new personal API key").action(async (label,
|
|
1387
|
+
apiKey.command("create <label>").description("Create a new personal API key").option("--permissions <value>", "Permission level: \"full-access\" or \"read-only\"", "full-access").option("--workspaces <slugs>", "Comma-separated workspace slugs to restrict the key to").option("--expires <duration>", "Expiration duration, e.g. \"30d\", \"90d\", \"1y\"").action(async (label, options, command) => {
|
|
1313
1388
|
const context = contextFromCommand(command);
|
|
1314
1389
|
await runWithErrorHandling(context, async () => {
|
|
1315
|
-
await runCreate(context, label);
|
|
1390
|
+
await runCreate(context, label, options);
|
|
1316
1391
|
});
|
|
1317
1392
|
});
|
|
1318
1393
|
apiKey.command("list").description("List all personal API keys").action(async (_options, command) => {
|
|
@@ -1669,7 +1744,7 @@ const resolveTaskView = (task) => {
|
|
|
1669
1744
|
const formatEpochDate = (epochMs) => formatInstantEpoch(epochMs);
|
|
1670
1745
|
//#endregion
|
|
1671
1746
|
//#region src/command-helpers.ts
|
|
1672
|
-
const SHORT_ID_SUFFIX_PATTERN = /-([a-f0-9]{8})
|
|
1747
|
+
const SHORT_ID_SUFFIX_PATTERN = /-([a-f0-9]{8})$/u;
|
|
1673
1748
|
/**
|
|
1674
1749
|
* Find a record by reference: exact ID, key, ID prefix, slug shortId, or name.
|
|
1675
1750
|
* Works for any entity with id, key, and name fields.
|
|
@@ -1723,7 +1798,7 @@ const taskListLines = (tasks) => tasks.map((task) => {
|
|
|
1723
1798
|
});
|
|
1724
1799
|
//#endregion
|
|
1725
1800
|
//#region src/workspace-context.ts
|
|
1726
|
-
const WORKSPACE_URL_KEY_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)
|
|
1801
|
+
const WORKSPACE_URL_KEY_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
1727
1802
|
const fetchWorkspaces = async (context, options) => {
|
|
1728
1803
|
const workspaces = await listWorkspaces(context, {
|
|
1729
1804
|
baseUrl: options.apiBaseUrl,
|
|
@@ -1782,7 +1857,7 @@ const byReference = (workspaces, reference) => {
|
|
|
1782
1857
|
return null;
|
|
1783
1858
|
};
|
|
1784
1859
|
const toWorkspaceUrlKey = (name) => {
|
|
1785
|
-
return name.trim().toLowerCase().replaceAll(/[^a-z0-9]+/
|
|
1860
|
+
return name.trim().toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-").replaceAll(/^-+|-+$/gu, "").replaceAll(/-{2,}/gu, "-").slice(0, 50);
|
|
1786
1861
|
};
|
|
1787
1862
|
const isValidWorkspaceUrlKey = (value) => WORKSPACE_URL_KEY_REGEX.test(value) && value.length >= 3;
|
|
1788
1863
|
const resolveWorkspace = async (context, options) => {
|
|
@@ -1993,7 +2068,7 @@ const checkAuth = async (context) => {
|
|
|
1993
2068
|
};
|
|
1994
2069
|
const checkWorkspace = async () => {
|
|
1995
2070
|
try {
|
|
1996
|
-
const { ensureLocalContext } = await import("./context-store-
|
|
2071
|
+
const { ensureLocalContext } = await import("./context-store-CK4yIl9e.mjs");
|
|
1997
2072
|
const localContext = await ensureLocalContext();
|
|
1998
2073
|
if (!localContext.workspaceId) return {
|
|
1999
2074
|
message: "No workspace selected (run `donebear workspace use`)",
|
|
@@ -2225,7 +2300,7 @@ const bytesToUuid = (bytes) => {
|
|
|
2225
2300
|
};
|
|
2226
2301
|
const createUuidV5 = (name, namespace) => {
|
|
2227
2302
|
const namespaceBytes = uuidToBytes(namespace);
|
|
2228
|
-
const hash = createHash("sha1").update(namespaceBytes).update(Buffer.from(name, "
|
|
2303
|
+
const hash = createHash("sha1").update(namespaceBytes).update(Buffer.from(name, "utf-8")).digest();
|
|
2229
2304
|
const bytes = Uint8Array.from(hash.subarray(0, 16));
|
|
2230
2305
|
const versionByte = bytes.at(6);
|
|
2231
2306
|
const variantByte = bytes.at(8);
|
|
@@ -2665,7 +2740,6 @@ var import_rrule = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
2665
2740
|
};
|
|
2666
2741
|
return __assign.apply(this, arguments);
|
|
2667
2742
|
};
|
|
2668
|
-
Object.create;
|
|
2669
2743
|
function __spreadArray(to, from, pack) {
|
|
2670
2744
|
if (pack || arguments.length === 2) {
|
|
2671
2745
|
for (var i = 0, l = from.length, ar; i < l; i++) if (ar || !(i in from)) {
|
|
@@ -2678,7 +2752,6 @@ var import_rrule = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
2678
2752
|
function __await(v) {
|
|
2679
2753
|
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
|
2680
2754
|
}
|
|
2681
|
-
Object.create;
|
|
2682
2755
|
const callbackiterresult = function(_super) {
|
|
2683
2756
|
__extends(CallbackIterResult, _super);
|
|
2684
2757
|
function CallbackIterResult(method, args, iterator) {
|
|
@@ -3515,7 +3588,8 @@ var import_rrule = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
3515
3588
|
this.month += months;
|
|
3516
3589
|
if (this.month > 12) {
|
|
3517
3590
|
var yearDiv = Math.floor(this.month / 12);
|
|
3518
|
-
|
|
3591
|
+
var monthMod = pymod(this.month, 12);
|
|
3592
|
+
this.month = monthMod;
|
|
3519
3593
|
this.year += yearDiv;
|
|
3520
3594
|
if (this.month === 0) {
|
|
3521
3595
|
this.month = 12;
|
|
@@ -4134,8 +4208,7 @@ var import_rrule = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
4134
4208
|
var month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
4135
4209
|
var day = (h + l - 7 * m + 114) % 31 + 1;
|
|
4136
4210
|
var date = Date.UTC(y, month - 1, day + offset);
|
|
4137
|
-
|
|
4138
|
-
return [Math.ceil((date - yearStart) / (1e3 * 60 * 60 * 24))];
|
|
4211
|
+
return [Math.ceil((date - Date.UTC(y, 0, 1)) / (1e3 * 60 * 60 * 24))];
|
|
4139
4212
|
}
|
|
4140
4213
|
const iterinfo = function() {
|
|
4141
4214
|
function Iterinfo(options) {
|
|
@@ -4461,7 +4534,8 @@ var import_rrule = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
4461
4534
|
if (noCache === void 0) noCache = false;
|
|
4462
4535
|
this._cache = noCache ? null : new Cache();
|
|
4463
4536
|
this.origOptions = initializeOptions(options);
|
|
4464
|
-
|
|
4537
|
+
var parsedOptions = parseOptions(options).parsedOptions;
|
|
4538
|
+
this.options = parsedOptions;
|
|
4465
4539
|
}
|
|
4466
4540
|
RRule.parseText = function(text, language) {
|
|
4467
4541
|
return parseText(text, language);
|
|
@@ -5152,17 +5226,17 @@ const THINGS_WEEKDAY_TO_RRULE = [
|
|
|
5152
5226
|
"SA"
|
|
5153
5227
|
];
|
|
5154
5228
|
const parseNumericPlistField = (xml, key) => {
|
|
5155
|
-
const match = new RegExp(`<key>${key}</key>\\s*<(integer|real)>([^<]+)</\\1
|
|
5229
|
+
const match = new RegExp(`<key>${key}</key>\\s*<(integer|real)>([^<]+)</\\1>`, "u").exec(xml);
|
|
5156
5230
|
if (!match?.[2]) return null;
|
|
5157
5231
|
const parsed = Number(match[2]);
|
|
5158
5232
|
return Number.isFinite(parsed) ? parsed : null;
|
|
5159
5233
|
};
|
|
5160
|
-
const PLIST_OFFSETS_ARRAY_PATTERN = /<key>of<\/key>\s*<array>([\s\S]*?)<\/array
|
|
5234
|
+
const PLIST_OFFSETS_ARRAY_PATTERN = /<key>of<\/key>\s*<array>([\s\S]*?)<\/array>/u;
|
|
5161
5235
|
const parseOffsets = (xml) => {
|
|
5162
5236
|
const arrayMatch = PLIST_OFFSETS_ARRAY_PATTERN.exec(xml);
|
|
5163
5237
|
if (!arrayMatch?.[1]) return [];
|
|
5164
5238
|
const offsets = [];
|
|
5165
|
-
for (const dictMatch of arrayMatch[1].matchAll(/<dict>([\s\S]*?)<\/dict>/
|
|
5239
|
+
for (const dictMatch of arrayMatch[1].matchAll(/<dict>([\s\S]*?)<\/dict>/gu)) {
|
|
5166
5240
|
const [, fragment] = dictMatch;
|
|
5167
5241
|
if (!fragment) continue;
|
|
5168
5242
|
const weekday = parseNumericPlistField(fragment, "wd");
|
|
@@ -5290,11 +5364,11 @@ const normalizeTitle = (value, fallback) => {
|
|
|
5290
5364
|
const trimmed = value?.trim();
|
|
5291
5365
|
return trimmed && trimmed.length > 0 ? trimmed : fallback;
|
|
5292
5366
|
};
|
|
5293
|
-
const NON_ALPHANUMERIC_PATTERN = /[^A-Z0-9]+/
|
|
5294
|
-
const WHITESPACE_SPLIT_PATTERN = /\s
|
|
5295
|
-
const NON_ALPHANUMERIC_STRICT_PATTERN = /[^A-Z0-9]/
|
|
5367
|
+
const NON_ALPHANUMERIC_PATTERN = /[^A-Z0-9]+/gu;
|
|
5368
|
+
const WHITESPACE_SPLIT_PATTERN = /\s+/u;
|
|
5369
|
+
const NON_ALPHANUMERIC_STRICT_PATTERN = /[^A-Z0-9]/gu;
|
|
5296
5370
|
const READABLE_TEXT_PATTERN = /^[\t\n\r\u0020-\u007E\u00A0-\uFFFF]*$/u;
|
|
5297
|
-
const EMAIL_SPLIT_PATTERN = /[,\n;]
|
|
5371
|
+
const EMAIL_SPLIT_PATTERN = /[,\n;]/u;
|
|
5298
5372
|
const normalizeKeyBase = (value, fallback) => {
|
|
5299
5373
|
const initials = value.toUpperCase().replace(NON_ALPHANUMERIC_PATTERN, " ").trim().split(WHITESPACE_SPLIT_PATTERN).filter((word) => word.length > 0).map((word) => word[0] ?? "").join("");
|
|
5300
5374
|
const compact = value.toUpperCase().replace(NON_ALPHANUMERIC_STRICT_PATTERN, "");
|
|
@@ -5312,7 +5386,7 @@ const buildUniqueKeys = (items, options) => {
|
|
|
5312
5386
|
const base = normalizeKeyBase(normalizeTitle(item.title, options.fallback), options.fallback).slice(0, options.maxLength);
|
|
5313
5387
|
let candidate = base || options.fallback;
|
|
5314
5388
|
if (used.has(candidate)) {
|
|
5315
|
-
const suffixBase = item.uuid.replaceAll(/[^a-zA-Z0-9]/
|
|
5389
|
+
const suffixBase = item.uuid.replaceAll(/[^a-zA-Z0-9]/gu, "").slice(-4);
|
|
5316
5390
|
const suffix = suffixBase.length > 0 ? suffixBase.toUpperCase() : "X";
|
|
5317
5391
|
const headLength = Math.max(1, options.maxLength - suffix.length - 1);
|
|
5318
5392
|
candidate = `${candidate.slice(0, headLength)}-${suffix}`;
|
|
@@ -5384,7 +5458,7 @@ const pickCompletedAt = (task) => {
|
|
|
5384
5458
|
};
|
|
5385
5459
|
const sortValue = (primary, fallback) => typeof primary === "number" ? primary : fallback;
|
|
5386
5460
|
const sanitizeBuffer = (buffer) => {
|
|
5387
|
-
const asText = buffer.toString("
|
|
5461
|
+
const asText = buffer.toString("utf-8");
|
|
5388
5462
|
if (!asText.includes("�") && READABLE_TEXT_PATTERN.test(asText)) {
|
|
5389
5463
|
const trimmed = asText.trim();
|
|
5390
5464
|
if (trimmed.length > 0) return trimmed;
|
|
@@ -5998,7 +6072,7 @@ const THINGS_CONTAINER_PATH = join(homedir(), "Library/Group Containers/JLMPQHK8
|
|
|
5998
6072
|
const THINGS_BUNDLE_NAME = "Things Database.thingsdatabase";
|
|
5999
6073
|
const THINGS_SQLITE_FILE = "main.sqlite";
|
|
6000
6074
|
const LEGACY_THINGS_SQLITE_FILE = "Things.sqlite3";
|
|
6001
|
-
const URL_SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*:/
|
|
6075
|
+
const URL_SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*:/iu;
|
|
6002
6076
|
const isUrlLike = (value) => URL_SCHEME_PATTERN.test(value);
|
|
6003
6077
|
const resolveInputPath = (databaseUrl) => {
|
|
6004
6078
|
if (!isUrlLike(databaseUrl)) return resolve(databaseUrl);
|
|
@@ -6061,7 +6135,7 @@ const toStringValue = (value) => {
|
|
|
6061
6135
|
return trimmed.length > 0 ? trimmed : null;
|
|
6062
6136
|
}
|
|
6063
6137
|
if (Buffer.isBuffer(value)) {
|
|
6064
|
-
const text = value.toString("
|
|
6138
|
+
const text = value.toString("utf-8").trim();
|
|
6065
6139
|
return text.length > 0 ? text : null;
|
|
6066
6140
|
}
|
|
6067
6141
|
return null;
|
|
@@ -6407,7 +6481,7 @@ const parseMetadataMode = (value) => {
|
|
|
6407
6481
|
};
|
|
6408
6482
|
const runThingsImportCommand = async (context, options, workspaceOverride) => {
|
|
6409
6483
|
const commandContext = await resolveCommandContext(context);
|
|
6410
|
-
const creatorId = requireUserId(commandContext
|
|
6484
|
+
const creatorId = await requireUserId(context, commandContext);
|
|
6411
6485
|
const metadataMode = parseMetadataMode(options.metadataMode);
|
|
6412
6486
|
const { workspace, autoSelected } = await resolveWorkspace(context, {
|
|
6413
6487
|
apiBaseUrl: commandContext.apiBaseUrl,
|
|
@@ -6463,7 +6537,7 @@ const isHistoryFile = (value) => {
|
|
|
6463
6537
|
};
|
|
6464
6538
|
const loadHistory = async (historyFile) => {
|
|
6465
6539
|
try {
|
|
6466
|
-
const raw = await readFile(historyFile, "
|
|
6540
|
+
const raw = await readFile(historyFile, "utf-8");
|
|
6467
6541
|
const parsed = JSON.parse(raw);
|
|
6468
6542
|
if (isHistoryFile(parsed)) return parsed.entries;
|
|
6469
6543
|
return [];
|
|
@@ -6538,7 +6612,7 @@ const runInteractiveMode = async (context, program) => {
|
|
|
6538
6612
|
recursive: true
|
|
6539
6613
|
});
|
|
6540
6614
|
await writeFile(HISTORY_FILE, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
6541
|
-
encoding: "
|
|
6615
|
+
encoding: "utf-8",
|
|
6542
6616
|
mode: 384
|
|
6543
6617
|
});
|
|
6544
6618
|
} catch {}
|
|
@@ -6635,7 +6709,7 @@ const runLabelShow = async (context, labelRef, options) => {
|
|
|
6635
6709
|
writeInfo(context, `createdAt: ${formatEpochDate(label.createdAt) ?? "(none)"}`);
|
|
6636
6710
|
writeInfo(context, `updatedAt: ${formatEpochDate(label.updatedAt) ?? "(none)"}`);
|
|
6637
6711
|
};
|
|
6638
|
-
const UUID_REGEX$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
|
6712
|
+
const UUID_REGEX$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
6639
6713
|
const resolveTaskForLabel = async (context, options) => {
|
|
6640
6714
|
const taskRef = options.taskRef.trim();
|
|
6641
6715
|
if (!taskRef) throw new Error("Task id is required.");
|
|
@@ -6882,7 +6956,7 @@ const getProjectStatus = (project) => {
|
|
|
6882
6956
|
};
|
|
6883
6957
|
const parseTargetDate = (value) => parseCliDateOnlyToEpoch(value, "target date");
|
|
6884
6958
|
const generateProjectSlug = (name, id) => {
|
|
6885
|
-
const slug = name.toLowerCase().trim().replaceAll(/[^a-z0-9]+/
|
|
6959
|
+
const slug = name.toLowerCase().trim().replaceAll(/[^a-z0-9]+/gu, "-").replaceAll(/^-|-$/gu, "").slice(0, 39);
|
|
6886
6960
|
const shortId = id.replaceAll("-", "").slice(0, 8);
|
|
6887
6961
|
return slug ? `${slug}-${shortId}` : shortId;
|
|
6888
6962
|
};
|
|
@@ -7002,14 +7076,14 @@ const resolveProjectName = async (context, rawName) => {
|
|
|
7002
7076
|
const trimmed = rawName.trim();
|
|
7003
7077
|
if (trimmed.length > 0) return trimmed;
|
|
7004
7078
|
}
|
|
7005
|
-
const { promptForValue } = await import("./prompt-
|
|
7079
|
+
const { promptForValue } = await import("./prompt-B7mDo4K7.mjs");
|
|
7006
7080
|
const prompted = await promptForValue(context, "Project name");
|
|
7007
7081
|
if (prompted) return prompted;
|
|
7008
7082
|
throw new CliError("Project name is required.", EXIT_CODES.VALIDATION, "Provide a name: donebear project add \"My project\"");
|
|
7009
7083
|
};
|
|
7010
7084
|
const runProjectAdd = async (context, name, options) => {
|
|
7011
7085
|
const commandContext = await resolveCommandContext(context);
|
|
7012
|
-
const userId = requireUserId(commandContext
|
|
7086
|
+
const userId = await requireUserId(context, commandContext);
|
|
7013
7087
|
const normalizedName = await resolveProjectName(context, name);
|
|
7014
7088
|
const { workspace, autoSelected } = await resolveWorkspace(context, {
|
|
7015
7089
|
apiBaseUrl: commandContext.apiBaseUrl,
|
|
@@ -7253,7 +7327,7 @@ Agent tip: run "donebear spec project add" for full option reference
|
|
|
7253
7327
|
};
|
|
7254
7328
|
//#endregion
|
|
7255
7329
|
//#region src/commands/task.ts
|
|
7256
|
-
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
|
|
7330
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
7257
7331
|
const DEFAULT_TASK_LIST_LIMIT = 20;
|
|
7258
7332
|
const VALID_TASK_VIEWS = new Set([
|
|
7259
7333
|
"inbox",
|
|
@@ -7417,7 +7491,7 @@ const resolveNotes = async (_context, flagNotes) => {
|
|
|
7417
7491
|
};
|
|
7418
7492
|
const runTaskAdd = async (context, title, options, workspaceOverride) => {
|
|
7419
7493
|
const commandContext = await resolveCommandContext(context);
|
|
7420
|
-
const userId = requireUserId(commandContext
|
|
7494
|
+
const userId = await requireUserId(context, commandContext);
|
|
7421
7495
|
const normalizedTitle = await resolveTitle(context, title);
|
|
7422
7496
|
const notes = await resolveNotes(context, options.notes);
|
|
7423
7497
|
const { workspace, autoSelected } = await resolveWorkspace(context, {
|
|
@@ -8161,6 +8235,15 @@ Examples:
|
|
|
8161
8235
|
const OVERVIEW = {
|
|
8162
8236
|
authentication: "Set DONEBEAR_TOKEN env var, or run: donebear auth login",
|
|
8163
8237
|
commands: {
|
|
8238
|
+
"api-key": {
|
|
8239
|
+
description: "Manage personal API keys",
|
|
8240
|
+
quick_example: "donebear api-key list --json",
|
|
8241
|
+
subcommands: [
|
|
8242
|
+
"create",
|
|
8243
|
+
"list",
|
|
8244
|
+
"revoke"
|
|
8245
|
+
]
|
|
8246
|
+
},
|
|
8164
8247
|
auth: {
|
|
8165
8248
|
description: "Authentication",
|
|
8166
8249
|
quick_example: "donebear auth status --json",
|
|
@@ -8276,6 +8359,70 @@ const OVERVIEW = {
|
|
|
8276
8359
|
workspace_targeting: "Prefix any command: donebear workspace=<slug> task list"
|
|
8277
8360
|
};
|
|
8278
8361
|
const COMMAND_SPECS = {
|
|
8362
|
+
"api-key create": {
|
|
8363
|
+
arguments: { label: {
|
|
8364
|
+
description: "Human-readable label for the key",
|
|
8365
|
+
required: true,
|
|
8366
|
+
type: "string"
|
|
8367
|
+
} },
|
|
8368
|
+
command: "api-key create",
|
|
8369
|
+
examples: [
|
|
8370
|
+
"donebear api-key create \"Raycast\" --json",
|
|
8371
|
+
"donebear api-key create \"CI\" --permissions read-only --expires 90d --json",
|
|
8372
|
+
"donebear api-key create \"Scoped\" --workspaces my-org,side-project --expires 1y --json"
|
|
8373
|
+
],
|
|
8374
|
+
json_output: {
|
|
8375
|
+
createdAt: "string",
|
|
8376
|
+
expiresAt: "string | null",
|
|
8377
|
+
id: "string",
|
|
8378
|
+
keyPrefix: "string",
|
|
8379
|
+
label: "string",
|
|
8380
|
+
scopes: "string[]",
|
|
8381
|
+
token: "string",
|
|
8382
|
+
workspaceIds: "string[] | null"
|
|
8383
|
+
},
|
|
8384
|
+
notes: "The full token is only shown once at creation time. Scopes default to full-access (read, write, admin).",
|
|
8385
|
+
options: {
|
|
8386
|
+
"--expires": {
|
|
8387
|
+
description: "Expiration duration, e.g. \"30d\", \"90d\", \"1y\"",
|
|
8388
|
+
type: "string"
|
|
8389
|
+
},
|
|
8390
|
+
"--permissions": {
|
|
8391
|
+
default: "full-access",
|
|
8392
|
+
description: "\"full-access\" (read, write, admin) or \"read-only\" (read only)",
|
|
8393
|
+
enum: ["full-access", "read-only"],
|
|
8394
|
+
type: "string"
|
|
8395
|
+
},
|
|
8396
|
+
"--workspaces": {
|
|
8397
|
+
description: "Comma-separated workspace slugs to restrict the key to",
|
|
8398
|
+
type: "string"
|
|
8399
|
+
}
|
|
8400
|
+
},
|
|
8401
|
+
usage: "donebear api-key create <label> [options]"
|
|
8402
|
+
},
|
|
8403
|
+
"api-key list": {
|
|
8404
|
+
command: "api-key list",
|
|
8405
|
+
examples: ["donebear api-key list --json"],
|
|
8406
|
+
json_output: { keys: "ApiKeyRecord[]" },
|
|
8407
|
+
notes: "Each key includes scopes, workspaceIds, and expiresAt fields.",
|
|
8408
|
+
options: {},
|
|
8409
|
+
usage: "donebear api-key list"
|
|
8410
|
+
},
|
|
8411
|
+
"api-key revoke": {
|
|
8412
|
+
arguments: { "key-id": {
|
|
8413
|
+
description: "The UUID of the API key to revoke",
|
|
8414
|
+
required: true,
|
|
8415
|
+
type: "string"
|
|
8416
|
+
} },
|
|
8417
|
+
command: "api-key revoke",
|
|
8418
|
+
examples: ["donebear api-key revoke abc12345 --json"],
|
|
8419
|
+
json_output: {
|
|
8420
|
+
id: "string",
|
|
8421
|
+
ok: "boolean"
|
|
8422
|
+
},
|
|
8423
|
+
options: {},
|
|
8424
|
+
usage: "donebear api-key revoke <key-id>"
|
|
8425
|
+
},
|
|
8279
8426
|
"auth login": {
|
|
8280
8427
|
command: "auth login",
|
|
8281
8428
|
examples: [
|
|
@@ -8922,6 +9069,16 @@ const COMMAND_SPECS = {
|
|
|
8922
9069
|
}
|
|
8923
9070
|
};
|
|
8924
9071
|
const TOP_LEVEL_SPECS = {
|
|
9072
|
+
"api-key": {
|
|
9073
|
+
command: "api-key",
|
|
9074
|
+
description: "Manage personal API keys",
|
|
9075
|
+
subcommands: {
|
|
9076
|
+
create: "Create a new API key (--permissions, --workspaces, --expires)",
|
|
9077
|
+
list: "List all API keys with scopes and expiration",
|
|
9078
|
+
revoke: "Revoke an API key by id"
|
|
9079
|
+
},
|
|
9080
|
+
tip: "donebear spec api-key create — get full spec for api-key create"
|
|
9081
|
+
},
|
|
8925
9082
|
auth: {
|
|
8926
9083
|
command: "auth",
|
|
8927
9084
|
description: "Authentication",
|
|
@@ -9215,8 +9372,13 @@ Examples:
|
|
|
9215
9372
|
//#endregion
|
|
9216
9373
|
//#region src/commands/whoami.ts
|
|
9217
9374
|
const runWhoAmI = async (context) => {
|
|
9218
|
-
|
|
9219
|
-
|
|
9375
|
+
let supabaseConfig = null;
|
|
9376
|
+
try {
|
|
9377
|
+
supabaseConfig = resolveSupabaseConfig();
|
|
9378
|
+
} catch {
|
|
9379
|
+
supabaseConfig = null;
|
|
9380
|
+
}
|
|
9381
|
+
const resolvedToken = await resolveAuthToken(context, supabaseConfig);
|
|
9220
9382
|
if (!resolvedToken) {
|
|
9221
9383
|
process.exitCode = EXIT_CODES.AUTH_REQUIRED;
|
|
9222
9384
|
if (context.json) {
|
|
@@ -9233,7 +9395,10 @@ const runWhoAmI = async (context) => {
|
|
|
9233
9395
|
writeInfo(context, "Run `donebear auth login`.");
|
|
9234
9396
|
return;
|
|
9235
9397
|
}
|
|
9236
|
-
const user = await
|
|
9398
|
+
const user = await loadViewer(context, {
|
|
9399
|
+
baseUrl: resolveApiBaseUrl(context),
|
|
9400
|
+
token: resolvedToken.token
|
|
9401
|
+
});
|
|
9237
9402
|
if (context.json) {
|
|
9238
9403
|
writeOutput(context, {
|
|
9239
9404
|
ok: true,
|
|
@@ -9594,10 +9759,10 @@ Examples:
|
|
|
9594
9759
|
//#endregion
|
|
9595
9760
|
//#region src/cli.ts
|
|
9596
9761
|
const packageManifest = createRequire(import.meta.url)("../package.json");
|
|
9597
|
-
const WORKSPACE_PREFIX_REGEX = /^workspace=(.+)$/
|
|
9762
|
+
const WORKSPACE_PREFIX_REGEX = /^workspace=(.+)$/iu;
|
|
9598
9763
|
const extractWorkspaceTarget = (argv) => {
|
|
9599
9764
|
const processedArgv = [...argv];
|
|
9600
|
-
const
|
|
9765
|
+
const firstArg = processedArgv[2];
|
|
9601
9766
|
if (firstArg) {
|
|
9602
9767
|
const match = WORKSPACE_PREFIX_REGEX.exec(firstArg);
|
|
9603
9768
|
if (match?.[1]) {
|