pinsay-cli 0.7.0 → 0.7.2
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/cli.js +129 -59
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_build_constants = __esm({
|
|
|
15
15
|
"src/build-constants.ts"() {
|
|
16
16
|
"use strict";
|
|
17
17
|
BUILD_DEFAULT_SERVER = true ? "https://app.pinsay.dev" : "https://app.pinsay.dev";
|
|
18
|
-
BUILD_CLI_VERSION = true ? "0.7.
|
|
18
|
+
BUILD_CLI_VERSION = true ? "0.7.2" : "0.0.0-dev";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -705,7 +705,7 @@ var init_map = __esm({
|
|
|
705
705
|
});
|
|
706
706
|
|
|
707
707
|
// src/auth.ts
|
|
708
|
-
import { promises as
|
|
708
|
+
import { promises as fs18 } from "node:fs";
|
|
709
709
|
import { dirname as dirname8 } from "node:path";
|
|
710
710
|
async function readApiKey(cwd2, server) {
|
|
711
711
|
const { key } = await resolveApiKey(cwd2, server);
|
|
@@ -730,7 +730,7 @@ async function resolveToken(server, cwd2, explicitApiKey) {
|
|
|
730
730
|
return void 0;
|
|
731
731
|
const cacheFile = tokenCacheFile(server, apiKey);
|
|
732
732
|
try {
|
|
733
|
-
const cached = JSON.parse(await
|
|
733
|
+
const cached = JSON.parse(await fs18.readFile(cacheFile, "utf8"));
|
|
734
734
|
const token = typeof cached?.token === "string" ? cached.token.trim() : "";
|
|
735
735
|
if (token && !isJwtExpired(token))
|
|
736
736
|
return token;
|
|
@@ -747,8 +747,8 @@ async function resolveToken(server, cwd2, explicitApiKey) {
|
|
|
747
747
|
);
|
|
748
748
|
if (login?.token) {
|
|
749
749
|
try {
|
|
750
|
-
await
|
|
751
|
-
await
|
|
750
|
+
await fs18.mkdir(dirname8(cacheFile), { recursive: true });
|
|
751
|
+
await fs18.writeFile(cacheFile, JSON.stringify({ token: login.token }), "utf8");
|
|
752
752
|
} catch {
|
|
753
753
|
}
|
|
754
754
|
return login.token;
|
|
@@ -770,7 +770,7 @@ var init_auth = __esm({
|
|
|
770
770
|
|
|
771
771
|
// src/vite/resolve.ts
|
|
772
772
|
import { existsSync as existsSync3, readFileSync } from "node:fs";
|
|
773
|
-
import { join as
|
|
773
|
+
import { join as join18 } from "node:path";
|
|
774
774
|
function entryOf(json, hash) {
|
|
775
775
|
if (!json || typeof json !== "object")
|
|
776
776
|
return void 0;
|
|
@@ -799,11 +799,11 @@ function resolveSource(cwd2, hash) {
|
|
|
799
799
|
const miss = { kind: "unknown", path: null, component: null };
|
|
800
800
|
if (!hash || !/^[0-9a-f]{8}$/.test(hash))
|
|
801
801
|
return miss;
|
|
802
|
-
const manifestPath =
|
|
802
|
+
const manifestPath = join18(cwd2, ".pinsay", "manifest.json");
|
|
803
803
|
const current = normalise(entryOf(readJson2(manifestPath), hash));
|
|
804
804
|
if (current)
|
|
805
805
|
return { kind: "manifest", path: current.path, component: current.component };
|
|
806
|
-
const prevPath =
|
|
806
|
+
const prevPath = join18(cwd2, ".pinsay", "manifest.prev.json");
|
|
807
807
|
const previous = normalise(entryOf(readJson2(prevPath), hash));
|
|
808
808
|
if (previous) {
|
|
809
809
|
return {
|
|
@@ -1103,6 +1103,12 @@ async function statusCommand(cwd2, parsed, positionals = []) {
|
|
|
1103
1103
|
console.error(`Invalid status: ${newStatusStr}. Must be open, ready, applied, or archived.`);
|
|
1104
1104
|
process.exit(2);
|
|
1105
1105
|
}
|
|
1106
|
+
if (statusNum === 3) {
|
|
1107
|
+
console.error(
|
|
1108
|
+
'Marking a comment as \'applied\' is not permitted via `pinsay status`.\nUse `pinsay apply --mark <id> --reply "<explanation>"` (or `pinsay reply <id> "<text>"`) to record a properly structured reply.'
|
|
1109
|
+
);
|
|
1110
|
+
process.exit(2);
|
|
1111
|
+
}
|
|
1106
1112
|
await api(server, `/api/comments/${id}`, {
|
|
1107
1113
|
method: "PATCH",
|
|
1108
1114
|
body: { status: statusNum },
|
|
@@ -4741,14 +4747,66 @@ async function updateCommand(cwd2, options) {
|
|
|
4741
4747
|
// src/commands/apply.ts
|
|
4742
4748
|
init_config();
|
|
4743
4749
|
init_api();
|
|
4750
|
+
|
|
4751
|
+
// src/lib/notify-update.ts
|
|
4752
|
+
import { promises as fs17 } from "node:fs";
|
|
4753
|
+
import { join as join17 } from "node:path";
|
|
4754
|
+
init_build_constants();
|
|
4755
|
+
async function checkAndNotifyUpdates(options) {
|
|
4756
|
+
const result = {
|
|
4757
|
+
cliUpdateAvailable: false,
|
|
4758
|
+
skillsUpdateAvailable: false
|
|
4759
|
+
};
|
|
4760
|
+
if (options.silent || !options.meta)
|
|
4761
|
+
return result;
|
|
4762
|
+
const meta = options.meta;
|
|
4763
|
+
if (meta.latestCliVersion && compareSemver(BUILD_CLI_VERSION, meta.latestCliVersion) < 0) {
|
|
4764
|
+
result.cliUpdateAvailable = true;
|
|
4765
|
+
console.error(
|
|
4766
|
+
`\x1B[33m\u{1F4A1} Update available for pinsay-cli: ${BUILD_CLI_VERSION} \u2192 ${meta.latestCliVersion}\x1B[0m
|
|
4767
|
+
\x1B[33m Run 'npx -y pinsay@latest' to update.\x1B[0m
|
|
4768
|
+
`
|
|
4769
|
+
);
|
|
4770
|
+
}
|
|
4771
|
+
if (meta.skillVersion && options.config && options.cwd) {
|
|
4772
|
+
try {
|
|
4773
|
+
const files = skillFilesFor(options.config);
|
|
4774
|
+
let hasStale = false;
|
|
4775
|
+
for (const rel of files) {
|
|
4776
|
+
const abs = join17(options.cwd, rel);
|
|
4777
|
+
try {
|
|
4778
|
+
await fs17.access(abs);
|
|
4779
|
+
const installed = await readStamp(abs);
|
|
4780
|
+
if (installed && installed !== meta.skillVersion) {
|
|
4781
|
+
hasStale = true;
|
|
4782
|
+
break;
|
|
4783
|
+
}
|
|
4784
|
+
} catch {
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
if (hasStale) {
|
|
4788
|
+
result.skillsUpdateAvailable = true;
|
|
4789
|
+
console.error(
|
|
4790
|
+
`\x1B[33m\u{1F4A1} Local AI skills are out of date with the server.\x1B[0m
|
|
4791
|
+
\x1B[33m Run 'npx pinsay-cli update' to refresh your prompt skills.\x1B[0m
|
|
4792
|
+
`
|
|
4793
|
+
);
|
|
4794
|
+
}
|
|
4795
|
+
} catch {
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
return result;
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
// src/commands/apply.ts
|
|
4744
4802
|
init_auth();
|
|
4745
4803
|
init_build_constants();
|
|
4746
4804
|
|
|
4747
4805
|
// src/apply/run.ts
|
|
4748
4806
|
init_resolve();
|
|
4749
4807
|
init_api();
|
|
4750
|
-
import { promises as
|
|
4751
|
-
import { join as
|
|
4808
|
+
import { promises as fs20 } from "node:fs";
|
|
4809
|
+
import { join as join20, dirname as dirname9 } from "node:path";
|
|
4752
4810
|
import { spawnSync } from "node:child_process";
|
|
4753
4811
|
|
|
4754
4812
|
// src/apply/queue.ts
|
|
@@ -4906,8 +4964,8 @@ async function fetchQueue(ctx, filter) {
|
|
|
4906
4964
|
|
|
4907
4965
|
// src/apply/context.ts
|
|
4908
4966
|
init_api();
|
|
4909
|
-
import { promises as
|
|
4910
|
-
import { join as
|
|
4967
|
+
import { promises as fs19 } from "node:fs";
|
|
4968
|
+
import { join as join19 } from "node:path";
|
|
4911
4969
|
init_config();
|
|
4912
4970
|
async function loadProjectContext(ctx) {
|
|
4913
4971
|
const branding = await getBranding(ctx.server);
|
|
@@ -4918,7 +4976,7 @@ async function loadProjectContext(ctx) {
|
|
|
4918
4976
|
if (config.delegation === "off")
|
|
4919
4977
|
delegation = "off";
|
|
4920
4978
|
const relPath = isMultiProject(config) ? stackFileRelPath(ctx.project) : stackFileRelPath();
|
|
4921
|
-
const stackRaw = await
|
|
4979
|
+
const stackRaw = await fs19.readFile(join19(ctx.cwd, relPath), "utf8");
|
|
4922
4980
|
stack = JSON.parse(stackRaw);
|
|
4923
4981
|
} catch {
|
|
4924
4982
|
}
|
|
@@ -5241,24 +5299,29 @@ function buildApplyPrompt(items, context, opts) {
|
|
|
5241
5299
|
'(Separate style: after each item; Single style: run `npx pinsay-cli apply --mark all --reply "..." --models "..." --tool <your-tool-name>`'
|
|
5242
5300
|
);
|
|
5243
5301
|
lines.push(
|
|
5244
|
-
"once at the end). Never run git push. `--models` MUST list EVERY model that touched the item and its role:"
|
|
5302
|
+
"once at the end). Never run git push. `--models` is MANDATORY and MUST list EVERY model that touched the item and its role:"
|
|
5245
5303
|
);
|
|
5246
5304
|
lines.push(
|
|
5247
|
-
"the planner/reviewer (your own model id) and each worker model you delegated to (`implementer`).
|
|
5305
|
+
"the planner/reviewer (your own model id) and each worker model you delegated to (`implementer`). NEVER guess or hardcode"
|
|
5306
|
+
);
|
|
5307
|
+
lines.push(
|
|
5308
|
+
'outdated model names from memory (like "gemini-2.5-pro"). Always inspect your active runtime model name directly. Use exact'
|
|
5248
5309
|
);
|
|
5249
5310
|
lines.push(
|
|
5250
5311
|
'model ids (e.g. `claude-opus-5-5`, `claude-sonnet-5-5`, `gpt-5.2`), never aliases like "haiku" or "sonnet". With one'
|
|
5251
5312
|
);
|
|
5252
5313
|
lines.push(
|
|
5253
|
-
"model and no delegation, pass just yours as `<your-model-id>=implementer`.
|
|
5314
|
+
"model and no delegation, pass just yours as `<your-model-id>=implementer`. Explicit role `=<role>` is required on each entry."
|
|
5315
|
+
);
|
|
5316
|
+
lines.push(
|
|
5317
|
+
"`--tool` (e.g. `claude-code`, `opencode`, `cursor`, `windsurf`, `antigravity`) records which agent you are running as."
|
|
5254
5318
|
);
|
|
5255
5319
|
lines.push(
|
|
5256
|
-
"
|
|
5320
|
+
"ALWAYS pass both explicitly, even on a project you ran `init` on \u2014 `--tool` silently falls back to whichever tool happened"
|
|
5257
5321
|
);
|
|
5258
5322
|
lines.push(
|
|
5259
|
-
"
|
|
5323
|
+
"to run `init`, which is wrong the moment a different tool applies a comment later."
|
|
5260
5324
|
);
|
|
5261
|
-
lines.push("the moment a different tool applies a comment later.");
|
|
5262
5325
|
return lines.join("\n") + "\n";
|
|
5263
5326
|
}
|
|
5264
5327
|
|
|
@@ -5285,10 +5348,10 @@ function detectAiTool(override) {
|
|
|
5285
5348
|
async function ensureToolRegistered(ctx, tool) {
|
|
5286
5349
|
const config = await readConfig(ctx.cwd).catch(() => ({}));
|
|
5287
5350
|
const relStackPath = isMultiProject(config) ? stackFileRelPath(ctx.project) : stackFileRelPath();
|
|
5288
|
-
const stackPath =
|
|
5351
|
+
const stackPath = join20(ctx.cwd, relStackPath);
|
|
5289
5352
|
let stackData = {};
|
|
5290
5353
|
try {
|
|
5291
|
-
const raw = await
|
|
5354
|
+
const raw = await fs20.readFile(stackPath, "utf8");
|
|
5292
5355
|
stackData = JSON.parse(raw);
|
|
5293
5356
|
} catch {
|
|
5294
5357
|
}
|
|
@@ -5307,8 +5370,8 @@ async function ensureToolRegistered(ctx, tool) {
|
|
|
5307
5370
|
}
|
|
5308
5371
|
);
|
|
5309
5372
|
if (res) {
|
|
5310
|
-
await
|
|
5311
|
-
await
|
|
5373
|
+
await fs20.mkdir(dirname9(stackPath), { recursive: true });
|
|
5374
|
+
await fs20.writeFile(stackPath, JSON.stringify(res, null, 2) + "\n", "utf8");
|
|
5312
5375
|
return;
|
|
5313
5376
|
}
|
|
5314
5377
|
} catch {
|
|
@@ -5317,8 +5380,8 @@ async function ensureToolRegistered(ctx, tool) {
|
|
|
5317
5380
|
aiTools.push(tool);
|
|
5318
5381
|
stackData.aiTools = aiTools;
|
|
5319
5382
|
try {
|
|
5320
|
-
await
|
|
5321
|
-
await
|
|
5383
|
+
await fs20.mkdir(dirname9(stackPath), { recursive: true });
|
|
5384
|
+
await fs20.writeFile(stackPath, JSON.stringify(stackData, null, 2) + "\n", "utf8");
|
|
5322
5385
|
} catch {
|
|
5323
5386
|
}
|
|
5324
5387
|
}
|
|
@@ -5392,9 +5455,9 @@ async function runApply(options, ctx) {
|
|
|
5392
5455
|
console.error(`Failed to spawn opencode: ${res.error.message}`);
|
|
5393
5456
|
}
|
|
5394
5457
|
} else if (tool === "cursor") {
|
|
5395
|
-
const promptFile =
|
|
5396
|
-
await
|
|
5397
|
-
await
|
|
5458
|
+
const promptFile = join20(ctx.cwd, ".pinsay/apply-prompt.md");
|
|
5459
|
+
await fs20.mkdir(join20(ctx.cwd, ".pinsay"), { recursive: true });
|
|
5460
|
+
await fs20.writeFile(promptFile, prompt, "utf8");
|
|
5398
5461
|
console.log(`Saved apply prompt to ${promptFile}`);
|
|
5399
5462
|
} else if (tool === "clipboard") {
|
|
5400
5463
|
const copied = copyToClipboard(prompt);
|
|
@@ -5753,6 +5816,18 @@ async function exitIfWorkspaceFrozen(server, token) {
|
|
|
5753
5816
|
} catch {
|
|
5754
5817
|
}
|
|
5755
5818
|
}
|
|
5819
|
+
async function checkMetaAndNotify(server, config, root, parsed) {
|
|
5820
|
+
try {
|
|
5821
|
+
const meta = await api(server, "/api/meta");
|
|
5822
|
+
const minCli = meta?.minCliVersion || "0.0.0";
|
|
5823
|
+
if (compareSemver(BUILD_CLI_VERSION, minCli) < 0) {
|
|
5824
|
+
console.error(tooOldMessage(BUILD_CLI_VERSION, minCli));
|
|
5825
|
+
process.exit(5);
|
|
5826
|
+
}
|
|
5827
|
+
await checkAndNotifyUpdates({ meta, config, cwd: root, silent: Boolean(parsed["json"]) });
|
|
5828
|
+
} catch {
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5756
5831
|
function parseModelFlags(parsed) {
|
|
5757
5832
|
try {
|
|
5758
5833
|
return resolveModels({
|
|
@@ -5796,17 +5871,7 @@ async function applyCommand(cwd2, parsed, positionals = []) {
|
|
|
5796
5871
|
return;
|
|
5797
5872
|
}
|
|
5798
5873
|
const project = resolved.ok ? resolved.project.key : "";
|
|
5799
|
-
|
|
5800
|
-
const meta = await api(server, "/api/meta");
|
|
5801
|
-
const minCli = meta?.minCliVersion || "0.0.0";
|
|
5802
|
-
if (compareSemver(BUILD_CLI_VERSION, minCli) < 0) {
|
|
5803
|
-
console.error(tooOldMessage(BUILD_CLI_VERSION, minCli));
|
|
5804
|
-
process.exit(5);
|
|
5805
|
-
}
|
|
5806
|
-
} catch (err) {
|
|
5807
|
-
if (!(err instanceof ApiError && err.code === 404)) {
|
|
5808
|
-
}
|
|
5809
|
-
}
|
|
5874
|
+
await checkMetaAndNotify(server, config, root, parsed);
|
|
5810
5875
|
const explicitKey = typeof parsed["key"] === "string" ? parsed["key"] : void 0;
|
|
5811
5876
|
const token = await resolveToken(server, root, explicitKey);
|
|
5812
5877
|
const apiKey = explicitKey || await readApiKey(root, server);
|
|
@@ -5841,8 +5906,10 @@ async function applyCommand(cwd2, parsed, positionals = []) {
|
|
|
5841
5906
|
markId = parsedNum;
|
|
5842
5907
|
}
|
|
5843
5908
|
const reply = typeof parsed["reply"] === "string" ? parsed["reply"] : "";
|
|
5844
|
-
if (!reply) {
|
|
5845
|
-
console.error(
|
|
5909
|
+
if (!reply || reply.trim().length < 15 || /^(done|fixed|applied|ok|yes)$/i.test(reply.trim())) {
|
|
5910
|
+
console.error(
|
|
5911
|
+
'--reply "<text>" is required when using --mark and must provide a substantive explanation of the changes (at least 15 characters, e.g. "Applied \u2713 \u2014 updated logo source in header").'
|
|
5912
|
+
);
|
|
5846
5913
|
process.exit(2);
|
|
5847
5914
|
}
|
|
5848
5915
|
const noCommit = parsed["no-commit"] === true;
|
|
@@ -5855,6 +5922,19 @@ async function applyCommand(cwd2, parsed, positionals = []) {
|
|
|
5855
5922
|
);
|
|
5856
5923
|
}
|
|
5857
5924
|
const models = parseModelFlags(parsed);
|
|
5925
|
+
if (models.length === 0) {
|
|
5926
|
+
console.error(
|
|
5927
|
+
'--models "<model>=<role>" is mandatory when marking a comment as applied.\nSpecify your actual active runtime model and role (e.g. --models "<active-model>=implementer").\nIf multiple models or subagents participated (planner, implementer, reviewer), list all of them separated by commas.\nNever guess or hardcode model names from memory.'
|
|
5928
|
+
);
|
|
5929
|
+
process.exit(2);
|
|
5930
|
+
}
|
|
5931
|
+
const missingRole = models.find((m) => !m.role);
|
|
5932
|
+
if (missingRole) {
|
|
5933
|
+
console.error(
|
|
5934
|
+
`Invalid --models entry "${missingRole.model}": explicit role is required. Expected "<model>=<role>" where role is one of: planner, implementer, reviewer (e.g. "${missingRole.model}=implementer").`
|
|
5935
|
+
);
|
|
5936
|
+
process.exit(2);
|
|
5937
|
+
}
|
|
5858
5938
|
const markStatus = typeof parsed["status"] === "string" ? parsed["status"] : void 0;
|
|
5859
5939
|
const markEnv = typeof parsed["env"] === "string" ? parsed["env"] : void 0;
|
|
5860
5940
|
const marked = await markApplied(
|
|
@@ -5930,17 +6010,7 @@ async function applyAllProjects(root, cwd2, config, server, parsed) {
|
|
|
5930
6010
|
console.error("--tool needs a single project \u2014 pass --project <key> (several are configured).");
|
|
5931
6011
|
process.exit(2);
|
|
5932
6012
|
}
|
|
5933
|
-
|
|
5934
|
-
const meta = await api(server, "/api/meta");
|
|
5935
|
-
const minCli = meta?.minCliVersion || "0.0.0";
|
|
5936
|
-
if (compareSemver(BUILD_CLI_VERSION, minCli) < 0) {
|
|
5937
|
-
console.error(tooOldMessage(BUILD_CLI_VERSION, minCli));
|
|
5938
|
-
process.exit(5);
|
|
5939
|
-
}
|
|
5940
|
-
} catch (err) {
|
|
5941
|
-
if (!(err instanceof ApiError && err.code === 404)) {
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
6013
|
+
await checkMetaAndNotify(server, config, root, parsed);
|
|
5944
6014
|
const explicitKey = typeof parsed["key"] === "string" ? parsed["key"] : void 0;
|
|
5945
6015
|
const token = await resolveToken(server, root, explicitKey);
|
|
5946
6016
|
const apiKey = explicitKey || await readApiKey(root, server);
|
|
@@ -5988,7 +6058,7 @@ init_build_constants();
|
|
|
5988
6058
|
|
|
5989
6059
|
// src/mcp/server.ts
|
|
5990
6060
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
5991
|
-
import { join as
|
|
6061
|
+
import { join as join22 } from "node:path";
|
|
5992
6062
|
|
|
5993
6063
|
// node_modules/zod/v3/external.js
|
|
5994
6064
|
var external_exports = {};
|
|
@@ -11560,7 +11630,7 @@ var ALL_TOOLS = [
|
|
|
11560
11630
|
// src/mcp/tools.ts
|
|
11561
11631
|
init_api();
|
|
11562
11632
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
|
|
11563
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11633
|
+
import { isAbsolute as isAbsolute3, join as join21, relative as relative5, resolve as resolve4 } from "node:path";
|
|
11564
11634
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11565
11635
|
init_build_constants();
|
|
11566
11636
|
init_projection();
|
|
@@ -12100,7 +12170,7 @@ async function handleResolveSource(args, ctx) {
|
|
|
12100
12170
|
if (!hash || typeof hash !== "string") {
|
|
12101
12171
|
throw mcpError("forbidden", "hash is required");
|
|
12102
12172
|
}
|
|
12103
|
-
const manifestPath =
|
|
12173
|
+
const manifestPath = join21(ctx.cwd, ".pinsay/manifest.json");
|
|
12104
12174
|
if (!existsSync4(manifestPath)) {
|
|
12105
12175
|
return { path: null, reason: "no-manifest" };
|
|
12106
12176
|
}
|
|
@@ -12280,12 +12350,12 @@ function createMcpServer(ctx) {
|
|
|
12280
12350
|
let configObj = {};
|
|
12281
12351
|
let stackObj = {};
|
|
12282
12352
|
try {
|
|
12283
|
-
const configPath =
|
|
12353
|
+
const configPath = join22(ctx.cwd, ".pinsay/config.json");
|
|
12284
12354
|
configObj = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
12285
12355
|
} catch {
|
|
12286
12356
|
}
|
|
12287
12357
|
try {
|
|
12288
|
-
const stackPath =
|
|
12358
|
+
const stackPath = join22(ctx.cwd, ".pinsay/stack.json");
|
|
12289
12359
|
stackObj = JSON.parse(readFileSync3(stackPath, "utf8"));
|
|
12290
12360
|
} catch {
|
|
12291
12361
|
}
|
|
@@ -12350,8 +12420,8 @@ function createMcpServer(ctx) {
|
|
|
12350
12420
|
async function runMcpServer(ctx, logFile) {
|
|
12351
12421
|
if (logFile) {
|
|
12352
12422
|
try {
|
|
12353
|
-
const
|
|
12354
|
-
const logStream =
|
|
12423
|
+
const fs21 = await import("node:fs");
|
|
12424
|
+
const logStream = fs21.createWriteStream(logFile, { flags: "a" });
|
|
12355
12425
|
const origWrite = process.stderr.write;
|
|
12356
12426
|
process.stderr.write = function(chunk, encoding, cb) {
|
|
12357
12427
|
logStream.write(chunk);
|
package/package.json
CHANGED