@sunasteriskrnd/takumi 1.0.0-dev.64 → 1.0.0-dev.66
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/index.js +385 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19815,7 +19815,7 @@ var package_default;
|
|
|
19815
19815
|
var init_package = __esm(() => {
|
|
19816
19816
|
package_default = {
|
|
19817
19817
|
name: "@sunasteriskrnd/takumi",
|
|
19818
|
-
version: "1.0.0-dev.
|
|
19818
|
+
version: "1.0.0-dev.66",
|
|
19819
19819
|
description: "CLI tool for bootstrapping and managing Takumi projects",
|
|
19820
19820
|
type: "module",
|
|
19821
19821
|
repository: {
|
|
@@ -20012,7 +20012,7 @@ function getLegacyManifestPath(providerRoot) {
|
|
|
20012
20012
|
return join4(providerRoot, LEGACY_MANIFEST_FILENAME);
|
|
20013
20013
|
}
|
|
20014
20014
|
function getCliVersion() {
|
|
20015
|
-
return "1.0.0-dev.
|
|
20015
|
+
return "1.0.0-dev.66"?.trim() || process.env.npm_package_version?.trim() || "unknown";
|
|
20016
20016
|
}
|
|
20017
20017
|
function getCliUserAgent() {
|
|
20018
20018
|
return `${TAKUMI_CLI_NPM_PACKAGE_NAME}/${getCliVersion()}`;
|
|
@@ -51450,6 +51450,10 @@ var init_artifact_action_help = __esm(() => {
|
|
|
51450
51450
|
{
|
|
51451
51451
|
flags: "-m, --message <message>",
|
|
51452
51452
|
description: "Short note describing this version's change (max 100 chars)"
|
|
51453
|
+
},
|
|
51454
|
+
{
|
|
51455
|
+
flags: "--open",
|
|
51456
|
+
description: "Open the artifact in the browser after a successful upload"
|
|
51453
51457
|
}
|
|
51454
51458
|
]
|
|
51455
51459
|
}
|
|
@@ -51692,15 +51696,65 @@ var init_artifact_comments_help = __esm(() => {
|
|
|
51692
51696
|
};
|
|
51693
51697
|
});
|
|
51694
51698
|
|
|
51699
|
+
// src/domains/help/commands/artifact-open-help.ts
|
|
51700
|
+
var artifactOpenHelp;
|
|
51701
|
+
var init_artifact_open_help = __esm(() => {
|
|
51702
|
+
artifactOpenHelp = {
|
|
51703
|
+
name: "artifact open",
|
|
51704
|
+
description: "Open the artifact viewer (or the dashboard with no ref) in the browser",
|
|
51705
|
+
usage: "tkm artifact open [uuid|url] [options]",
|
|
51706
|
+
examples: [
|
|
51707
|
+
{
|
|
51708
|
+
command: "tkm artifact open",
|
|
51709
|
+
description: "Open the artifacts dashboard (no artifact reference)"
|
|
51710
|
+
},
|
|
51711
|
+
{
|
|
51712
|
+
command: "tkm artifact open <uuid|url>",
|
|
51713
|
+
description: "Open the latest version of an artifact in the viewer"
|
|
51714
|
+
},
|
|
51715
|
+
{
|
|
51716
|
+
command: "tkm artifact open <uuid|url> --ver 3 --file README.md",
|
|
51717
|
+
description: "Deep-link to version 3 and a specific file inside the artifact"
|
|
51718
|
+
}
|
|
51719
|
+
],
|
|
51720
|
+
optionGroups: [
|
|
51721
|
+
{
|
|
51722
|
+
title: "Options",
|
|
51723
|
+
options: [
|
|
51724
|
+
{
|
|
51725
|
+
flags: "--ver <n>",
|
|
51726
|
+
description: "Version to open. ?v=<n> in a pasted URL works too; --ver wins when both given"
|
|
51727
|
+
},
|
|
51728
|
+
{
|
|
51729
|
+
flags: "--file <path>",
|
|
51730
|
+
description: "Deep-link to a file INSIDE the artifact (not a local file — contrast with `comments reply --file`, which reads a local file's contents)"
|
|
51731
|
+
},
|
|
51732
|
+
{
|
|
51733
|
+
flags: "--thread <uuid>",
|
|
51734
|
+
description: "Deep-link to a comment thread by id"
|
|
51735
|
+
}
|
|
51736
|
+
]
|
|
51737
|
+
}
|
|
51738
|
+
],
|
|
51739
|
+
sections: [
|
|
51740
|
+
{
|
|
51741
|
+
title: "Notes",
|
|
51742
|
+
content: "Makes no API calls — an invalid reference is rejected locally, and a valid-looking but nonexistent artifact simply 404s in the browser."
|
|
51743
|
+
}
|
|
51744
|
+
]
|
|
51745
|
+
};
|
|
51746
|
+
});
|
|
51747
|
+
|
|
51695
51748
|
// src/domains/help/commands/artifact-command-help.ts
|
|
51696
51749
|
var artifactCommandHelp;
|
|
51697
51750
|
var init_artifact_command_help = __esm(() => {
|
|
51698
51751
|
init_artifact_action_help();
|
|
51699
51752
|
init_artifact_comments_help();
|
|
51753
|
+
init_artifact_open_help();
|
|
51700
51754
|
artifactCommandHelp = {
|
|
51701
51755
|
name: "artifact",
|
|
51702
|
-
description: "List, search, upload, download, and
|
|
51703
|
-
usage: "tkm artifact <list | search <term> | upload <file|dir> | download <uuid|url> | delete <uuid|url> | comments <verb> <uuid|url> [id]>",
|
|
51756
|
+
description: "List, search, upload, download, delete, and open Takumi artifacts, and work with their review comments",
|
|
51757
|
+
usage: "tkm artifact <list | search <term> | upload <file|dir> | download <uuid|url> | delete <uuid|url> | open [uuid|url] | comments <verb> <uuid|url> [id]>",
|
|
51704
51758
|
examples: [
|
|
51705
51759
|
{
|
|
51706
51760
|
command: "tkm artifact upload ./report.html --title 'Weekly Report'",
|
|
@@ -51739,6 +51793,10 @@ var init_artifact_command_help = __esm(() => {
|
|
|
51739
51793
|
flags: "delete <uuid|url>",
|
|
51740
51794
|
description: "Soft-delete the whole artifact, or one version with --ver <n>"
|
|
51741
51795
|
},
|
|
51796
|
+
{
|
|
51797
|
+
flags: "open [uuid|url]",
|
|
51798
|
+
description: "Open the viewer (or dashboard with no ref) in the browser"
|
|
51799
|
+
},
|
|
51742
51800
|
{
|
|
51743
51801
|
flags: "comments <verb> <uuid|url> [id]",
|
|
51744
51802
|
description: "Read and act on review comments (list|reply|solve|reopen|delete)"
|
|
@@ -51758,6 +51816,7 @@ var init_artifact_command_help = __esm(() => {
|
|
|
51758
51816
|
upload: artifactUploadHelp,
|
|
51759
51817
|
download: artifactDownloadHelp,
|
|
51760
51818
|
delete: artifactDeleteHelp,
|
|
51819
|
+
open: artifactOpenHelp,
|
|
51761
51820
|
comments: artifactCommentsHelp
|
|
51762
51821
|
}
|
|
51763
51822
|
};
|
|
@@ -51842,6 +51901,7 @@ var init_commands2 = __esm(() => {
|
|
|
51842
51901
|
init_artifact_command_help();
|
|
51843
51902
|
init_artifact_comments_help();
|
|
51844
51903
|
init_artifact_action_help();
|
|
51904
|
+
init_artifact_open_help();
|
|
51845
51905
|
init_mcp_command_help();
|
|
51846
51906
|
init_common_options();
|
|
51847
51907
|
});
|
|
@@ -52920,6 +52980,9 @@ ${API_KEY_VAR}=${apiKey}
|
|
|
52920
52980
|
writeFileSync(envPath, content, "utf-8");
|
|
52921
52981
|
}
|
|
52922
52982
|
// src/domains/takumi-api/api-error-handler.ts
|
|
52983
|
+
var LICENSE_REQUIRED_REMEDIATION = "Your Takumi license is inactive or expired. Contact your Sun* admin to renew access.";
|
|
52984
|
+
var LICENSE_REQUIRED_EXIT_CODE = 4;
|
|
52985
|
+
|
|
52923
52986
|
class CkApiError extends Error {
|
|
52924
52987
|
code;
|
|
52925
52988
|
status;
|
|
@@ -52945,10 +53008,16 @@ function parseApiError(status, body) {
|
|
|
52945
53008
|
const message = parsed?.message || parsed?.error || `API error (HTTP ${status})`;
|
|
52946
53009
|
const retryAfter = parsed?.retryAfter;
|
|
52947
53010
|
if (parsed?.code && isKnownErrorCode(parsed.code)) {
|
|
52948
|
-
|
|
53011
|
+
const code2 = parsed.code;
|
|
53012
|
+
return new CkApiError(code2, withRemediation(code2, message), status, retryAfter);
|
|
52949
53013
|
}
|
|
52950
53014
|
const code = mapStatusToErrorCode(status);
|
|
52951
|
-
return new CkApiError(code, message, status, retryAfter);
|
|
53015
|
+
return new CkApiError(code, withRemediation(code, message), status, retryAfter);
|
|
53016
|
+
}
|
|
53017
|
+
function withRemediation(code, message) {
|
|
53018
|
+
if (code === "LICENSE_REQUIRED")
|
|
53019
|
+
return `${message} ${LICENSE_REQUIRED_REMEDIATION}`;
|
|
53020
|
+
return message;
|
|
52952
53021
|
}
|
|
52953
53022
|
function isKnownErrorCode(code) {
|
|
52954
53023
|
const known = new Set([
|
|
@@ -53967,38 +54036,83 @@ function showApiHelp() {
|
|
|
53967
54036
|
console.log(" takumi api reviewweb seo-backlinks <domain> SEO backlinks");
|
|
53968
54037
|
console.log();
|
|
53969
54038
|
}
|
|
54039
|
+
// src/commands/artifact/action-flag-scope.ts
|
|
54040
|
+
var ACTION_SCOPED_FLAGS = {
|
|
54041
|
+
comments: ["status", "author", "cursor", "quiet", "file"],
|
|
54042
|
+
open: ["file", "thread"],
|
|
54043
|
+
upload: ["open", "id"]
|
|
54044
|
+
};
|
|
54045
|
+
var ALL_SCOPED_FLAGS = Array.from(new Set(Object.values(ACTION_SCOPED_FLAGS).flat()));
|
|
54046
|
+
function owningActions(flag) {
|
|
54047
|
+
return Object.entries(ACTION_SCOPED_FLAGS).filter(([, flags]) => flags.includes(flag)).map(([owner]) => `\`artifact ${owner}\``);
|
|
54048
|
+
}
|
|
54049
|
+
function strayFlagDetail(action, opts) {
|
|
54050
|
+
const allowed = ACTION_SCOPED_FLAGS[action] ?? [];
|
|
54051
|
+
const stray = ALL_SCOPED_FLAGS.filter((flag) => !allowed.includes(flag) && opts[flag] !== undefined && opts[flag] !== false);
|
|
54052
|
+
if (stray.length === 0)
|
|
54053
|
+
return null;
|
|
54054
|
+
return stray.map((flag) => `--${flag} (only ${owningActions(flag).join(" or ")})`).join(", ");
|
|
54055
|
+
}
|
|
54056
|
+
|
|
53970
54057
|
// src/commands/artifact/refs.ts
|
|
53971
54058
|
init_auth_client();
|
|
53972
54059
|
var UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
53973
54060
|
function isArtifactUuid(id) {
|
|
53974
|
-
return UUID_V4_RE.test(id.trim());
|
|
54061
|
+
return UUID_V4_RE.test(String(id).trim());
|
|
53975
54062
|
}
|
|
53976
54063
|
function parseArtifactRef(input) {
|
|
53977
|
-
const s = input.trim();
|
|
54064
|
+
const s = String(input).trim();
|
|
53978
54065
|
if (UUID_V4_RE.test(s))
|
|
53979
54066
|
return s.toLowerCase();
|
|
53980
54067
|
const m2 = s.match(/\/artifacts\/([^/?#]+)/i);
|
|
53981
54068
|
const candidate = m2?.[1] ?? "";
|
|
53982
54069
|
return UUID_V4_RE.test(candidate) ? candidate.toLowerCase() : null;
|
|
53983
54070
|
}
|
|
53984
|
-
|
|
54071
|
+
var HOST_FIRST_RE = /^[a-z0-9][a-z0-9.-]*(:\d+)?\//i;
|
|
54072
|
+
function tryUrl(s) {
|
|
53985
54073
|
try {
|
|
53986
|
-
|
|
53987
|
-
const v2 = url.searchParams.get("v");
|
|
53988
|
-
if (v2 !== null) {
|
|
53989
|
-
const n = Number.parseInt(v2, 10);
|
|
53990
|
-
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
53991
|
-
}
|
|
53992
|
-
} catch {}
|
|
53993
|
-
return;
|
|
53994
|
-
}
|
|
53995
|
-
function warnIfHostMismatch(input) {
|
|
53996
|
-
let inputUrl;
|
|
53997
|
-
try {
|
|
53998
|
-
inputUrl = new URL(input.trim());
|
|
54074
|
+
return new URL(s);
|
|
53999
54075
|
} catch {
|
|
54076
|
+
return null;
|
|
54077
|
+
}
|
|
54078
|
+
}
|
|
54079
|
+
function toUrl(ref) {
|
|
54080
|
+
const s = String(ref).trim();
|
|
54081
|
+
if (!s.includes("/"))
|
|
54082
|
+
return null;
|
|
54083
|
+
const direct = tryUrl(s);
|
|
54084
|
+
if (direct && /^https?:$/.test(direct.protocol))
|
|
54085
|
+
return direct;
|
|
54086
|
+
return HOST_FIRST_RE.test(s) ? tryUrl(`https://${s}`) : null;
|
|
54087
|
+
}
|
|
54088
|
+
function extractVersionFromRef(ref) {
|
|
54089
|
+
const url = toUrl(ref);
|
|
54090
|
+
if (!url)
|
|
54091
|
+
return;
|
|
54092
|
+
const v2 = url.searchParams.get("v");
|
|
54093
|
+
if (v2 === null || !/^[1-9]\d*$/.test(v2.trim()))
|
|
54000
54094
|
return;
|
|
54095
|
+
return Number(v2);
|
|
54096
|
+
}
|
|
54097
|
+
function extractDeepLinkFromRef(ref) {
|
|
54098
|
+
const url = toUrl(ref);
|
|
54099
|
+
if (!url)
|
|
54100
|
+
return {};
|
|
54101
|
+
const parts = {};
|
|
54102
|
+
const file = url.searchParams.get("file");
|
|
54103
|
+
if (file !== null && file.trim() !== "") {
|
|
54104
|
+
parts.file = file;
|
|
54001
54105
|
}
|
|
54106
|
+
const thread = url.searchParams.get("thread");
|
|
54107
|
+
if (thread !== null && thread.trim() !== "") {
|
|
54108
|
+
parts.thread = thread;
|
|
54109
|
+
}
|
|
54110
|
+
return parts;
|
|
54111
|
+
}
|
|
54112
|
+
function warnIfHostMismatch(input) {
|
|
54113
|
+
const inputUrl = toUrl(input);
|
|
54114
|
+
if (!inputUrl)
|
|
54115
|
+
return;
|
|
54002
54116
|
let serverHost;
|
|
54003
54117
|
try {
|
|
54004
54118
|
serverHost = new URL(getServerUrl()).host;
|
|
@@ -55140,6 +55254,100 @@ async function artifactList(term, opts) {
|
|
|
55140
55254
|
logger.info(footerLine2(payload));
|
|
55141
55255
|
}
|
|
55142
55256
|
|
|
55257
|
+
// src/domains/sessions/browser-open.ts
|
|
55258
|
+
init_open();
|
|
55259
|
+
function tryOpenBrowser(target) {
|
|
55260
|
+
open_default(target).catch(() => {});
|
|
55261
|
+
}
|
|
55262
|
+
|
|
55263
|
+
// src/commands/artifact/open-in-browser.ts
|
|
55264
|
+
init_environment();
|
|
55265
|
+
function openOrPrint(url, opts) {
|
|
55266
|
+
console.log(url);
|
|
55267
|
+
if (isNonInteractive()) {
|
|
55268
|
+
return;
|
|
55269
|
+
}
|
|
55270
|
+
(opts?._openBrowser ?? tryOpenBrowser)(url);
|
|
55271
|
+
}
|
|
55272
|
+
|
|
55273
|
+
// src/commands/artifact/viewer-url.ts
|
|
55274
|
+
init_auth_client();
|
|
55275
|
+
function buildViewerUrl(parts) {
|
|
55276
|
+
const base = getServerUrl();
|
|
55277
|
+
if (!parts.uuid) {
|
|
55278
|
+
return `${base}/app/artifacts`;
|
|
55279
|
+
}
|
|
55280
|
+
const params = new URLSearchParams;
|
|
55281
|
+
const entries = [
|
|
55282
|
+
["v", parts.version],
|
|
55283
|
+
["file", parts.file],
|
|
55284
|
+
["thread", parts.thread]
|
|
55285
|
+
];
|
|
55286
|
+
for (const [key, value] of entries) {
|
|
55287
|
+
if (value !== undefined && String(value) !== "") {
|
|
55288
|
+
params.set(key, String(value));
|
|
55289
|
+
}
|
|
55290
|
+
}
|
|
55291
|
+
const query = params.toString();
|
|
55292
|
+
return `${base}/app/artifacts/${parts.uuid}${query ? `?${query}` : ""}`;
|
|
55293
|
+
}
|
|
55294
|
+
|
|
55295
|
+
// src/commands/artifact/open-command.ts
|
|
55296
|
+
function singleValue(label, value) {
|
|
55297
|
+
if (Array.isArray(value)) {
|
|
55298
|
+
console.error(`${label} may only be given once`);
|
|
55299
|
+
process.exitCode = 1;
|
|
55300
|
+
return null;
|
|
55301
|
+
}
|
|
55302
|
+
return String(value).trim();
|
|
55303
|
+
}
|
|
55304
|
+
function normalizeFilePath(file) {
|
|
55305
|
+
return file.replace(/\\/g, "/").replace(/^(\.\/|\/)+/, "");
|
|
55306
|
+
}
|
|
55307
|
+
async function artifactOpen(ref, opts) {
|
|
55308
|
+
if (ref === undefined) {
|
|
55309
|
+
if (opts.version !== undefined || opts.file !== undefined || opts.thread !== undefined) {
|
|
55310
|
+
console.error("tkm artifact open — --ver/--file/--thread require an artifact reference");
|
|
55311
|
+
process.exitCode = 1;
|
|
55312
|
+
return;
|
|
55313
|
+
}
|
|
55314
|
+
openOrPrint(buildViewerUrl({}), opts);
|
|
55315
|
+
return;
|
|
55316
|
+
}
|
|
55317
|
+
const uuid = parseArtifactRef(ref);
|
|
55318
|
+
if (!uuid) {
|
|
55319
|
+
console.error(`Invalid artifact id or URL: ${ref}`);
|
|
55320
|
+
process.exitCode = 1;
|
|
55321
|
+
return;
|
|
55322
|
+
}
|
|
55323
|
+
const version3 = opts.version ?? extractVersionFromRef(ref);
|
|
55324
|
+
const deep = extractDeepLinkFromRef(ref);
|
|
55325
|
+
const rawFile = opts.file ?? deep.file;
|
|
55326
|
+
let file;
|
|
55327
|
+
if (rawFile !== undefined) {
|
|
55328
|
+
const single = singleValue("--file", rawFile);
|
|
55329
|
+
if (single === null)
|
|
55330
|
+
return;
|
|
55331
|
+
file = normalizeFilePath(single);
|
|
55332
|
+
}
|
|
55333
|
+
const rawThread = opts.thread ?? deep.thread;
|
|
55334
|
+
let thread;
|
|
55335
|
+
if (rawThread !== undefined) {
|
|
55336
|
+
const single = singleValue("--thread", rawThread);
|
|
55337
|
+
if (single === null)
|
|
55338
|
+
return;
|
|
55339
|
+
if (!isArtifactUuid(single)) {
|
|
55340
|
+
console.error(`Invalid thread id (must be a UUID): ${single}`);
|
|
55341
|
+
process.exitCode = 1;
|
|
55342
|
+
return;
|
|
55343
|
+
}
|
|
55344
|
+
thread = single.toLowerCase();
|
|
55345
|
+
}
|
|
55346
|
+
warnIfHostMismatch(ref);
|
|
55347
|
+
const url = buildViewerUrl({ uuid, version: version3, file, thread });
|
|
55348
|
+
openOrPrint(url, opts);
|
|
55349
|
+
}
|
|
55350
|
+
|
|
55143
55351
|
// src/commands/artifact/upload-command.ts
|
|
55144
55352
|
init_dist2();
|
|
55145
55353
|
import { promises as fs14 } from "node:fs";
|
|
@@ -55273,6 +55481,13 @@ async function artifactUpload(filePath, opts) {
|
|
|
55273
55481
|
process.exitCode = 1;
|
|
55274
55482
|
}
|
|
55275
55483
|
}
|
|
55484
|
+
function printResultUrl(url, opts) {
|
|
55485
|
+
if (opts.open) {
|
|
55486
|
+
openOrPrint(url, opts);
|
|
55487
|
+
} else {
|
|
55488
|
+
console.log(url);
|
|
55489
|
+
}
|
|
55490
|
+
}
|
|
55276
55491
|
async function uploadFile(absPath, displayPath, size, token, opts) {
|
|
55277
55492
|
const ext = extname6(absPath).toLowerCase().slice(1);
|
|
55278
55493
|
if (!ALLOWED_EXTENSIONS.has(ext)) {
|
|
@@ -55349,7 +55564,7 @@ async function uploadFile(absPath, displayPath, size, token, opts) {
|
|
|
55349
55564
|
await upsertFolderEntry(absPath, result.uuid, result.version, folderHash);
|
|
55350
55565
|
spinner.stop("Uploaded.");
|
|
55351
55566
|
printUploadSummary(summary);
|
|
55352
|
-
|
|
55567
|
+
printResultUrl(result.url, opts);
|
|
55353
55568
|
}
|
|
55354
55569
|
async function uploadFolder(absPath, displayPath, token, opts) {
|
|
55355
55570
|
const spinner = de();
|
|
@@ -55464,15 +55679,23 @@ async function uploadFolder(absPath, displayPath, token, opts) {
|
|
|
55464
55679
|
await upsertFolderEntry(absPath, result.uuid, result.version, folderHash);
|
|
55465
55680
|
spinner.stop("Uploaded.");
|
|
55466
55681
|
printUploadSummary(summary);
|
|
55467
|
-
|
|
55682
|
+
printResultUrl(result.url, opts);
|
|
55468
55683
|
}
|
|
55469
55684
|
|
|
55470
55685
|
// src/commands/artifact/artifact-command.ts
|
|
55686
|
+
var ARTIFACT_ACTIONS = new Set([
|
|
55687
|
+
"list",
|
|
55688
|
+
"search",
|
|
55689
|
+
"upload",
|
|
55690
|
+
"download",
|
|
55691
|
+
"delete",
|
|
55692
|
+
"open",
|
|
55693
|
+
"comments"
|
|
55694
|
+
]);
|
|
55471
55695
|
function usageError2(hint) {
|
|
55472
55696
|
console.error(`Usage: ${hint}`);
|
|
55473
55697
|
process.exitCode = 1;
|
|
55474
55698
|
}
|
|
55475
|
-
var COMMENTS_ONLY_FLAGS = ["status", "author", "cursor", "quiet", "file"];
|
|
55476
55699
|
async function artifactCommand(action, target, ...rest) {
|
|
55477
55700
|
if (rest.length !== 1 && rest.length !== 3) {
|
|
55478
55701
|
throw new TypeError(`artifactCommand: expected 3 or 5 arguments, received ${rest.length + 2}`);
|
|
@@ -55480,13 +55703,13 @@ async function artifactCommand(action, target, ...rest) {
|
|
|
55480
55703
|
const opts = rest[rest.length - 1];
|
|
55481
55704
|
const arg3 = rest.length === 3 ? rest[0] : undefined;
|
|
55482
55705
|
const arg4 = rest.length === 3 ? rest[1] : undefined;
|
|
55483
|
-
if (action !== undefined && action
|
|
55484
|
-
if (arg3 !== undefined && arg3 !== null) {
|
|
55706
|
+
if (action !== undefined && ARTIFACT_ACTIONS.has(action)) {
|
|
55707
|
+
if (action !== "comments" && arg3 !== undefined && arg3 !== null) {
|
|
55485
55708
|
return usageError2(`tkm artifact ${action} — unexpected extra argument "${arg3}"`);
|
|
55486
55709
|
}
|
|
55487
|
-
const
|
|
55488
|
-
if (
|
|
55489
|
-
return usageError2(`tkm artifact ${action} — ${
|
|
55710
|
+
const detail = strayFlagDetail(action, opts);
|
|
55711
|
+
if (detail !== null) {
|
|
55712
|
+
return usageError2(`tkm artifact ${action} — ${detail}`);
|
|
55490
55713
|
}
|
|
55491
55714
|
}
|
|
55492
55715
|
switch (action) {
|
|
@@ -55522,11 +55745,14 @@ async function artifactCommand(action, target, ...rest) {
|
|
|
55522
55745
|
}
|
|
55523
55746
|
await commentsCommand(target, arg3, arg4, opts);
|
|
55524
55747
|
break;
|
|
55748
|
+
case "open":
|
|
55749
|
+
await artifactOpen(target, opts);
|
|
55750
|
+
break;
|
|
55525
55751
|
case undefined:
|
|
55526
|
-
usageError2("tkm artifact <list | search <term> | upload <file> | download <uuid|url> | delete <uuid|url> [--ver <n>] | comments <verb> <ref> [id]>");
|
|
55752
|
+
usageError2("tkm artifact <list | search <term> | upload <file> | download <uuid|url> | delete <uuid|url> [--ver <n>] | open [uuid|url] | comments <verb> <ref> [id]>");
|
|
55527
55753
|
break;
|
|
55528
55754
|
default:
|
|
55529
|
-
console.error(`Unknown artifact action: ${action}. Available: list, search, upload, download, delete, comments`);
|
|
55755
|
+
console.error(`Unknown artifact action: ${action}. Available: list, search, upload, download, delete, open, comments`);
|
|
55530
55756
|
process.exitCode = 1;
|
|
55531
55757
|
}
|
|
55532
55758
|
}
|
|
@@ -56146,12 +56372,6 @@ async function configCommand(action, keyOrOptions, valueOrOptions, options2) {
|
|
|
56146
56372
|
};
|
|
56147
56373
|
return configUICommand(uiOpts);
|
|
56148
56374
|
}
|
|
56149
|
-
// src/domains/sessions/browser-open.ts
|
|
56150
|
-
init_open();
|
|
56151
|
-
function tryOpenBrowser(target) {
|
|
56152
|
-
open_default(target).catch(() => {});
|
|
56153
|
-
}
|
|
56154
|
-
|
|
56155
56375
|
// src/domains/sessions/server.ts
|
|
56156
56376
|
init_logger();
|
|
56157
56377
|
import * as http from "node:http";
|
|
@@ -80048,6 +80268,57 @@ function assetNameFor(kit) {
|
|
|
80048
80268
|
return `takumi-${kit}-package.zip`;
|
|
80049
80269
|
}
|
|
80050
80270
|
|
|
80271
|
+
class WorkerAssetError extends Error {
|
|
80272
|
+
status;
|
|
80273
|
+
reason;
|
|
80274
|
+
body;
|
|
80275
|
+
constructor(status2, reason, body) {
|
|
80276
|
+
super(`Worker asset fetch failed (HTTP ${status2}): ${reason}`);
|
|
80277
|
+
this.name = "WorkerAssetError";
|
|
80278
|
+
this.status = status2;
|
|
80279
|
+
this.reason = reason;
|
|
80280
|
+
this.body = body;
|
|
80281
|
+
}
|
|
80282
|
+
}
|
|
80283
|
+
async function parseWorkerAssetError(res) {
|
|
80284
|
+
let body = null;
|
|
80285
|
+
try {
|
|
80286
|
+
body = await res.json();
|
|
80287
|
+
} catch {
|
|
80288
|
+
body = null;
|
|
80289
|
+
}
|
|
80290
|
+
if (res.status === 404)
|
|
80291
|
+
return new WorkerAssetError(res.status, "NOT_FOUND", body);
|
|
80292
|
+
if (res.status === 503)
|
|
80293
|
+
return new WorkerAssetError(res.status, "TRANSIENT", body);
|
|
80294
|
+
if (res.status === 403 && body?.error === "LICENSE_REQUIRED") {
|
|
80295
|
+
return new WorkerAssetError(res.status, "LICENSE_REQUIRED", body);
|
|
80296
|
+
}
|
|
80297
|
+
return new WorkerAssetError(res.status, "UNKNOWN", body);
|
|
80298
|
+
}
|
|
80299
|
+
|
|
80300
|
+
class LicenseRequiredError extends Error {
|
|
80301
|
+
status = 403;
|
|
80302
|
+
reason;
|
|
80303
|
+
constructor(reason) {
|
|
80304
|
+
super(LICENSE_REQUIRED_REMEDIATION);
|
|
80305
|
+
this.name = "LicenseRequiredError";
|
|
80306
|
+
this.reason = reason ?? "no_license_or_entitlement";
|
|
80307
|
+
}
|
|
80308
|
+
}
|
|
80309
|
+
async function licenseErrorFromResponse(res) {
|
|
80310
|
+
if (res.status !== 403)
|
|
80311
|
+
return null;
|
|
80312
|
+
let body = null;
|
|
80313
|
+
try {
|
|
80314
|
+
body = await res.json();
|
|
80315
|
+
} catch {
|
|
80316
|
+
body = null;
|
|
80317
|
+
}
|
|
80318
|
+
if (body?.error === "LICENSE_REQUIRED")
|
|
80319
|
+
return new LicenseRequiredError(body.reason);
|
|
80320
|
+
return null;
|
|
80321
|
+
}
|
|
80051
80322
|
class WorkerSource {
|
|
80052
80323
|
serverUrl;
|
|
80053
80324
|
kit;
|
|
@@ -80074,6 +80345,9 @@ class WorkerSource {
|
|
|
80074
80345
|
if (res.status === 401)
|
|
80075
80346
|
throw new NotLoggedInError;
|
|
80076
80347
|
if (!res.ok) {
|
|
80348
|
+
const licenseError = await licenseErrorFromResponse(res);
|
|
80349
|
+
if (licenseError)
|
|
80350
|
+
throw licenseError;
|
|
80077
80351
|
throw new Error(`Worker source: GET ${url} failed (HTTP ${res.status})`);
|
|
80078
80352
|
}
|
|
80079
80353
|
return ReleaseEntrySchema.parse(await res.json());
|
|
@@ -80085,6 +80359,9 @@ class WorkerSource {
|
|
|
80085
80359
|
if (res.status === 401)
|
|
80086
80360
|
throw new NotLoggedInError;
|
|
80087
80361
|
if (!res.ok) {
|
|
80362
|
+
const licenseError = await licenseErrorFromResponse(res);
|
|
80363
|
+
if (licenseError)
|
|
80364
|
+
throw licenseError;
|
|
80088
80365
|
throw new Error(`Worker source: GET ${url} failed (HTTP ${res.status})`);
|
|
80089
80366
|
}
|
|
80090
80367
|
const parsed = ReleaseListResponseSchema.parse(await res.json());
|
|
@@ -80099,6 +80376,9 @@ class WorkerSource {
|
|
|
80099
80376
|
if (res.status === 404)
|
|
80100
80377
|
throw new NotInIndexError(tag);
|
|
80101
80378
|
if (!res.ok) {
|
|
80379
|
+
const licenseError = await licenseErrorFromResponse(res);
|
|
80380
|
+
if (licenseError)
|
|
80381
|
+
throw licenseError;
|
|
80102
80382
|
throw new Error(`Worker source: GET ${url} failed (HTTP ${res.status})`);
|
|
80103
80383
|
}
|
|
80104
80384
|
return ReleaseEntrySchema.parse(await res.json());
|
|
@@ -80109,12 +80389,8 @@ class WorkerSource {
|
|
|
80109
80389
|
const res = await fetch(url, { headers });
|
|
80110
80390
|
if (res.status === 401)
|
|
80111
80391
|
throw new NotLoggedInError;
|
|
80112
|
-
if (res.
|
|
80113
|
-
throw
|
|
80114
|
-
}
|
|
80115
|
-
if (!res.ok) {
|
|
80116
|
-
throw new Error(`Worker source: GET ${url} failed (HTTP ${res.status})`);
|
|
80117
|
-
}
|
|
80392
|
+
if (!res.ok)
|
|
80393
|
+
throw await parseWorkerAssetError(res);
|
|
80118
80394
|
return res;
|
|
80119
80395
|
}
|
|
80120
80396
|
}
|
|
@@ -80431,6 +80707,11 @@ async function createVersionPrompt(kit, choices, _defaultIndex, allowManualEntry
|
|
|
80431
80707
|
return selected;
|
|
80432
80708
|
}
|
|
80433
80709
|
async function handleSelectionError(error, kit, allowManualEntry, retryCallback) {
|
|
80710
|
+
if (error instanceof LicenseRequiredError) {
|
|
80711
|
+
le(VersionDisplayFormatter.formatError("License required", error.message), import_picocolors21.default.red("License Required"));
|
|
80712
|
+
process.exitCode = LICENSE_REQUIRED_EXIT_CODE;
|
|
80713
|
+
return null;
|
|
80714
|
+
}
|
|
80434
80715
|
logger.error(`Version selection error: ${error.message}`);
|
|
80435
80716
|
if (error.message.includes("401") || error.message.includes("403")) {
|
|
80436
80717
|
le(VersionDisplayFormatter.formatError("Authentication failed", "Please check your GitHub token with: tkm auth"), import_picocolors21.default.red("Authentication Error"));
|
|
@@ -92358,6 +92639,27 @@ function normalizeSkillGroupFlag(value) {
|
|
|
92358
92639
|
}
|
|
92359
92640
|
|
|
92360
92641
|
// src/cli/command-registry.ts
|
|
92642
|
+
var ARTIFACT_STRING_FLAGS = [
|
|
92643
|
+
"id",
|
|
92644
|
+
"title",
|
|
92645
|
+
"message",
|
|
92646
|
+
"output",
|
|
92647
|
+
"access",
|
|
92648
|
+
"status",
|
|
92649
|
+
"author",
|
|
92650
|
+
"cursor",
|
|
92651
|
+
"file",
|
|
92652
|
+
"thread"
|
|
92653
|
+
];
|
|
92654
|
+
function stringifyFlags(opts, keys) {
|
|
92655
|
+
const out = {};
|
|
92656
|
+
for (const key of keys) {
|
|
92657
|
+
const value = opts[key];
|
|
92658
|
+
if (value !== undefined && !Array.isArray(value))
|
|
92659
|
+
out[key] = String(value);
|
|
92660
|
+
}
|
|
92661
|
+
return out;
|
|
92662
|
+
}
|
|
92361
92663
|
function parsePositiveIntFlag(raw, label, example, max) {
|
|
92362
92664
|
if (raw === undefined)
|
|
92363
92665
|
return;
|
|
@@ -92488,7 +92790,7 @@ function registerCommands(cli) {
|
|
|
92488
92790
|
cli.command("api [action] [service] [path]", "Interact with Takumi API and proxy services").option("--method <method>", "HTTP method for proxy requests (default: GET)").option("--body <json>", "Request body as JSON string (proxy only)").option("--query <json>", "Query params as JSON string (proxy only)").option("--key <key>", "API key to use (setup only)").option("--force", "Force re-setup even if key exists (setup only)").option("--json", "Output raw JSON instead of formatted display").option("--locale <locale>", "Locale for vidcap summary/caption (default: en)").option("--max-results <n>", "Max results for vidcap search").option("--second <s>", "Timestamp in seconds for vidcap screenshot").option("--order <order>", "Sort order for vidcap comments (time/relevance)").option("--format <fmt>", "Summary format for reviewweb (bullet/paragraph)").option("--max-length <n>", "Max summary length for reviewweb").option("--instructions <text>", "Extraction instructions for reviewweb extract").option("--template <json>", "JSON template for reviewweb extract").option("--type <type>", "Link type filter for reviewweb links (web/image/file/all)").option("--country <code>", "Country code for reviewweb SEO commands").action(async (action, service, path11, options2) => {
|
|
92489
92791
|
await apiCommand(action, service, path11, options2);
|
|
92490
92792
|
});
|
|
92491
|
-
cli.command("artifact [action] [target] [arg3] [arg4]", "Manage Takumi artifacts (list | search <term> | upload <file> | download <uuid|url> | delete <uuid|url> | comments <verb> <ref> [id])").option("--id <uuid|url>", "Existing artifact (UUID or viewer URL) to overwrite on upload").option("--title <title>", "Display title for the artifact (max 200 chars)").option("-m, --message <message>", "(upload) Version note, max 100 chars · (comments reply) Comment body").option("-o, --output <dir>", "(download) Output directory; default: slug(title) or uuid in CWD").option("--ver <n>", "Version number (download: download it; delete: delete only that version)").option("--force", "(download) Allow writing into a non-empty directory").option("-y, --yes", "Skip delete confirmation prompt").option("--access <level>", "(list) Filter by access level: private | restricted | organization").option("--page <n>", "(list) Page number, 1-based (default: 1)").option("--limit <n>", "(list) Rows per page · (comments list) Threads per page · max 100").option("--json", "Machine-readable JSON output (list/search/comments)").option("--status <status>", "(comments list) Filter by status: open | solved | all (default: open)").option("--author <author>", "(comments list) Filter by author name, email, or user id").option("--cursor <cursor>", "(comments list) Pagination cursor from a previous page").option("--quiet", "Print only ids, one per line (comments)").option("--file <path>", "(comments reply) Read the message body from this file").action(async (action, target, arg3, arg4, opts) => {
|
|
92793
|
+
cli.command("artifact [action] [target] [arg3] [arg4]", "Manage Takumi artifacts (list | search <term> | upload <file> | download <uuid|url> | delete <uuid|url> | open [uuid|url] | comments <verb> <ref> [id])").option("--id <uuid|url>", "Existing artifact (UUID or viewer URL) to overwrite on upload").option("--title <title>", "Display title for the artifact (max 200 chars)").option("-m, --message <message>", "(upload) Version note, max 100 chars · (comments reply) Comment body").option("-o, --output <dir>", "(download) Output directory; default: slug(title) or uuid in CWD").option("--ver <n>", "Version number (download: download it; delete: delete only that version; open: deep-link)").option("--force", "(download) Allow writing into a non-empty directory").option("-y, --yes", "Skip delete confirmation prompt").option("--access <level>", "(list) Filter by access level: private | restricted | organization").option("--page <n>", "(list) Page number, 1-based (default: 1)").option("--limit <n>", "(list) Rows per page · (comments list) Threads per page · max 100").option("--json", "Machine-readable JSON output (list/search/comments)").option("--status <status>", "(comments list) Filter by status: open | solved | all (default: open)").option("--author <author>", "(comments list) Filter by author name, email, or user id").option("--cursor <cursor>", "(comments list) Pagination cursor from a previous page").option("--quiet", "Print only ids, one per line (comments)").option("--file <path>", "(open) Deep-link to a file · (comments reply) Read the message body from this file").option("--thread <uuid>", "(open) Deep-link to a comment thread").option("--open", "(upload) Open the artifact in the browser after a successful upload").action(async (action, target, arg3, arg4, opts) => {
|
|
92492
92794
|
const version3 = parsePositiveIntFlag(opts.ver, "version", "--ver 2");
|
|
92493
92795
|
if (version3 === null)
|
|
92494
92796
|
return;
|
|
@@ -92498,7 +92800,13 @@ function registerCommands(cli) {
|
|
|
92498
92800
|
const limit = parsePositiveIntFlag(opts.limit, "limit", "--limit 25", ARTIFACT_LIST_LIMIT_MAX);
|
|
92499
92801
|
if (limit === null)
|
|
92500
92802
|
return;
|
|
92501
|
-
await artifactCommand(action, target, arg3, arg4, {
|
|
92803
|
+
await artifactCommand(action, target, arg3, arg4, {
|
|
92804
|
+
...opts,
|
|
92805
|
+
...stringifyFlags(opts, ARTIFACT_STRING_FLAGS),
|
|
92806
|
+
version: version3,
|
|
92807
|
+
page,
|
|
92808
|
+
limit
|
|
92809
|
+
});
|
|
92502
92810
|
});
|
|
92503
92811
|
cli.command("auth [action]", "Sign in/out, refresh, and check Takumi session (login|logout|refresh|status)").option("--json", "Machine-readable JSON output (status, refresh)").option("-f, --force", "Force a token refresh even when the current token is still valid (refresh only)").action(async (action, options2 = {}) => {
|
|
92504
92812
|
switch (action) {
|
|
@@ -92671,6 +92979,36 @@ function getPackageVersion3() {
|
|
|
92671
92979
|
return packageVersion2;
|
|
92672
92980
|
}
|
|
92673
92981
|
|
|
92982
|
+
// src/domains/installation/release-source.ts
|
|
92983
|
+
init_auth_client();
|
|
92984
|
+
class WorkerAssetError2 extends Error {
|
|
92985
|
+
status;
|
|
92986
|
+
reason;
|
|
92987
|
+
body;
|
|
92988
|
+
constructor(status2, reason, body) {
|
|
92989
|
+
super(`Worker asset fetch failed (HTTP ${status2}): ${reason}`);
|
|
92990
|
+
this.name = "WorkerAssetError";
|
|
92991
|
+
this.status = status2;
|
|
92992
|
+
this.reason = reason;
|
|
92993
|
+
this.body = body;
|
|
92994
|
+
}
|
|
92995
|
+
}
|
|
92996
|
+
class LicenseRequiredError2 extends Error {
|
|
92997
|
+
status = 403;
|
|
92998
|
+
reason;
|
|
92999
|
+
constructor(reason) {
|
|
93000
|
+
super(LICENSE_REQUIRED_REMEDIATION);
|
|
93001
|
+
this.name = "LicenseRequiredError";
|
|
93002
|
+
this.reason = reason ?? "no_license_or_entitlement";
|
|
93003
|
+
}
|
|
93004
|
+
}
|
|
93005
|
+
function isLicenseRequired(error) {
|
|
93006
|
+
return error instanceof LicenseRequiredError2 || error instanceof WorkerAssetError2 && error.reason === "LICENSE_REQUIRED";
|
|
93007
|
+
}
|
|
93008
|
+
|
|
93009
|
+
// src/domains/takumi-api/api-error-handler.ts
|
|
93010
|
+
var LICENSE_REQUIRED_EXIT_CODE2 = 4;
|
|
93011
|
+
|
|
92674
93012
|
// src/shared/logger.ts
|
|
92675
93013
|
init_output_manager();
|
|
92676
93014
|
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
@@ -93114,7 +93452,7 @@ var parsed = cli.parse(process.argv, { run: false });
|
|
|
93114
93452
|
}
|
|
93115
93453
|
} catch (error) {
|
|
93116
93454
|
console.error("CLI error:", error instanceof Error ? error.message : error);
|
|
93117
|
-
process.exitCode = 1;
|
|
93455
|
+
process.exitCode = isLicenseRequired(error) ? LICENSE_REQUIRED_EXIT_CODE2 : 1;
|
|
93118
93456
|
if (output2.isJson()) {
|
|
93119
93457
|
await output2.flushJson();
|
|
93120
93458
|
}
|