@driftless-sh/cli 0.1.37 → 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 +225 -71
- 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,89 @@ 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
|
+
}
|
|
216132
|
+
async function fetchRepos(slug) {
|
|
216133
|
+
try {
|
|
216134
|
+
const raw = await api.get(`/workspaces/${slug}/repos`);
|
|
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) };
|
|
216139
|
+
}
|
|
216140
|
+
}
|
|
216048
216141
|
async function resolveRepo() {
|
|
216049
216142
|
const remote = getGitRemote();
|
|
216050
216143
|
if (!remote) return { ok: false, reason: "no_remote" };
|
|
216051
|
-
|
|
216144
|
+
const configSlug = getCachedWorkspace().slug;
|
|
216145
|
+
let meSlug;
|
|
216146
|
+
let meWorkspaceId;
|
|
216147
|
+
let meReturned = false;
|
|
216148
|
+
let meError;
|
|
216052
216149
|
try {
|
|
216053
|
-
const me = await api.get("/me");
|
|
216054
|
-
|
|
216055
|
-
|
|
216150
|
+
const me = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
216151
|
+
meReturned = true;
|
|
216152
|
+
meSlug = me?.slug;
|
|
216153
|
+
meWorkspaceId = me?.workspace_id;
|
|
216154
|
+
if (meSlug) saveWorkspaceToConfig(meSlug, meWorkspaceId);
|
|
216155
|
+
} catch (e) {
|
|
216156
|
+
meError = e instanceof Error ? e.message : String(e);
|
|
216056
216157
|
}
|
|
216057
|
-
const
|
|
216058
|
-
let
|
|
216059
|
-
|
|
216060
|
-
|
|
216061
|
-
|
|
216158
|
+
const candidates = [...new Set([configSlug, meSlug, remote.org].filter(Boolean))];
|
|
216159
|
+
let lastLinkedSlug;
|
|
216160
|
+
let failedEndpoint;
|
|
216161
|
+
for (const slug of candidates) {
|
|
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);
|
|
216168
|
+
if (repo) {
|
|
216169
|
+
saveWorkspaceToConfig(slug, meWorkspaceId);
|
|
216170
|
+
return {
|
|
216171
|
+
ok: true,
|
|
216172
|
+
workspaceSlug: slug,
|
|
216173
|
+
repoId: repo.id,
|
|
216174
|
+
remote,
|
|
216175
|
+
hasScanBaseline: !!repo.scan_summary
|
|
216176
|
+
};
|
|
216177
|
+
}
|
|
216178
|
+
lastLinkedSlug = slug;
|
|
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
|
+
};
|
|
216191
|
+
if (lastLinkedSlug) {
|
|
216192
|
+
return { ok: false, reason: "not_linked", workspaceSlug: lastLinkedSlug, remote, diagnostics };
|
|
216062
216193
|
}
|
|
216063
|
-
if (!repos) return { ok: false, reason: "no_workspace", remote };
|
|
216064
|
-
const repo = repos.find((r) => r.github_org === remote.org && r.github_repo === remote.repo);
|
|
216065
|
-
if (!repo) return { ok: false, reason: "not_linked", workspaceSlug: slug, remote };
|
|
216066
216194
|
return {
|
|
216067
|
-
ok:
|
|
216068
|
-
|
|
216069
|
-
repoId: repo.id,
|
|
216195
|
+
ok: false,
|
|
216196
|
+
reason: "no_workspace",
|
|
216070
216197
|
remote,
|
|
216071
|
-
|
|
216198
|
+
detail: formatDiagnostics(diagnostics),
|
|
216199
|
+
diagnostics
|
|
216072
216200
|
};
|
|
216073
216201
|
}
|
|
216074
216202
|
|
|
@@ -216099,12 +216227,31 @@ async function syncCommand(args) {
|
|
|
216099
216227
|
const isJSON = !!flags["json"];
|
|
216100
216228
|
const resolution = await resolveRepo();
|
|
216101
216229
|
if (!resolution.ok) {
|
|
216102
|
-
|
|
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
|
+
}
|
|
216103
216245
|
if (!isJSON) {
|
|
216104
|
-
console.log(
|
|
216105
|
-
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.");
|
|
216106
216249
|
} else {
|
|
216107
|
-
emitJSON3({
|
|
216250
|
+
emitJSON3({
|
|
216251
|
+
error: "no_workspace",
|
|
216252
|
+
message: "could not resolve workspace",
|
|
216253
|
+
diagnostics: resolution.diagnostics
|
|
216254
|
+
});
|
|
216108
216255
|
}
|
|
216109
216256
|
process.exit(1);
|
|
216110
216257
|
}
|
|
@@ -216187,6 +216334,7 @@ var import_node_path6 = require("node:path");
|
|
|
216187
216334
|
var import_node_readline = require("node:readline");
|
|
216188
216335
|
var import_node_child_process2 = require("node:child_process");
|
|
216189
216336
|
var import_node_os2 = require("node:os");
|
|
216337
|
+
init_api_client();
|
|
216190
216338
|
var CONFIG_DIR = (0, import_node_path6.resolve)((0, import_node_os2.homedir)(), ".driftless");
|
|
216191
216339
|
var CONFIG_PATH2 = (0, import_node_path6.resolve)(CONFIG_DIR, "config.json");
|
|
216192
216340
|
function openBrowser(url) {
|
|
@@ -216198,7 +216346,7 @@ async function loginCommand(args) {
|
|
|
216198
216346
|
const keyIndex = args.indexOf("--key");
|
|
216199
216347
|
if (keyIndex !== -1 && args[keyIndex + 1]) {
|
|
216200
216348
|
const apiKey2 = args[keyIndex + 1];
|
|
216201
|
-
saveConfig(apiKey2);
|
|
216349
|
+
await saveConfig(apiKey2);
|
|
216202
216350
|
return;
|
|
216203
216351
|
}
|
|
216204
216352
|
const apiUrl = process.env["DRIFTLESS_API_URL"] || "https://api.driftless.icu/api/v1";
|
|
@@ -216229,9 +216377,9 @@ async function loginCommand(args) {
|
|
|
216229
216377
|
console.error("Get a valid key from your Driftless Dashboard \u2192 Settings \u2192 API Keys.");
|
|
216230
216378
|
process.exit(1);
|
|
216231
216379
|
}
|
|
216232
|
-
saveConfig(apiKey, apiUrl);
|
|
216380
|
+
await saveConfig(apiKey, apiUrl);
|
|
216233
216381
|
}
|
|
216234
|
-
function saveConfig(apiKey, apiUrl) {
|
|
216382
|
+
async function saveConfig(apiKey, apiUrl) {
|
|
216235
216383
|
const url = apiUrl || "https://api.driftless.icu/api/v1";
|
|
216236
216384
|
try {
|
|
216237
216385
|
if (!(0, import_node_fs6.existsSync)(CONFIG_DIR)) {
|
|
@@ -216241,16 +216389,24 @@ function saveConfig(apiKey, apiUrl) {
|
|
|
216241
216389
|
CONFIG_PATH2,
|
|
216242
216390
|
JSON.stringify({ api_key: apiKey, api_url: url }, null, 2) + "\n"
|
|
216243
216391
|
);
|
|
216244
|
-
console.log();
|
|
216245
|
-
console.log("Logged in successfully.");
|
|
216246
|
-
console.log(` Config: ${CONFIG_PATH2}`);
|
|
216247
|
-
console.log();
|
|
216248
|
-
console.log("Try: driftless scan --diff");
|
|
216249
|
-
process.exit(0);
|
|
216250
216392
|
} catch (err) {
|
|
216251
216393
|
console.error("Failed to save config:", err);
|
|
216252
216394
|
process.exit(1);
|
|
216253
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);
|
|
216254
216410
|
}
|
|
216255
216411
|
|
|
216256
216412
|
// src/commands/doctor.ts
|
|
@@ -216282,33 +216438,27 @@ async function doctorCommand() {
|
|
|
216282
216438
|
async function getMe() {
|
|
216283
216439
|
if (meCache) return meCache;
|
|
216284
216440
|
try {
|
|
216285
|
-
meCache = await api.get("/me");
|
|
216441
|
+
meCache = await api.get("/me", { timeoutMs: 8e3, retries: 1 });
|
|
216286
216442
|
} catch {
|
|
216287
216443
|
meCache = null;
|
|
216288
216444
|
}
|
|
216289
216445
|
return meCache;
|
|
216290
216446
|
}
|
|
216291
|
-
|
|
216292
|
-
|
|
216293
|
-
|
|
216294
|
-
try {
|
|
216295
|
-
reposCache = await api.get(`/workspaces/${slug}/repos`);
|
|
216296
|
-
} catch {
|
|
216297
|
-
reposCache = null;
|
|
216298
|
-
}
|
|
216299
|
-
return reposCache;
|
|
216300
|
-
}
|
|
216301
|
-
if (apiKey && apiUrl !== "http://localhost:3000/api/v1") {
|
|
216302
|
-
const me = await getMe();
|
|
216303
|
-
if (me?.slug) {
|
|
216304
|
-
checks.push({ name: "Workspace", status: "ok", detail: me.slug });
|
|
216305
|
-
} else {
|
|
216306
|
-
checks.push({ name: "Workspace", status: "warn", detail: "API returned no workspace. Run `driftless init`" });
|
|
216307
|
-
}
|
|
216308
|
-
} else {
|
|
216447
|
+
const resolution = await resolveRepo();
|
|
216448
|
+
const localOrNoKey = !apiKey || apiUrl === "http://localhost:3000/api/v1";
|
|
216449
|
+
if (localOrNoKey) {
|
|
216309
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)" });
|
|
216310
216461
|
}
|
|
216311
|
-
const resolution = await resolveRepo();
|
|
216312
216462
|
if (resolution.ok) {
|
|
216313
216463
|
checks.push({ name: "Repo linked", status: "ok", detail: `${resolution.remote.org}/${resolution.remote.repo}` });
|
|
216314
216464
|
checks.push({
|
|
@@ -216377,6 +216527,10 @@ async function doctorCommand() {
|
|
|
216377
216527
|
}
|
|
216378
216528
|
console.log(`
|
|
216379
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
|
+
}
|
|
216380
216534
|
if (failCount > 0) {
|
|
216381
216535
|
console.log("\nFix failures before running `driftless init` or `driftless scan`.");
|
|
216382
216536
|
process.exit(1);
|
|
@@ -216389,7 +216543,7 @@ function pad2(s, n) {
|
|
|
216389
216543
|
}
|
|
216390
216544
|
|
|
216391
216545
|
// src/index.ts
|
|
216392
|
-
var VERSION = "0.1.
|
|
216546
|
+
var VERSION = "0.1.39";
|
|
216393
216547
|
var HELP_TEXT = `Driftless CLI v${VERSION} \u2014 Living repo context for humans and coding agents
|
|
216394
216548
|
|
|
216395
216549
|
Install: npm install -g @driftless-sh/cli
|