@memmo/cli 0.7.1 → 0.7.3
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 +48 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -109,7 +109,15 @@ function forgetRepo(remote) {
|
|
|
109
109
|
} catch {
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
function envApiUrl() {
|
|
113
|
+
const v = process.env.MEMMO_API_URL?.trim();
|
|
114
|
+
return v ? v.replace(/\/$/, "") : void 0;
|
|
115
|
+
}
|
|
116
|
+
function envToken() {
|
|
117
|
+
const v = process.env.MEMMO_TOKEN?.trim();
|
|
118
|
+
return v || void 0;
|
|
119
|
+
}
|
|
120
|
+
var DEFAULT_API_BASE_URL = envApiUrl() ?? "https://api.memmo.dev";
|
|
113
121
|
function detectGitRemote(cwd = process.cwd()) {
|
|
114
122
|
try {
|
|
115
123
|
return execSync("git remote get-url origin", {
|
|
@@ -122,11 +130,12 @@ function detectGitRemote(cwd = process.cwd()) {
|
|
|
122
130
|
}
|
|
123
131
|
async function resolveProjectConfig(cwd = process.cwd(), opts = {}) {
|
|
124
132
|
const creds = loadCredentials();
|
|
125
|
-
const apiBaseUrl = opts.apiBaseUrl ??
|
|
133
|
+
const apiBaseUrl = opts.apiBaseUrl ?? envApiUrl() ?? creds?.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
134
|
+
const token = envToken() ?? creds?.token;
|
|
126
135
|
const explicit = opts.repoId ?? process.env.MEMMO_REPO_ID;
|
|
127
136
|
if (explicit) return { apiBaseUrl, repoId: explicit };
|
|
128
137
|
const remote = detectGitRemote(cwd);
|
|
129
|
-
if (remote &&
|
|
138
|
+
if (remote && token) {
|
|
130
139
|
const hit = readRepoCache()[remote];
|
|
131
140
|
if (hit && hit.apiBaseUrl === apiBaseUrl && Date.now() - hit.at < REPO_CACHE_TTL_MS) {
|
|
132
141
|
return { apiBaseUrl, repoId: hit.repoId, repoFullName: hit.fullName };
|
|
@@ -134,7 +143,7 @@ async function resolveProjectConfig(cwd = process.cwd(), opts = {}) {
|
|
|
134
143
|
try {
|
|
135
144
|
const { apiFetch: apiFetch2 } = await Promise.resolve().then(() => (init_api(), api_exports));
|
|
136
145
|
const r = await apiFetch2(
|
|
137
|
-
{ baseUrl: apiBaseUrl, token
|
|
146
|
+
{ baseUrl: apiBaseUrl, token },
|
|
138
147
|
"/repos/resolve",
|
|
139
148
|
{ method: "POST", body: JSON.stringify({ repoRemote: remote }) }
|
|
140
149
|
);
|
|
@@ -612,7 +621,7 @@ async function desktopCommand(opts = {}) {
|
|
|
612
621
|
}
|
|
613
622
|
const creds = loadCredentials();
|
|
614
623
|
if (!creds) throw new Error("Not logged in. Run `memmo login` first.");
|
|
615
|
-
const client = { baseUrl:
|
|
624
|
+
const client = { baseUrl: envApiUrl() ?? creds.apiBaseUrl, token: creds.token };
|
|
616
625
|
let repoId = opts.repo;
|
|
617
626
|
let label = repoId;
|
|
618
627
|
if (!repoId) {
|
|
@@ -675,7 +684,7 @@ async function chooseProject(client, wanted, yes = false) {
|
|
|
675
684
|
async function initCommand(opts) {
|
|
676
685
|
const creds = loadCredentials();
|
|
677
686
|
if (!creds) throw new Error("Not logged in. Run `memmo login` first.");
|
|
678
|
-
const client = { baseUrl:
|
|
687
|
+
const client = { baseUrl: envApiUrl() ?? creds.apiBaseUrl, token: creds.token };
|
|
679
688
|
const cwd = process.cwd();
|
|
680
689
|
if (!existsSync5(join5(cwd, ".git"))) {
|
|
681
690
|
console.log("note: no .git here \u2014 run `memmo init` at your repo root.");
|
|
@@ -894,14 +903,12 @@ async function mcpCommand(opts = {}) {
|
|
|
894
903
|
`/repos/${config.repoId}/proposals`,
|
|
895
904
|
{ method: "POST", body: JSON.stringify({ memories }) }
|
|
896
905
|
);
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
]
|
|
904
|
-
};
|
|
906
|
+
const parts = [];
|
|
907
|
+
if (result.proposedCount) parts.push(`${result.proposedCount} proposed for review`);
|
|
908
|
+
if (result.autoApproved) parts.push(`${result.autoApproved} auto-approved`);
|
|
909
|
+
if (result.autoRejected) parts.push(`${result.autoRejected} auto-rejected (low confidence)`);
|
|
910
|
+
if (result.skipped) parts.push(`${result.skipped} skipped as already known`);
|
|
911
|
+
return { content: [{ type: "text", text: parts.length ? `Memmo: ${parts.join(", ")}.` : "Memmo: nothing new to record." }] };
|
|
905
912
|
}
|
|
906
913
|
);
|
|
907
914
|
const transport = new StdioServerTransport();
|
|
@@ -1858,15 +1865,21 @@ async function postInlineReview(ctx, diff, review) {
|
|
|
1858
1865
|
`Memmo: posted review (${payload.comments.length} inline, ${payload.newCount} new findings).`
|
|
1859
1866
|
);
|
|
1860
1867
|
}
|
|
1868
|
+
function skipReview(message) {
|
|
1869
|
+
console.error(message);
|
|
1870
|
+
if (!process.env.GITHUB_ACTIONS) process.exitCode = 1;
|
|
1871
|
+
}
|
|
1861
1872
|
async function reviewCommand(opts = {}) {
|
|
1862
1873
|
const config = await resolveProjectConfig();
|
|
1863
1874
|
if (!config) {
|
|
1864
|
-
|
|
1875
|
+
return skipReview(
|
|
1876
|
+
process.env.GITHUB_ACTIONS ? "Memmo: this repo isn't connected to a project, or MEMMO_TOKEN isn't a token for it. Open Memmo \u2192 Reviews to fix; skipping the review." : NOT_CONNECTED
|
|
1877
|
+
);
|
|
1865
1878
|
}
|
|
1866
1879
|
const creds = loadCredentials();
|
|
1867
|
-
const token =
|
|
1880
|
+
const token = envToken() ?? creds?.token;
|
|
1868
1881
|
if (!token) throw new Error("No API token. Set MEMMO_TOKEN (CI) or run `memmo login`.");
|
|
1869
|
-
const baseUrl = opts.api ??
|
|
1882
|
+
const baseUrl = opts.api ?? envApiUrl() ?? config.apiBaseUrl ?? creds?.apiBaseUrl;
|
|
1870
1883
|
if (!baseUrl) throw new Error("No API base URL. Set MEMMO_API_URL or pass --api.");
|
|
1871
1884
|
const client = { baseUrl, token };
|
|
1872
1885
|
const base = opts.base ?? process.env.GITHUB_BASE_REF ?? "main";
|
|
@@ -1878,10 +1891,22 @@ async function reviewCommand(opts = {}) {
|
|
|
1878
1891
|
const ev = readEvent();
|
|
1879
1892
|
const prTitle = (opts.title ?? ev.title ?? git(["log", "-1", "--pretty=%s"]).trim()).slice(0, 500);
|
|
1880
1893
|
const prBody = opts.body ?? ev.body;
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1894
|
+
let res;
|
|
1895
|
+
try {
|
|
1896
|
+
res = await apiFetch(client, `/repos/${config.repoId}/review-diff`, {
|
|
1897
|
+
method: "POST",
|
|
1898
|
+
body: JSON.stringify({ prTitle, prBody, diff })
|
|
1899
|
+
});
|
|
1900
|
+
} catch (e) {
|
|
1901
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1902
|
+
if (msg.includes("llm_not_configured")) {
|
|
1903
|
+
return skipReview("Memmo: the project has no AI key yet. Add one in Memmo \u2192 Reviews (step 1); skipping the review.");
|
|
1904
|
+
}
|
|
1905
|
+
if (msg.includes("plan_requires_reviewer")) {
|
|
1906
|
+
return skipReview("Memmo: the PR reviewer needs the Scale plan. Upgrade in Memmo \u2192 Settings \u2192 Subscription; skipping the review.");
|
|
1907
|
+
}
|
|
1908
|
+
throw e;
|
|
1909
|
+
}
|
|
1885
1910
|
if (res.skipped) {
|
|
1886
1911
|
console.error("Memmo reviewer is disabled for this repo \u2014 skipping (enable it in the dashboard).");
|
|
1887
1912
|
return;
|
|
@@ -1935,9 +1960,9 @@ async function reviewSyncCommand(opts = {}) {
|
|
|
1935
1960
|
throw new Error(NOT_CONNECTED);
|
|
1936
1961
|
}
|
|
1937
1962
|
const creds = loadCredentials();
|
|
1938
|
-
const token =
|
|
1963
|
+
const token = envToken() ?? creds?.token;
|
|
1939
1964
|
if (!token) throw new Error("No API token. Set MEMMO_TOKEN (CI) or run `memmo login`.");
|
|
1940
|
-
const baseUrl = opts.api ??
|
|
1965
|
+
const baseUrl = opts.api ?? envApiUrl() ?? config.apiBaseUrl ?? creds?.apiBaseUrl;
|
|
1941
1966
|
if (!baseUrl) throw new Error("No API base URL. Set MEMMO_API_URL or pass --api.");
|
|
1942
1967
|
const client = { baseUrl, token };
|
|
1943
1968
|
const ev = readEvent();
|