@driftless-sh/cli 0.1.38 → 0.1.39
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 +207 -69
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -39,8 +39,38 @@ __export(api_client_exports, {
|
|
|
39
39
|
api: () => api,
|
|
40
40
|
formatError: () => formatError,
|
|
41
41
|
getApiKey: () => getApiKey,
|
|
42
|
-
getApiUrl: () => getApiUrl
|
|
42
|
+
getApiUrl: () => getApiUrl,
|
|
43
|
+
getCachedWorkspace: () => getCachedWorkspace,
|
|
44
|
+
saveWorkspaceToConfig: () => saveWorkspaceToConfig
|
|
43
45
|
});
|
|
46
|
+
function readConfig() {
|
|
47
|
+
try {
|
|
48
|
+
if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
|
|
49
|
+
return JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8"));
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
function getCachedWorkspace() {
|
|
56
|
+
const c = readConfig();
|
|
57
|
+
return { slug: c.workspace_slug, workspaceId: c.workspace_id };
|
|
58
|
+
}
|
|
59
|
+
function saveWorkspaceToConfig(slug, workspaceId) {
|
|
60
|
+
if (!slug) return;
|
|
61
|
+
try {
|
|
62
|
+
const c = readConfig();
|
|
63
|
+
if (c.workspace_slug === slug && (workspaceId === void 0 || c.workspace_id === workspaceId)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
c.workspace_slug = slug;
|
|
67
|
+
if (workspaceId !== void 0) c.workspace_id = workspaceId;
|
|
68
|
+
const dir = (0, import_node_path.dirname)(CONFIG_PATH);
|
|
69
|
+
if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
70
|
+
(0, import_node_fs.writeFileSync)(CONFIG_PATH, JSON.stringify(c, null, 2) + "\n");
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
44
74
|
function loadApiKey() {
|
|
45
75
|
const envKey = process.env["DRIFTLESS_API_KEY"];
|
|
46
76
|
if (envKey) return envKey;
|
|
@@ -94,7 +124,7 @@ function parseError(e) {
|
|
|
94
124
|
}
|
|
95
125
|
return msg;
|
|
96
126
|
}
|
|
97
|
-
function
|
|
127
|
+
function singleRequest(method, path, body, timeoutMs) {
|
|
98
128
|
return new Promise((resolve8, reject) => {
|
|
99
129
|
const baseUrl = getBaseUrl();
|
|
100
130
|
const fullUrl = `${baseUrl}${path}`;
|
|
@@ -128,11 +158,33 @@ function request(method, path, body) {
|
|
|
128
158
|
});
|
|
129
159
|
}
|
|
130
160
|
);
|
|
161
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
162
|
+
req.setTimeout(timeoutMs, () => {
|
|
163
|
+
req.destroy(new Error(`Request timed out after ${timeoutMs}ms`));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
131
166
|
req.on("error", (e) => reject(new Error(`Connection failed: ${e.message}`)));
|
|
132
167
|
if (body) req.write(JSON.stringify(body));
|
|
133
168
|
req.end();
|
|
134
169
|
});
|
|
135
170
|
}
|
|
171
|
+
function isTransient(err) {
|
|
172
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
173
|
+
return !/HTTP 4\d\d:/.test(msg);
|
|
174
|
+
}
|
|
175
|
+
async function request(method, path, body, opts) {
|
|
176
|
+
const retries = opts?.retries ?? 0;
|
|
177
|
+
let lastErr;
|
|
178
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
179
|
+
try {
|
|
180
|
+
return await singleRequest(method, path, body, opts?.timeoutMs);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
lastErr = e;
|
|
183
|
+
if (attempt === retries || !isTransient(e)) break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
throw lastErr;
|
|
187
|
+
}
|
|
136
188
|
function getApiUrl() {
|
|
137
189
|
return getBaseUrl();
|
|
138
190
|
}
|
|
@@ -154,11 +206,11 @@ var init_api_client = __esm({
|
|
|
154
206
|
CONFIG_PATH = (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".driftless", "config.json");
|
|
155
207
|
DEFAULT_URL = "http://localhost:3000/api/v1";
|
|
156
208
|
api = {
|
|
157
|
-
get: (path) => request("GET", path),
|
|
158
|
-
post: (path, body) => request("POST", path, body),
|
|
159
|
-
put: (path, body) => request("PUT", path, body),
|
|
160
|
-
patch: (path, body) => request("PATCH", path, body),
|
|
161
|
-
delete: (path) => request("DELETE", path)
|
|
209
|
+
get: (path, opts) => request("GET", path, void 0, opts),
|
|
210
|
+
post: (path, body, opts) => request("POST", path, body, opts),
|
|
211
|
+
put: (path, body, opts) => request("PUT", path, body, opts),
|
|
212
|
+
patch: (path, body, opts) => request("PATCH", path, body, opts),
|
|
213
|
+
delete: (path, opts) => request("DELETE", path, void 0, opts)
|
|
162
214
|
};
|
|
163
215
|
}
|
|
164
216
|
});
|
|
@@ -3184,7 +3236,7 @@ var require_typescript = __commonJS({
|
|
|
3184
3236
|
forEachYieldExpression: () => forEachYieldExpression,
|
|
3185
3237
|
formatColorAndReset: () => formatColorAndReset,
|
|
3186
3238
|
formatDiagnostic: () => formatDiagnostic,
|
|
3187
|
-
formatDiagnostics: () =>
|
|
3239
|
+
formatDiagnostics: () => formatDiagnostics2,
|
|
3188
3240
|
formatDiagnosticsWithColorAndContext: () => formatDiagnosticsWithColorAndContext,
|
|
3189
3241
|
formatGeneratedName: () => formatGeneratedName,
|
|
3190
3242
|
formatGeneratedNamePart: () => formatGeneratedNamePart,
|
|
@@ -138049,7 +138101,7 @@ ${lanes.join("\n")}
|
|
|
138049
138101
|
}
|
|
138050
138102
|
return sortAndDeduplicateDiagnostics(diagnostics || emptyArray);
|
|
138051
138103
|
}
|
|
138052
|
-
function
|
|
138104
|
+
function formatDiagnostics2(diagnostics, host) {
|
|
138053
138105
|
let output = "";
|
|
138054
138106
|
for (const diagnostic of diagnostics) {
|
|
138055
138107
|
output += formatDiagnostic(diagnostic, host);
|
|
@@ -198687,7 +198739,7 @@ ${options.prefix}` : "\n" : options.prefix
|
|
|
198687
198739
|
forEachYieldExpression: () => forEachYieldExpression,
|
|
198688
198740
|
formatColorAndReset: () => formatColorAndReset,
|
|
198689
198741
|
formatDiagnostic: () => formatDiagnostic,
|
|
198690
|
-
formatDiagnostics: () =>
|
|
198742
|
+
formatDiagnostics: () => formatDiagnostics2,
|
|
198691
198743
|
formatDiagnosticsWithColorAndContext: () => formatDiagnosticsWithColorAndContext,
|
|
198692
198744
|
formatGeneratedName: () => formatGeneratedName,
|
|
198693
198745
|
formatGeneratedNamePart: () => formatGeneratedNamePart,
|
|
@@ -214581,7 +214633,7 @@ async function installSkillCommand() {
|
|
|
214581
214633
|
// src/commands/init.ts
|
|
214582
214634
|
function getVersion() {
|
|
214583
214635
|
try {
|
|
214584
|
-
return "0.1.
|
|
214636
|
+
return "0.1.39";
|
|
214585
214637
|
} catch {
|
|
214586
214638
|
return "0.0.0";
|
|
214587
214639
|
}
|
|
@@ -214922,6 +214974,7 @@ async function initCommand(args) {
|
|
|
214922
214974
|
process.exit(1);
|
|
214923
214975
|
}
|
|
214924
214976
|
const workspaceSlug = workspace.slug;
|
|
214977
|
+
if (workspaceSlug) saveWorkspaceToConfig(workspaceSlug, workspace.workspace_id);
|
|
214925
214978
|
console.log(`Repository: ${remote.org}/${remote.repo}`);
|
|
214926
214979
|
console.log(`Workspace: ${workspaceSlug} \u2713`);
|
|
214927
214980
|
if (srcOverride) console.log(`Scan root: ${srcOverride}`);
|
|
@@ -215103,16 +215156,27 @@ async function scanCommand(args) {
|
|
|
215103
215156
|
process.exit(1);
|
|
215104
215157
|
}
|
|
215105
215158
|
const isJSON = args.includes("--json");
|
|
215106
|
-
let
|
|
215159
|
+
let workspaceSlug;
|
|
215160
|
+
let workspaceId;
|
|
215107
215161
|
try {
|
|
215108
|
-
|
|
215162
|
+
const me = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
215163
|
+
workspaceSlug = me?.slug;
|
|
215164
|
+
workspaceId = me?.workspace_id;
|
|
215165
|
+
if (workspaceSlug) saveWorkspaceToConfig(workspaceSlug, workspaceId);
|
|
215109
215166
|
} catch {
|
|
215167
|
+
}
|
|
215168
|
+
if (!workspaceSlug) {
|
|
215169
|
+
const cached = getCachedWorkspace();
|
|
215170
|
+
workspaceSlug = cached.slug;
|
|
215171
|
+
workspaceId = workspaceId ?? cached.workspaceId;
|
|
215172
|
+
}
|
|
215173
|
+
if (!workspaceSlug) {
|
|
215110
215174
|
console.error("Could not resolve workspace. Run driftless login first.");
|
|
215111
215175
|
process.exit(1);
|
|
215112
215176
|
}
|
|
215113
|
-
const repos = await api.get(`/workspaces/${
|
|
215177
|
+
const repos = await api.get(`/workspaces/${workspaceSlug}/repos`);
|
|
215114
215178
|
if (!Array.isArray(repos)) {
|
|
215115
|
-
console.error(`Error: Could not fetch repos for workspace '${
|
|
215179
|
+
console.error(`Error: Could not fetch repos for workspace '${workspaceSlug}'.`);
|
|
215116
215180
|
console.error(`Response:`, JSON.stringify(repos).slice(0, 200));
|
|
215117
215181
|
console.error("\nTip: Make sure your API key belongs to this workspace.");
|
|
215118
215182
|
console.error("Run: driftless login --key <key>");
|
|
@@ -215156,7 +215220,7 @@ async function scanCommand(args) {
|
|
|
215156
215220
|
}
|
|
215157
215221
|
}
|
|
215158
215222
|
const result = await api.post("/scan", {
|
|
215159
|
-
workspace_id:
|
|
215223
|
+
workspace_id: workspaceId,
|
|
215160
215224
|
repo_id: repo.id,
|
|
215161
215225
|
diff,
|
|
215162
215226
|
commit_hash: commitHash,
|
|
@@ -215164,7 +215228,7 @@ async function scanCommand(args) {
|
|
|
215164
215228
|
});
|
|
215165
215229
|
const rulesEvaluated = result.rules_evaluated || 0;
|
|
215166
215230
|
if (result.status === "clean") {
|
|
215167
|
-
analyticsEvent("cli_scan_run",
|
|
215231
|
+
analyticsEvent("cli_scan_run", workspaceSlug, { violations_found: false, count: 0 });
|
|
215168
215232
|
if (isJSON) {
|
|
215169
215233
|
emitJSON({ status: "clean", files: changedFiles, rules_evaluated: rulesEvaluated, violations: [] });
|
|
215170
215234
|
} else {
|
|
@@ -215173,7 +215237,7 @@ async function scanCommand(args) {
|
|
|
215173
215237
|
process.exit(0);
|
|
215174
215238
|
}
|
|
215175
215239
|
if (!result.violations || result.violations.length === 0) {
|
|
215176
|
-
analyticsEvent("cli_scan_run",
|
|
215240
|
+
analyticsEvent("cli_scan_run", workspaceSlug, { violations_found: false, count: 0 });
|
|
215177
215241
|
if (isJSON) {
|
|
215178
215242
|
emitJSON({ status: "clean", files: changedFiles, rules_evaluated: rulesEvaluated, violations: [] });
|
|
215179
215243
|
} else {
|
|
@@ -215181,7 +215245,7 @@ async function scanCommand(args) {
|
|
|
215181
215245
|
}
|
|
215182
215246
|
process.exit(0);
|
|
215183
215247
|
}
|
|
215184
|
-
analyticsEvent("cli_scan_run",
|
|
215248
|
+
analyticsEvent("cli_scan_run", workspaceSlug, { violations_found: true, count: result.violations.length });
|
|
215185
215249
|
if (isJSON) {
|
|
215186
215250
|
emitJSON({ status: "violated", files: changedFiles, rules_evaluated: rulesEvaluated, violations: result.violations });
|
|
215187
215251
|
} else {
|
|
@@ -215379,10 +215443,15 @@ function countLocalFilesMatching(pattern) {
|
|
|
215379
215443
|
}
|
|
215380
215444
|
async function resolveWorkspaceSlug() {
|
|
215381
215445
|
try {
|
|
215382
|
-
const me = await api.get("/me");
|
|
215383
|
-
if (me?.slug)
|
|
215446
|
+
const me = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
215447
|
+
if (me?.slug) {
|
|
215448
|
+
saveWorkspaceToConfig(me.slug, me.workspace_id);
|
|
215449
|
+
return me.slug;
|
|
215450
|
+
}
|
|
215384
215451
|
} catch {
|
|
215385
215452
|
}
|
|
215453
|
+
const cached = getCachedWorkspace().slug;
|
|
215454
|
+
if (cached) return cached;
|
|
215386
215455
|
const remote = getGitRemote();
|
|
215387
215456
|
if (!remote) {
|
|
215388
215457
|
console.error("Error: no git remote found.");
|
|
@@ -216045,30 +216114,59 @@ init_api_client();
|
|
|
216045
216114
|
function notLinkedMessage(remote, workspaceSlug) {
|
|
216046
216115
|
return `Repo '${remote.org}/${remote.repo}' is not registered in workspace '${workspaceSlug}'. Run \`driftless init\` to register it.`;
|
|
216047
216116
|
}
|
|
216117
|
+
function formatDiagnostics(d) {
|
|
216118
|
+
const lines = [];
|
|
216119
|
+
if (d.remote) lines.push(` repo: ${d.remote.org}/${d.remote.repo}`);
|
|
216120
|
+
lines.push(` tried slugs: ${d.triedSlugs.length ? d.triedSlugs.join(", ") : "(none)"}`);
|
|
216121
|
+
lines.push(` config slug: ${d.configSlug ?? "(not cached \u2014 run `driftless login` or `driftless init`)"}`);
|
|
216122
|
+
if (!d.meAttempted) {
|
|
216123
|
+
lines.push(" /me: not attempted");
|
|
216124
|
+
} else if (d.meReturned) {
|
|
216125
|
+
lines.push(` /me: returned slug=${d.meSlug ?? "(none)"} workspace_id=${d.meWorkspaceId ?? "(none)"}`);
|
|
216126
|
+
} else {
|
|
216127
|
+
lines.push(` /me: FAILED \u2014 ${d.meError ?? "unknown error"}`);
|
|
216128
|
+
}
|
|
216129
|
+
if (d.failedEndpoint) lines.push(` last endpoint: ${d.failedEndpoint} (rejected)`);
|
|
216130
|
+
return lines.join("\n");
|
|
216131
|
+
}
|
|
216048
216132
|
async function fetchRepos(slug) {
|
|
216049
216133
|
try {
|
|
216050
216134
|
const raw = await api.get(`/workspaces/${slug}/repos`);
|
|
216051
|
-
|
|
216052
|
-
|
|
216053
|
-
|
|
216135
|
+
if (Array.isArray(raw)) return { repos: raw };
|
|
216136
|
+
return { error: "unexpected response shape" };
|
|
216137
|
+
} catch (e) {
|
|
216138
|
+
return { error: e instanceof Error ? e.message : String(e) };
|
|
216054
216139
|
}
|
|
216055
216140
|
}
|
|
216056
216141
|
async function resolveRepo() {
|
|
216057
216142
|
const remote = getGitRemote();
|
|
216058
216143
|
if (!remote) return { ok: false, reason: "no_remote" };
|
|
216144
|
+
const configSlug = getCachedWorkspace().slug;
|
|
216059
216145
|
let meSlug;
|
|
216146
|
+
let meWorkspaceId;
|
|
216147
|
+
let meReturned = false;
|
|
216148
|
+
let meError;
|
|
216060
216149
|
try {
|
|
216061
|
-
const me = await api.get("/me");
|
|
216150
|
+
const me = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
216151
|
+
meReturned = true;
|
|
216062
216152
|
meSlug = me?.slug;
|
|
216063
|
-
|
|
216153
|
+
meWorkspaceId = me?.workspace_id;
|
|
216154
|
+
if (meSlug) saveWorkspaceToConfig(meSlug, meWorkspaceId);
|
|
216155
|
+
} catch (e) {
|
|
216156
|
+
meError = e instanceof Error ? e.message : String(e);
|
|
216064
216157
|
}
|
|
216065
|
-
const candidates = [...new Set([meSlug, remote.org].filter(Boolean))];
|
|
216158
|
+
const candidates = [...new Set([configSlug, meSlug, remote.org].filter(Boolean))];
|
|
216066
216159
|
let lastLinkedSlug;
|
|
216160
|
+
let failedEndpoint;
|
|
216067
216161
|
for (const slug of candidates) {
|
|
216068
|
-
const
|
|
216069
|
-
if (
|
|
216070
|
-
|
|
216162
|
+
const result = await fetchRepos(slug);
|
|
216163
|
+
if ("error" in result) {
|
|
216164
|
+
failedEndpoint = `/workspaces/${slug}/repos`;
|
|
216165
|
+
continue;
|
|
216166
|
+
}
|
|
216167
|
+
const repo = result.repos.find((r) => r.github_org === remote.org && r.github_repo === remote.repo);
|
|
216071
216168
|
if (repo) {
|
|
216169
|
+
saveWorkspaceToConfig(slug, meWorkspaceId);
|
|
216072
216170
|
return {
|
|
216073
216171
|
ok: true,
|
|
216074
216172
|
workspaceSlug: slug,
|
|
@@ -216079,11 +216177,27 @@ async function resolveRepo() {
|
|
|
216079
216177
|
}
|
|
216080
216178
|
lastLinkedSlug = slug;
|
|
216081
216179
|
}
|
|
216180
|
+
const diagnostics = {
|
|
216181
|
+
remote,
|
|
216182
|
+
triedSlugs: candidates,
|
|
216183
|
+
configSlug,
|
|
216184
|
+
meAttempted: true,
|
|
216185
|
+
meReturned,
|
|
216186
|
+
meSlug,
|
|
216187
|
+
meWorkspaceId,
|
|
216188
|
+
meError,
|
|
216189
|
+
failedEndpoint
|
|
216190
|
+
};
|
|
216082
216191
|
if (lastLinkedSlug) {
|
|
216083
|
-
return { ok: false, reason: "not_linked", workspaceSlug: lastLinkedSlug, remote };
|
|
216192
|
+
return { ok: false, reason: "not_linked", workspaceSlug: lastLinkedSlug, remote, diagnostics };
|
|
216084
216193
|
}
|
|
216085
|
-
|
|
216086
|
-
|
|
216194
|
+
return {
|
|
216195
|
+
ok: false,
|
|
216196
|
+
reason: "no_workspace",
|
|
216197
|
+
remote,
|
|
216198
|
+
detail: formatDiagnostics(diagnostics),
|
|
216199
|
+
diagnostics
|
|
216200
|
+
};
|
|
216087
216201
|
}
|
|
216088
216202
|
|
|
216089
216203
|
// src/commands/sync.ts
|
|
@@ -216113,14 +216227,31 @@ async function syncCommand(args) {
|
|
|
216113
216227
|
const isJSON = !!flags["json"];
|
|
216114
216228
|
const resolution = await resolveRepo();
|
|
216115
216229
|
if (!resolution.ok) {
|
|
216116
|
-
|
|
216117
|
-
|
|
216118
|
-
|
|
216230
|
+
if (resolution.reason === "no_remote") {
|
|
216231
|
+
if (!isJSON) console.log("\u26A0 Error: no git remote configured.");
|
|
216232
|
+
else emitJSON3({ error: "no_remote", message: "no git remote configured" });
|
|
216233
|
+
process.exit(1);
|
|
216234
|
+
}
|
|
216235
|
+
if (resolution.reason === "not_linked") {
|
|
216236
|
+
const msg = notLinkedMessage(resolution.remote, resolution.workspaceSlug);
|
|
216237
|
+
if (!isJSON) {
|
|
216238
|
+
console.log(`\u26A0 ${msg}`);
|
|
216239
|
+
console.log(" Run `driftless doctor` to diagnose.");
|
|
216240
|
+
} else {
|
|
216241
|
+
emitJSON3({ error: "not_linked", message: msg, diagnostics: resolution.diagnostics });
|
|
216242
|
+
}
|
|
216243
|
+
process.exit(1);
|
|
216244
|
+
}
|
|
216119
216245
|
if (!isJSON) {
|
|
216120
|
-
console.log(
|
|
216121
|
-
if (resolution.
|
|
216246
|
+
console.log("\u26A0 Error: could not resolve workspace.");
|
|
216247
|
+
if (resolution.detail) console.log(resolution.detail);
|
|
216248
|
+
console.log(" Run `driftless doctor` to diagnose.");
|
|
216122
216249
|
} else {
|
|
216123
|
-
emitJSON3({
|
|
216250
|
+
emitJSON3({
|
|
216251
|
+
error: "no_workspace",
|
|
216252
|
+
message: "could not resolve workspace",
|
|
216253
|
+
diagnostics: resolution.diagnostics
|
|
216254
|
+
});
|
|
216124
216255
|
}
|
|
216125
216256
|
process.exit(1);
|
|
216126
216257
|
}
|
|
@@ -216203,6 +216334,7 @@ var import_node_path6 = require("node:path");
|
|
|
216203
216334
|
var import_node_readline = require("node:readline");
|
|
216204
216335
|
var import_node_child_process2 = require("node:child_process");
|
|
216205
216336
|
var import_node_os2 = require("node:os");
|
|
216337
|
+
init_api_client();
|
|
216206
216338
|
var CONFIG_DIR = (0, import_node_path6.resolve)((0, import_node_os2.homedir)(), ".driftless");
|
|
216207
216339
|
var CONFIG_PATH2 = (0, import_node_path6.resolve)(CONFIG_DIR, "config.json");
|
|
216208
216340
|
function openBrowser(url) {
|
|
@@ -216214,7 +216346,7 @@ async function loginCommand(args) {
|
|
|
216214
216346
|
const keyIndex = args.indexOf("--key");
|
|
216215
216347
|
if (keyIndex !== -1 && args[keyIndex + 1]) {
|
|
216216
216348
|
const apiKey2 = args[keyIndex + 1];
|
|
216217
|
-
saveConfig(apiKey2);
|
|
216349
|
+
await saveConfig(apiKey2);
|
|
216218
216350
|
return;
|
|
216219
216351
|
}
|
|
216220
216352
|
const apiUrl = process.env["DRIFTLESS_API_URL"] || "https://api.driftless.icu/api/v1";
|
|
@@ -216245,9 +216377,9 @@ async function loginCommand(args) {
|
|
|
216245
216377
|
console.error("Get a valid key from your Driftless Dashboard \u2192 Settings \u2192 API Keys.");
|
|
216246
216378
|
process.exit(1);
|
|
216247
216379
|
}
|
|
216248
|
-
saveConfig(apiKey, apiUrl);
|
|
216380
|
+
await saveConfig(apiKey, apiUrl);
|
|
216249
216381
|
}
|
|
216250
|
-
function saveConfig(apiKey, apiUrl) {
|
|
216382
|
+
async function saveConfig(apiKey, apiUrl) {
|
|
216251
216383
|
const url = apiUrl || "https://api.driftless.icu/api/v1";
|
|
216252
216384
|
try {
|
|
216253
216385
|
if (!(0, import_node_fs6.existsSync)(CONFIG_DIR)) {
|
|
@@ -216257,16 +216389,24 @@ function saveConfig(apiKey, apiUrl) {
|
|
|
216257
216389
|
CONFIG_PATH2,
|
|
216258
216390
|
JSON.stringify({ api_key: apiKey, api_url: url }, null, 2) + "\n"
|
|
216259
216391
|
);
|
|
216260
|
-
console.log();
|
|
216261
|
-
console.log("Logged in successfully.");
|
|
216262
|
-
console.log(` Config: ${CONFIG_PATH2}`);
|
|
216263
|
-
console.log();
|
|
216264
|
-
console.log("Try: driftless scan --diff");
|
|
216265
|
-
process.exit(0);
|
|
216266
216392
|
} catch (err) {
|
|
216267
216393
|
console.error("Failed to save config:", err);
|
|
216268
216394
|
process.exit(1);
|
|
216269
216395
|
}
|
|
216396
|
+
console.log();
|
|
216397
|
+
console.log("Logged in successfully.");
|
|
216398
|
+
console.log(` Config: ${CONFIG_PATH2}`);
|
|
216399
|
+
try {
|
|
216400
|
+
const me = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
216401
|
+
if (me?.slug) {
|
|
216402
|
+
saveWorkspaceToConfig(me.slug, me.workspace_id);
|
|
216403
|
+
console.log(` Workspace: ${me.slug}`);
|
|
216404
|
+
}
|
|
216405
|
+
} catch {
|
|
216406
|
+
}
|
|
216407
|
+
console.log();
|
|
216408
|
+
console.log("Try: driftless scan --diff");
|
|
216409
|
+
process.exit(0);
|
|
216270
216410
|
}
|
|
216271
216411
|
|
|
216272
216412
|
// src/commands/doctor.ts
|
|
@@ -216298,33 +216438,27 @@ async function doctorCommand() {
|
|
|
216298
216438
|
async function getMe() {
|
|
216299
216439
|
if (meCache) return meCache;
|
|
216300
216440
|
try {
|
|
216301
|
-
meCache = await api.get("/me");
|
|
216441
|
+
meCache = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
216302
216442
|
} catch {
|
|
216303
216443
|
meCache = null;
|
|
216304
216444
|
}
|
|
216305
216445
|
return meCache;
|
|
216306
216446
|
}
|
|
216307
|
-
|
|
216308
|
-
|
|
216309
|
-
|
|
216310
|
-
try {
|
|
216311
|
-
reposCache = await api.get(`/workspaces/${slug}/repos`);
|
|
216312
|
-
} catch {
|
|
216313
|
-
reposCache = null;
|
|
216314
|
-
}
|
|
216315
|
-
return reposCache;
|
|
216316
|
-
}
|
|
216317
|
-
if (apiKey && apiUrl !== "http://localhost:3000/api/v1") {
|
|
216318
|
-
const me = await getMe();
|
|
216319
|
-
if (me?.slug) {
|
|
216320
|
-
checks.push({ name: "Workspace", status: "ok", detail: me.slug });
|
|
216321
|
-
} else {
|
|
216322
|
-
checks.push({ name: "Workspace", status: "warn", detail: "API returned no workspace. Run `driftless init`" });
|
|
216323
|
-
}
|
|
216324
|
-
} else {
|
|
216447
|
+
const resolution = await resolveRepo();
|
|
216448
|
+
const localOrNoKey = !apiKey || apiUrl === "http://localhost:3000/api/v1";
|
|
216449
|
+
if (localOrNoKey) {
|
|
216325
216450
|
checks.push({ name: "Workspace", status: "warn", detail: "Skipped (local API or no key)" });
|
|
216451
|
+
} else if (resolution.ok) {
|
|
216452
|
+
checks.push({ name: "Workspace", status: "ok", detail: resolution.workspaceSlug });
|
|
216453
|
+
} else if (resolution.reason === "not_linked" && resolution.workspaceSlug) {
|
|
216454
|
+
checks.push({ name: "Workspace", status: "ok", detail: resolution.workspaceSlug });
|
|
216455
|
+
} else if (resolution.reason === "no_workspace" && resolution.diagnostics) {
|
|
216456
|
+
const d = resolution.diagnostics;
|
|
216457
|
+
const detail = !d.meReturned && d.meError ? `/me failed (${d.meError}); cached=${d.configSlug ?? "none"}` : "Could not resolve. Run `driftless init`";
|
|
216458
|
+
checks.push({ name: "Workspace", status: "warn", detail });
|
|
216459
|
+
} else {
|
|
216460
|
+
checks.push({ name: "Workspace", status: "warn", detail: "Could not resolve (no git remote)" });
|
|
216326
216461
|
}
|
|
216327
|
-
const resolution = await resolveRepo();
|
|
216328
216462
|
if (resolution.ok) {
|
|
216329
216463
|
checks.push({ name: "Repo linked", status: "ok", detail: `${resolution.remote.org}/${resolution.remote.repo}` });
|
|
216330
216464
|
checks.push({
|
|
@@ -216393,6 +216527,10 @@ async function doctorCommand() {
|
|
|
216393
216527
|
}
|
|
216394
216528
|
console.log(`
|
|
216395
216529
|
${okCount} ok, ${warnCount} warnings, ${failCount} failures`);
|
|
216530
|
+
if (!resolution.ok && resolution.reason === "no_workspace" && resolution.diagnostics) {
|
|
216531
|
+
console.log("\nWorkspace resolution diagnostics:");
|
|
216532
|
+
console.log(formatDiagnostics(resolution.diagnostics));
|
|
216533
|
+
}
|
|
216396
216534
|
if (failCount > 0) {
|
|
216397
216535
|
console.log("\nFix failures before running `driftless init` or `driftless scan`.");
|
|
216398
216536
|
process.exit(1);
|
|
@@ -216405,7 +216543,7 @@ function pad2(s, n) {
|
|
|
216405
216543
|
}
|
|
216406
216544
|
|
|
216407
216545
|
// src/index.ts
|
|
216408
|
-
var VERSION = "0.1.
|
|
216546
|
+
var VERSION = "0.1.39";
|
|
216409
216547
|
var HELP_TEXT = `Driftless CLI v${VERSION} \u2014 Living repo context for humans and coding agents
|
|
216410
216548
|
|
|
216411
216549
|
Install: npm install -g @driftless-sh/cli
|