md4ai 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.bundled.js +125 -12
- package/package.json +1 -1
package/dist/index.bundled.js
CHANGED
|
@@ -73,7 +73,7 @@ var CURRENT_VERSION;
|
|
|
73
73
|
var init_check_update = __esm({
|
|
74
74
|
"dist/check-update.js"() {
|
|
75
75
|
"use strict";
|
|
76
|
-
CURRENT_VERSION = true ? "0.
|
|
76
|
+
CURRENT_VERSION = true ? "0.12.0" : "0.0.0-dev";
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -1713,6 +1713,10 @@ async function validateDopplerToken(token) {
|
|
|
1713
1713
|
throw err;
|
|
1714
1714
|
}
|
|
1715
1715
|
}
|
|
1716
|
+
async function fetchDopplerProjects(token) {
|
|
1717
|
+
const data = await dopplerFetch("https://api.doppler.com/v3/projects", token);
|
|
1718
|
+
return data.projects.map((p) => ({ slug: p.slug, name: p.name }));
|
|
1719
|
+
}
|
|
1716
1720
|
var DopplerApiError, MAX_RETRIES;
|
|
1717
1721
|
var init_api = __esm({
|
|
1718
1722
|
"dist/doppler/api.js"() {
|
|
@@ -1733,9 +1737,10 @@ var init_api = __esm({
|
|
|
1733
1737
|
|
|
1734
1738
|
// dist/scanner/doppler-scanner.js
|
|
1735
1739
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
1736
|
-
import { join as join11 } from "node:path";
|
|
1740
|
+
import { join as join11, basename } from "node:path";
|
|
1737
1741
|
import { existsSync as existsSync6 } from "node:fs";
|
|
1738
1742
|
import chalk10 from "chalk";
|
|
1743
|
+
import { select as select3 } from "@inquirer/prompts";
|
|
1739
1744
|
async function parseDopplerYaml(projectRoot) {
|
|
1740
1745
|
const yamlPath = join11(projectRoot, "doppler.yaml");
|
|
1741
1746
|
if (!existsSync6(yamlPath))
|
|
@@ -1751,6 +1756,7 @@ async function parseDopplerYaml(projectRoot) {
|
|
|
1751
1756
|
async function scanDoppler(projectRoot, folderId) {
|
|
1752
1757
|
const tokenResult = await resolveDopplerToken();
|
|
1753
1758
|
if (!tokenResult) {
|
|
1759
|
+
console.log(chalk10.dim(' Doppler: no token configured. Run "md4ai doppler connect" to set up.'));
|
|
1754
1760
|
return null;
|
|
1755
1761
|
}
|
|
1756
1762
|
let projectSlug = await parseDopplerYaml(projectRoot);
|
|
@@ -1762,7 +1768,40 @@ async function scanDoppler(projectRoot, folderId) {
|
|
|
1762
1768
|
matchedVia = "manual";
|
|
1763
1769
|
}
|
|
1764
1770
|
if (!projectSlug) {
|
|
1765
|
-
|
|
1771
|
+
if (!folderId || !process.stdin.isTTY) {
|
|
1772
|
+
console.log(chalk10.dim(' Doppler: token configured but no project linked. Run "md4ai doppler set-project <slug>" to link one.'));
|
|
1773
|
+
return null;
|
|
1774
|
+
}
|
|
1775
|
+
const projects = await fetchDopplerProjects(tokenResult.token);
|
|
1776
|
+
if (projects.length === 0) {
|
|
1777
|
+
console.log(chalk10.yellow(" Doppler: no projects accessible with this token."));
|
|
1778
|
+
return null;
|
|
1779
|
+
}
|
|
1780
|
+
const projectName = basename(projectRoot);
|
|
1781
|
+
if (projects.length === 1) {
|
|
1782
|
+
projectSlug = projects[0].slug;
|
|
1783
|
+
console.log(chalk10.green(` Doppler: using "${projectSlug}" (only accessible project).`));
|
|
1784
|
+
} else {
|
|
1785
|
+
const autoMatch = projects.find((p) => p.slug.toLowerCase() === projectName.toLowerCase());
|
|
1786
|
+
if (autoMatch) {
|
|
1787
|
+
projectSlug = autoMatch.slug;
|
|
1788
|
+
console.log(chalk10.green(` Doppler: auto-matched project "${projectSlug}" from project name.`));
|
|
1789
|
+
} else {
|
|
1790
|
+
projectSlug = await select3({
|
|
1791
|
+
message: `Which Doppler project holds secrets for "${projectName}"?`,
|
|
1792
|
+
choices: projects.map((p) => ({
|
|
1793
|
+
name: `${p.slug}${p.name !== p.slug ? ` (${p.name})` : ""}`,
|
|
1794
|
+
value: p.slug
|
|
1795
|
+
}))
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
const state = await loadState();
|
|
1800
|
+
const dopplerProjects = state.dopplerProjects ?? {};
|
|
1801
|
+
dopplerProjects[folderId] = projectSlug;
|
|
1802
|
+
await saveState({ dopplerProjects });
|
|
1803
|
+
matchedVia = "manual";
|
|
1804
|
+
console.log(chalk10.dim(` Doppler: saved "${projectSlug}" for this project. To change: md4ai doppler set-project <slug>`));
|
|
1766
1805
|
}
|
|
1767
1806
|
console.log(chalk10.dim(` Doppler: checking project "${projectSlug}" (via ${matchedVia})...`));
|
|
1768
1807
|
try {
|
|
@@ -2274,11 +2313,11 @@ var map_exports = {};
|
|
|
2274
2313
|
__export(map_exports, {
|
|
2275
2314
|
mapCommand: () => mapCommand
|
|
2276
2315
|
});
|
|
2277
|
-
import { resolve as resolve4, basename } from "node:path";
|
|
2316
|
+
import { resolve as resolve4, basename as basename2 } from "node:path";
|
|
2278
2317
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
2279
2318
|
import { existsSync as existsSync8 } from "node:fs";
|
|
2280
2319
|
import chalk12 from "chalk";
|
|
2281
|
-
import { select as
|
|
2320
|
+
import { select as select4, input as input5, confirm as confirm2 } from "@inquirer/prompts";
|
|
2282
2321
|
async function mapCommand(path, options) {
|
|
2283
2322
|
await checkForUpdate();
|
|
2284
2323
|
const projectRoot = resolve4(path ?? process.cwd());
|
|
@@ -2288,7 +2327,16 @@ async function mapCommand(path, options) {
|
|
|
2288
2327
|
}
|
|
2289
2328
|
console.log(chalk12.blue(`Scanning: ${projectRoot}
|
|
2290
2329
|
`));
|
|
2291
|
-
|
|
2330
|
+
let earlyFolderId;
|
|
2331
|
+
if (!options.offline) {
|
|
2332
|
+
try {
|
|
2333
|
+
const { supabase: earlyDb } = await getAuthenticatedClient();
|
|
2334
|
+
const { data: dp } = await earlyDb.from("device_paths").select("folder_id").eq("path", projectRoot).maybeSingle();
|
|
2335
|
+
earlyFolderId = dp?.folder_id ?? void 0;
|
|
2336
|
+
} catch {
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
const result = await scanProject(projectRoot, earlyFolderId);
|
|
2292
2340
|
console.log(` Files found: ${result.graph.nodes.length}`);
|
|
2293
2341
|
console.log(` References: ${result.graph.edges.length}`);
|
|
2294
2342
|
console.log(` Broken refs: ${result.brokenRefs.length}`);
|
|
@@ -2297,7 +2345,7 @@ async function mapCommand(path, options) {
|
|
|
2297
2345
|
console.log(` Skills: ${result.skills.length}`);
|
|
2298
2346
|
console.log(` Toolings: ${result.toolings.length}`);
|
|
2299
2347
|
console.log(` Env Vars: ${result.envManifest?.variables.length ?? 0} (${result.envManifest ? "manifest found" : "no manifest"})`);
|
|
2300
|
-
console.log(` Doppler: ${result.doppler ? `${result.doppler.configs.length} config(s)` : "
|
|
2348
|
+
console.log(` Doppler: ${result.doppler ? `${result.doppler.configs.length} config(s) \u2014 ${result.doppler.project}` : "see above"}`);
|
|
2301
2349
|
console.log(` Plugins: ${result.marketplacePlugins.length} (${result.marketplacePlugins.reduce((n, p) => n + p.skills.length, 0)} skills)`);
|
|
2302
2350
|
console.log(` Data hash: ${result.dataHash.slice(0, 12)}...`);
|
|
2303
2351
|
if (result.brokenRefs.length > 0) {
|
|
@@ -2438,7 +2486,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2438
2486
|
{ name: "+ Create a new project", value: "__new__" },
|
|
2439
2487
|
...(folders ?? []).map((f) => ({ name: f.name, value: f.id }))
|
|
2440
2488
|
];
|
|
2441
|
-
const chosen = await
|
|
2489
|
+
const chosen = await select4({
|
|
2442
2490
|
message: "Link to which project?",
|
|
2443
2491
|
choices
|
|
2444
2492
|
});
|
|
@@ -2446,7 +2494,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2446
2494
|
if (chosen === "__new__") {
|
|
2447
2495
|
const projectName = await input5({
|
|
2448
2496
|
message: "Project name:",
|
|
2449
|
-
default:
|
|
2497
|
+
default: basename2(projectRoot)
|
|
2450
2498
|
});
|
|
2451
2499
|
const { data: newFolder, error: createErr } = await sb.from("claude_folders").insert({ user_id: userId, name: projectName }).select("id").single();
|
|
2452
2500
|
if (createErr || !newFolder) {
|
|
@@ -3782,7 +3830,7 @@ Linking "${folder.name}" to this device...
|
|
|
3782
3830
|
console.log(` Skills: ${result.skills.length}`);
|
|
3783
3831
|
console.log(` Toolings: ${result.toolings.length}`);
|
|
3784
3832
|
console.log(` Env Vars: ${result.envManifest?.variables.length ?? 0} (${result.envManifest ? "manifest found" : "no manifest"})`);
|
|
3785
|
-
console.log(` Doppler: ${result.doppler ? `${result.doppler.configs.length} config(s)` : "
|
|
3833
|
+
console.log(` Doppler: ${result.doppler ? `${result.doppler.configs.length} config(s) \u2014 ${result.doppler.project}` : "see above"}`);
|
|
3786
3834
|
console.log(` Plugins: ${result.marketplacePlugins.length} (${result.marketplacePlugins.reduce((n, p) => n + p.skills.length, 0)} skills)`);
|
|
3787
3835
|
const { error: scanErr } = await supabase.from("claude_folders").update({
|
|
3788
3836
|
graph_json: result.graph,
|
|
@@ -4581,6 +4629,8 @@ async function configSetCommand(key, value) {
|
|
|
4581
4629
|
// dist/commands/doppler.js
|
|
4582
4630
|
init_config();
|
|
4583
4631
|
init_api();
|
|
4632
|
+
init_auth();
|
|
4633
|
+
init_dist();
|
|
4584
4634
|
import chalk26 from "chalk";
|
|
4585
4635
|
import { input as input7 } from "@inquirer/prompts";
|
|
4586
4636
|
async function dopplerConnectCommand() {
|
|
@@ -4599,7 +4649,51 @@ async function dopplerConnectCommand() {
|
|
|
4599
4649
|
await mergeCredentials({ dopplerToken: token });
|
|
4600
4650
|
console.log(chalk26.green(`Token validated \u2014 ${projectCount} project${projectCount !== 1 ? "s" : ""} accessible.`));
|
|
4601
4651
|
console.log(chalk26.green("Saved to ~/.md4ai/credentials.json"));
|
|
4602
|
-
|
|
4652
|
+
const creds = await loadCredentials();
|
|
4653
|
+
if (!creds?.accessToken || !creds?.userId) {
|
|
4654
|
+
console.log("");
|
|
4655
|
+
console.log(chalk26.yellow("\u26A0 Not logged in to MD4AI \u2014 token saved locally only."));
|
|
4656
|
+
console.log(chalk26.yellow(" The web dashboard cannot show live Doppler status until the token is synced."));
|
|
4657
|
+
console.log(chalk26.yellow(' To fix: run "md4ai login", then "md4ai doppler connect" again.'));
|
|
4658
|
+
} else {
|
|
4659
|
+
let supabase = createSupabaseClient(getAnonKey(), creds.accessToken);
|
|
4660
|
+
let userId = creds.userId;
|
|
4661
|
+
if (Date.now() > creds.expiresAt) {
|
|
4662
|
+
const refreshed = await refreshSession();
|
|
4663
|
+
if (refreshed) {
|
|
4664
|
+
supabase = refreshed.supabase;
|
|
4665
|
+
userId = refreshed.userId;
|
|
4666
|
+
} else {
|
|
4667
|
+
console.log("");
|
|
4668
|
+
console.log(chalk26.yellow("\u26A0 Session expired \u2014 token saved locally only."));
|
|
4669
|
+
console.log(chalk26.yellow(' To sync to the web dashboard: run "md4ai login", then "md4ai doppler connect" again.'));
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
if (supabase) {
|
|
4673
|
+
try {
|
|
4674
|
+
const { error } = await supabase.from("user_secrets").upsert({ user_id: userId, doppler_token: token, updated_at: (/* @__PURE__ */ new Date()).toISOString() }, { onConflict: "user_id" });
|
|
4675
|
+
if (error) {
|
|
4676
|
+
console.log(chalk26.yellow(`\u26A0 Could not sync token to web dashboard: ${error.message}`));
|
|
4677
|
+
} else {
|
|
4678
|
+
const { data: verify } = await supabase.from("user_secrets").select("id").eq("user_id", userId).maybeSingle();
|
|
4679
|
+
if (verify) {
|
|
4680
|
+
console.log(chalk26.green("Token synced to web dashboard."));
|
|
4681
|
+
} else {
|
|
4682
|
+
console.log(chalk26.yellow("\u26A0 Token sync could not be verified \u2014 check the web dashboard."));
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
} catch (err) {
|
|
4686
|
+
console.log(chalk26.yellow(`\u26A0 Could not sync token to web dashboard: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
console.log("");
|
|
4691
|
+
console.log(chalk26.cyan("Next step: link a Doppler project to your Claude project."));
|
|
4692
|
+
console.log(chalk26.dim(" The scanner looks for a doppler.yaml in the project root, e.g.:"));
|
|
4693
|
+
console.log(chalk26.dim(" project: my-doppler-project"));
|
|
4694
|
+
console.log(chalk26.dim(" Or use a manual override:"));
|
|
4695
|
+
console.log(chalk26.dim(" md4ai doppler set-project <slug>"));
|
|
4696
|
+
console.log(chalk26.dim(' Then run "md4ai scan" to fetch secret names from Doppler.'));
|
|
4603
4697
|
}
|
|
4604
4698
|
async function dopplerDisconnectCommand() {
|
|
4605
4699
|
const creds = await loadCredentials();
|
|
@@ -4614,7 +4708,26 @@ async function dopplerDisconnectCommand() {
|
|
|
4614
4708
|
const credPath = join17(homedir10(), ".md4ai", "credentials.json");
|
|
4615
4709
|
await writeFile6(credPath, JSON.stringify(rest, null, 2), "utf-8");
|
|
4616
4710
|
await chmod2(credPath, 384);
|
|
4617
|
-
|
|
4711
|
+
try {
|
|
4712
|
+
const currentCreds = await loadCredentials();
|
|
4713
|
+
if (currentCreds?.accessToken && currentCreds?.userId) {
|
|
4714
|
+
let supabase = createSupabaseClient(getAnonKey(), currentCreds.accessToken);
|
|
4715
|
+
let userId = currentCreds.userId;
|
|
4716
|
+
if (Date.now() > currentCreds.expiresAt) {
|
|
4717
|
+
const refreshed = await refreshSession();
|
|
4718
|
+
if (refreshed) {
|
|
4719
|
+
supabase = refreshed.supabase;
|
|
4720
|
+
userId = refreshed.userId;
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
await supabase.from("user_secrets").delete().eq("user_id", userId);
|
|
4724
|
+
console.log(chalk26.green("Doppler token removed from local and web dashboard."));
|
|
4725
|
+
} else {
|
|
4726
|
+
console.log(chalk26.green("Doppler token removed locally."));
|
|
4727
|
+
}
|
|
4728
|
+
} catch {
|
|
4729
|
+
console.log(chalk26.green("Doppler token removed locally."));
|
|
4730
|
+
}
|
|
4618
4731
|
}
|
|
4619
4732
|
async function dopplerSetProjectCommand(slug) {
|
|
4620
4733
|
const state = await loadState();
|