@systemdox/mcp-server 0.1.57 → 0.1.58
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/README.md +37 -9
- package/dist/cli.js +454 -69
- package/dist/http.js +155 -38
- package/dist/index.js +155 -38
- package/dist/lib/memory-sync.d.ts +10 -3
- package/dist/lib/memory-sync.js +30 -4
- package/dist/lib/team-setup-files.d.ts +8 -1
- package/dist/lib/team-setup-files.js +8 -0
- package/dist/lib/team-setup-types.d.ts +2 -0
- package/dist/server.js +154 -37
- package/dist/setup-mcp.js +10 -9
- package/dist/setup-team.d.ts +38 -5
- package/dist/setup-team.js +228 -44
- package/dist/sync-memory.d.ts +61 -9
- package/dist/sync-memory.js +343 -34
- package/dist/tools/team-setup.js +147 -30
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -873,8 +873,8 @@ function registerGetPlanBoard(server, apiClient) {
|
|
|
873
873
|
]
|
|
874
874
|
};
|
|
875
875
|
}
|
|
876
|
-
const
|
|
877
|
-
if (
|
|
876
|
+
const open2 = boards.filter((b) => !b.closed);
|
|
877
|
+
if (open2.length === 0) {
|
|
878
878
|
return {
|
|
879
879
|
content: [
|
|
880
880
|
{
|
|
@@ -884,16 +884,16 @@ function registerGetPlanBoard(server, apiClient) {
|
|
|
884
884
|
]
|
|
885
885
|
};
|
|
886
886
|
}
|
|
887
|
-
const closedNote = boards.length >
|
|
887
|
+
const closedNote = boards.length > open2.length ? `
|
|
888
888
|
|
|
889
|
-
_${boards.length -
|
|
889
|
+
_${boards.length - open2.length} closed board(s) not listed._` : "";
|
|
890
890
|
return {
|
|
891
891
|
content: [
|
|
892
892
|
{
|
|
893
893
|
type: "text",
|
|
894
|
-
text: `${
|
|
894
|
+
text: `${open2.length} open project board(s):
|
|
895
895
|
|
|
896
|
-
${formatBoards(
|
|
896
|
+
${formatBoards(open2)}` + closedNote + `
|
|
897
897
|
|
|
898
898
|
Call get_plan_board with project_number to list a board's issues.`
|
|
899
899
|
}
|
|
@@ -3040,7 +3040,7 @@ var PERSON_ID_RE = new RegExp(`^${PERSON_ID}$`);
|
|
|
3040
3040
|
|
|
3041
3041
|
// src/sync-memory.ts
|
|
3042
3042
|
import { existsSync as existsSync3 } from "fs";
|
|
3043
|
-
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile4, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
3043
|
+
import { appendFile, mkdir as mkdir3, open, readdir as readdir2, readFile as readFile4, rename as rename2, rm as rm3, stat, writeFile as writeFile3 } from "fs/promises";
|
|
3044
3044
|
import { dirname as dirname3, join as join4, resolve as resolve3 } from "path";
|
|
3045
3045
|
|
|
3046
3046
|
// src/lib/memory-sync.ts
|
|
@@ -3064,15 +3064,41 @@ function readFrontmatter(text3) {
|
|
|
3064
3064
|
const m = BLOCK_RE.exec(text3);
|
|
3065
3065
|
if (!m) return void 0;
|
|
3066
3066
|
const front = { shareFalse: false };
|
|
3067
|
-
|
|
3068
|
-
|
|
3067
|
+
const lines = m[1].split(/\r?\n/);
|
|
3068
|
+
if (lines.some((l) => /^[ \t]*\t/.test(l) && l.trim())) return front;
|
|
3069
|
+
let topType;
|
|
3070
|
+
let topShare;
|
|
3071
|
+
let nestedType;
|
|
3072
|
+
let nestedShare;
|
|
3073
|
+
let inMetadata = false;
|
|
3074
|
+
let nestedIndent;
|
|
3075
|
+
for (const line of lines) {
|
|
3076
|
+
if (!line.trim() || /^[ \t]*#/.test(line)) continue;
|
|
3077
|
+
const indent = /^ */.exec(line)[0].length;
|
|
3078
|
+
if (indent === 0) {
|
|
3079
|
+
inMetadata = /^metadata[ \t]*:[ \t]*(#.*)?$/.test(line);
|
|
3080
|
+
nestedIndent = void 0;
|
|
3081
|
+
}
|
|
3082
|
+
const kv = /^ *([A-Za-z_][\w-]*)[ \t]*:[ \t]*(.*?)[ \t]*$/.exec(line);
|
|
3069
3083
|
if (!kv) continue;
|
|
3070
3084
|
const raw = kv[2].replace(/[ \t]+#.*$/, "");
|
|
3071
3085
|
const quoted = /^(["'])(.*)\1$/.exec(raw);
|
|
3072
3086
|
const value = quoted ? quoted[2] : raw;
|
|
3073
|
-
|
|
3074
|
-
if (
|
|
3075
|
-
|
|
3087
|
+
const isFalse = quoted ? value.trim().toLowerCase() === "false" : YAML_FALSE.has(value);
|
|
3088
|
+
if (indent === 0) {
|
|
3089
|
+
if (kv[1] === "type") topType = value.trim().toLowerCase();
|
|
3090
|
+
if (kv[1] === "share") topShare = isFalse;
|
|
3091
|
+
continue;
|
|
3092
|
+
}
|
|
3093
|
+
if (!inMetadata) continue;
|
|
3094
|
+
nestedIndent ??= indent;
|
|
3095
|
+
if (indent !== nestedIndent) continue;
|
|
3096
|
+
if (kv[1] === "type") nestedType = value.trim().toLowerCase();
|
|
3097
|
+
if (kv[1] === "share") nestedShare = isFalse;
|
|
3098
|
+
}
|
|
3099
|
+
const type = topType ?? nestedType;
|
|
3100
|
+
if (type !== void 0) front.type = type;
|
|
3101
|
+
front.shareFalse = (topShare ?? nestedShare) === true;
|
|
3076
3102
|
return front;
|
|
3077
3103
|
}
|
|
3078
3104
|
function isShareable(path, text3) {
|
|
@@ -3313,18 +3339,50 @@ function lineDiff(before, after) {
|
|
|
3313
3339
|
}
|
|
3314
3340
|
|
|
3315
3341
|
// src/sync-memory.ts
|
|
3342
|
+
var HOOK_LOG_MAX_BYTES = 1024 * 1024;
|
|
3316
3343
|
var SYNC_MEMORY_COMMAND = "npx -y @systemdox/mcp-server sync-memory";
|
|
3317
3344
|
var SyncFailed = class extends Error {
|
|
3318
3345
|
};
|
|
3346
|
+
var SyncStopped = class extends Error {
|
|
3347
|
+
constructor(reason, message) {
|
|
3348
|
+
super(message);
|
|
3349
|
+
this.reason = reason;
|
|
3350
|
+
}
|
|
3351
|
+
reason;
|
|
3352
|
+
};
|
|
3353
|
+
function failureReason(e) {
|
|
3354
|
+
if (e instanceof SyncStopped) return e.reason;
|
|
3355
|
+
const { status, code } = refusal(e);
|
|
3356
|
+
if (status !== void 0) return code ? `SystemDox refused it, ${code}` : "SystemDox refused it";
|
|
3357
|
+
const err = e;
|
|
3358
|
+
const net = err?.cause?.code ?? err?.code ?? "";
|
|
3359
|
+
if (e instanceof TypeError || /^(ECONN|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|UND_ERR)/.test(net)) {
|
|
3360
|
+
return "SystemDox could not be reached";
|
|
3361
|
+
}
|
|
3362
|
+
return "it could not finish";
|
|
3363
|
+
}
|
|
3364
|
+
async function writeWhole(path, text3) {
|
|
3365
|
+
await mkdir3(dirname3(path), { recursive: true });
|
|
3366
|
+
const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
3367
|
+
try {
|
|
3368
|
+
await writeFile3(tmp, text3, "utf8");
|
|
3369
|
+
await rename2(tmp, path);
|
|
3370
|
+
} catch (e) {
|
|
3371
|
+
await rm3(tmp, { force: true });
|
|
3372
|
+
throw e;
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3319
3375
|
function refusal(e) {
|
|
3320
3376
|
if (!(e instanceof Error)) return {};
|
|
3321
3377
|
const { status, code } = e;
|
|
3322
3378
|
return { status: typeof status === "number" ? status : void 0, code: typeof code === "string" ? code : void 0 };
|
|
3323
3379
|
}
|
|
3324
3380
|
var toPath = (root, rel) => join4(root, ...rel.split("/"));
|
|
3381
|
+
var LEFT_TEMP_RE = /\.\d+\.[a-z0-9]+\.tmp$/;
|
|
3325
3382
|
async function readFolder(root) {
|
|
3326
3383
|
const files = {};
|
|
3327
3384
|
const names = /* @__PURE__ */ new Set();
|
|
3385
|
+
const temps = [];
|
|
3328
3386
|
async function walk2(dir, prefix) {
|
|
3329
3387
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
3330
3388
|
if (e.name.startsWith(".")) continue;
|
|
@@ -3332,12 +3390,13 @@ async function readFolder(root) {
|
|
|
3332
3390
|
if (e.isDirectory()) await walk2(join4(dir, e.name), rel);
|
|
3333
3391
|
else if (e.isFile()) {
|
|
3334
3392
|
names.add(rel.toLowerCase());
|
|
3393
|
+
if (LEFT_TEMP_RE.test(e.name)) temps.push(rel);
|
|
3335
3394
|
if (e.name.endsWith(".md")) files[rel] = await readFile4(join4(dir, e.name), "utf8");
|
|
3336
3395
|
}
|
|
3337
3396
|
}
|
|
3338
3397
|
}
|
|
3339
3398
|
if (existsSync3(root)) await walk2(root, "");
|
|
3340
|
-
return { files, names };
|
|
3399
|
+
return { files, names, temps };
|
|
3341
3400
|
}
|
|
3342
3401
|
async function pullTeam(client, ws, project) {
|
|
3343
3402
|
try {
|
|
@@ -3386,7 +3445,11 @@ var Report = class {
|
|
|
3386
3445
|
deletedHere = /* @__PURE__ */ new Set();
|
|
3387
3446
|
deletedFromTeam = /* @__PURE__ */ new Set();
|
|
3388
3447
|
conflicts = [];
|
|
3448
|
+
/** The conflict copies written this run, by name. */
|
|
3449
|
+
copies = /* @__PURE__ */ new Set();
|
|
3389
3450
|
skipped = /* @__PURE__ */ new Map();
|
|
3451
|
+
/** Skipped files a sync in the member's terminal can send: held for a value, or for the vault. */
|
|
3452
|
+
waiting = /* @__PURE__ */ new Set();
|
|
3390
3453
|
people = [];
|
|
3391
3454
|
toAnswer = /* @__PURE__ */ new Map();
|
|
3392
3455
|
add(plan) {
|
|
@@ -3394,12 +3457,32 @@ var Report = class {
|
|
|
3394
3457
|
plan.pushed.forEach((p) => this.pushed.add(p));
|
|
3395
3458
|
plan.deletedHere.forEach((p) => this.deletedHere.add(p));
|
|
3396
3459
|
plan.deletedFromTeam.forEach((p) => this.deletedFromTeam.add(p));
|
|
3397
|
-
for (const c of plan.conflicts)
|
|
3460
|
+
for (const c of plan.conflicts) {
|
|
3461
|
+
this.conflicts.push(`${c.path}: the team's text; yours is beside it as ${c.copy}`);
|
|
3462
|
+
this.copies.add(c.copy);
|
|
3463
|
+
}
|
|
3398
3464
|
for (const line of plan.indexTeamLines) this.conflicts.push(`${INDEX_FILE}: your line was kept; the team's was: ${line}`);
|
|
3399
3465
|
}
|
|
3400
3466
|
skip(path, reason) {
|
|
3401
3467
|
if (!this.skipped.has(path)) this.skipped.set(path, reason);
|
|
3402
3468
|
}
|
|
3469
|
+
/** Skipped, and waiting for the member at a terminal. */
|
|
3470
|
+
wait(path, reason) {
|
|
3471
|
+
this.skip(path, reason);
|
|
3472
|
+
this.waiting.add(path);
|
|
3473
|
+
}
|
|
3474
|
+
summary(outcome, version, reason) {
|
|
3475
|
+
return {
|
|
3476
|
+
outcome,
|
|
3477
|
+
...reason ? { reason } : {},
|
|
3478
|
+
version,
|
|
3479
|
+
pulled: this.pulled.size,
|
|
3480
|
+
pushed: this.pushed.size,
|
|
3481
|
+
deleted: this.deletedHere.size + this.deletedFromTeam.size,
|
|
3482
|
+
conflictCopies: [...this.copies].sort(),
|
|
3483
|
+
waiting: [...this.waiting].sort()
|
|
3484
|
+
};
|
|
3485
|
+
}
|
|
3403
3486
|
lines(summary, dryRun) {
|
|
3404
3487
|
const out = [summary];
|
|
3405
3488
|
const section = (title, items) => {
|
|
@@ -3502,7 +3585,7 @@ async function people(opts, ws, files, report, hint) {
|
|
|
3502
3585
|
for (const path of g.files) {
|
|
3503
3586
|
if (leftOut.has(path)) continue;
|
|
3504
3587
|
current[path] = addShareFalse(current[path]);
|
|
3505
|
-
await
|
|
3588
|
+
await writeWhole(toPath(opts.dir, path), current[path]);
|
|
3506
3589
|
leftOut.add(path);
|
|
3507
3590
|
}
|
|
3508
3591
|
report.people.push({ kind: g.kind, answer: "left out (share: false)", files: g.files.length });
|
|
@@ -3605,7 +3688,7 @@ async function people(opts, ws, files, report, hint) {
|
|
|
3605
3688
|
const yes = /^y(es)?$/i.test((await ask(`Rewrite ${paths.length} file${paths.length === 1 ? "" : "s"} as shown? [y/N] `)).trim());
|
|
3606
3689
|
if (yes) {
|
|
3607
3690
|
for (const path of paths) {
|
|
3608
|
-
await
|
|
3691
|
+
await writeWhole(toPath(opts.dir, path), rewritten[path]);
|
|
3609
3692
|
current[path] = rewritten[path];
|
|
3610
3693
|
}
|
|
3611
3694
|
}
|
|
@@ -3620,11 +3703,11 @@ async function people(opts, ws, files, report, hint) {
|
|
|
3620
3703
|
held.add(path);
|
|
3621
3704
|
const keys = pending.filter((f) => f.kind !== HOME_PATH).map((f) => groupKey(f.kind, f.normalised));
|
|
3622
3705
|
if (keys.some((k) => vaultDown.has(k))) {
|
|
3623
|
-
report.
|
|
3706
|
+
report.wait(path, "the vault did not answer (SYD-K019) for a value in it; it syncs once the value is filed");
|
|
3624
3707
|
} else if (keys.some((k) => !answers.has(k))) {
|
|
3625
|
-
report.
|
|
3708
|
+
report.wait(path, `it holds a value nobody has answered for: run \`${hint}\` in a terminal`);
|
|
3626
3709
|
} else {
|
|
3627
|
-
report.
|
|
3710
|
+
report.wait(path, `it holds a value to rewrite as its identifier or ~: run \`${hint}\` in a terminal`);
|
|
3628
3711
|
}
|
|
3629
3712
|
}
|
|
3630
3713
|
for (const g of groups) {
|
|
@@ -3635,12 +3718,11 @@ async function people(opts, ws, files, report, hint) {
|
|
|
3635
3718
|
}
|
|
3636
3719
|
return { files: current, held, leftOut };
|
|
3637
3720
|
}
|
|
3721
|
+
async function removeLeftTemps(dir, temps) {
|
|
3722
|
+
for (const rel of temps) await rm3(toPath(dir, rel), { force: true });
|
|
3723
|
+
}
|
|
3638
3724
|
async function applyPlan(dir, plan) {
|
|
3639
|
-
for (const [path, text3] of Object.entries(plan.writes))
|
|
3640
|
-
const full = toPath(dir, path);
|
|
3641
|
-
await mkdir3(dirname3(full), { recursive: true });
|
|
3642
|
-
await writeFile3(full, text3, "utf8");
|
|
3643
|
-
}
|
|
3725
|
+
for (const [path, text3] of Object.entries(plan.writes)) await writeWhole(toPath(dir, path), text3);
|
|
3644
3726
|
for (const path of plan.deletes) await rm3(toPath(dir, path), { force: true });
|
|
3645
3727
|
}
|
|
3646
3728
|
var sameManifest = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([p, h]) => b[p] === h);
|
|
@@ -3685,8 +3767,19 @@ async function syncMemory(opts) {
|
|
|
3685
3767
|
const { client, out } = opts;
|
|
3686
3768
|
const now = opts.now?.() ?? /* @__PURE__ */ new Date();
|
|
3687
3769
|
try {
|
|
3770
|
+
const checkDeadline = () => {
|
|
3771
|
+
if (opts.deadline !== void 0 && Date.now() > opts.deadline) {
|
|
3772
|
+
throw new SyncStopped("took too long", "Stopped: the sync's time ran out before anything more was written or sent.");
|
|
3773
|
+
}
|
|
3774
|
+
};
|
|
3688
3775
|
const own = await client.getOwnTeamSetup();
|
|
3689
3776
|
const ws = own.workspace;
|
|
3777
|
+
if (opts.workspace && ws !== opts.workspace) {
|
|
3778
|
+
throw new SyncStopped(
|
|
3779
|
+
"the key is for another workspace",
|
|
3780
|
+
`The key is for ${ws}, not ${opts.workspace}: nothing was synced. Set SYSTEMDOX_API_KEY to a key of ${opts.workspace}, or unset it.`
|
|
3781
|
+
);
|
|
3782
|
+
}
|
|
3690
3783
|
const project = opts.project ?? (own.memory.length === 1 ? own.memory[0].project : void 0);
|
|
3691
3784
|
if (!project) {
|
|
3692
3785
|
throw new SyncFailed(
|
|
@@ -3700,6 +3793,12 @@ async function syncMemory(opts) {
|
|
|
3700
3793
|
const date = localDate(now);
|
|
3701
3794
|
const stored = (await readState(ws)).memory?.[project];
|
|
3702
3795
|
let team = await pullTeam(client, ws, project);
|
|
3796
|
+
if (opts.unattended && stored && !team.exists) {
|
|
3797
|
+
throw new SyncStopped(
|
|
3798
|
+
"the team memory could not be read",
|
|
3799
|
+
`${ws}/${project} could not be read from SystemDox: nothing was changed. Run sync-memory in your terminal to see why.`
|
|
3800
|
+
);
|
|
3801
|
+
}
|
|
3703
3802
|
let base = stored ? { version: stored.version, manifest: stored.manifest, exists: true } : { version: 0, manifest: {}, exists: false };
|
|
3704
3803
|
const folder = await readFolder(dir);
|
|
3705
3804
|
const shared = {};
|
|
@@ -3712,14 +3811,16 @@ async function syncMemory(opts) {
|
|
|
3712
3811
|
} else shared[path] = text3;
|
|
3713
3812
|
}
|
|
3714
3813
|
const importWrites = {};
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3814
|
+
const current = { ...folder.files };
|
|
3815
|
+
const taken = new Set(folder.names);
|
|
3816
|
+
for (const importDir of opts.importDirs ?? []) {
|
|
3817
|
+
const other = await readFolder(resolve3(importDir));
|
|
3718
3818
|
for (const [path, text3] of Object.entries(other.files).sort(([a], [b]) => a.localeCompare(b))) {
|
|
3719
3819
|
if (!isShareable(path, text3) || !isFilePath(path)) continue;
|
|
3720
|
-
const here =
|
|
3820
|
+
const here = current[path];
|
|
3721
3821
|
if (here === void 0) {
|
|
3722
3822
|
shared[path] = text3;
|
|
3823
|
+
current[path] = text3;
|
|
3723
3824
|
importWrites[path] = text3;
|
|
3724
3825
|
taken.add(path.toLowerCase());
|
|
3725
3826
|
} else if (here !== text3) {
|
|
@@ -3727,16 +3828,14 @@ async function syncMemory(opts) {
|
|
|
3727
3828
|
taken.add(copy.toLowerCase());
|
|
3728
3829
|
importWrites[copy] = text3;
|
|
3729
3830
|
report.conflicts.push(`${path}: this folder's text; the imported one is beside it as ${copy}`);
|
|
3831
|
+
report.copies.add(copy);
|
|
3730
3832
|
}
|
|
3731
3833
|
}
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
await writeFile3(full, text3, "utf8");
|
|
3738
|
-
}
|
|
3739
|
-
}
|
|
3834
|
+
}
|
|
3835
|
+
folder.names = taken;
|
|
3836
|
+
if (!opts.dryRun) {
|
|
3837
|
+
checkDeadline();
|
|
3838
|
+
for (const [path, text3] of Object.entries(importWrites)) await writeWhole(toPath(dir, path), text3);
|
|
3740
3839
|
}
|
|
3741
3840
|
const found = await people(run2, ws, shared, report, hint);
|
|
3742
3841
|
for (const path of found.leftOut) {
|
|
@@ -3761,12 +3860,16 @@ async function syncMemory(opts) {
|
|
|
3761
3860
|
);
|
|
3762
3861
|
return 0;
|
|
3763
3862
|
}
|
|
3863
|
+
checkDeadline();
|
|
3864
|
+
if (attempt === 1) await removeLeftTemps(dir, folder.temps);
|
|
3764
3865
|
await applyPlan(dir, plan);
|
|
3765
3866
|
let version = team.version;
|
|
3766
3867
|
if (!sameManifest(plan.manifest, team.manifest)) {
|
|
3868
|
+
checkDeadline();
|
|
3767
3869
|
await upload(client, ws, project, plan, team.manifest, report);
|
|
3768
3870
|
}
|
|
3769
3871
|
if (!sameManifest(plan.manifest, team.manifest)) {
|
|
3872
|
+
checkDeadline();
|
|
3770
3873
|
try {
|
|
3771
3874
|
version = (await client.pushMemoryVersion(ws, project, { baseVersion: team.version, manifest: plan.manifest })).version;
|
|
3772
3875
|
} catch (e) {
|
|
@@ -3778,6 +3881,7 @@ async function syncMemory(opts) {
|
|
|
3778
3881
|
false
|
|
3779
3882
|
)
|
|
3780
3883
|
);
|
|
3884
|
+
opts.summary?.(report.summary("moved-on", team.version, "moved on twice"));
|
|
3781
3885
|
return 2;
|
|
3782
3886
|
}
|
|
3783
3887
|
base = team;
|
|
@@ -3802,10 +3906,21 @@ async function syncMemory(opts) {
|
|
|
3802
3906
|
false
|
|
3803
3907
|
)
|
|
3804
3908
|
);
|
|
3909
|
+
opts.summary?.(report.summary("synced", version));
|
|
3805
3910
|
return 0;
|
|
3806
3911
|
}
|
|
3807
3912
|
} catch (e) {
|
|
3808
3913
|
out(e.message);
|
|
3914
|
+
opts.summary?.({
|
|
3915
|
+
outcome: "failed",
|
|
3916
|
+
reason: failureReason(e),
|
|
3917
|
+
version: 0,
|
|
3918
|
+
pulled: 0,
|
|
3919
|
+
pushed: 0,
|
|
3920
|
+
deleted: 0,
|
|
3921
|
+
conflictCopies: [],
|
|
3922
|
+
waiting: []
|
|
3923
|
+
});
|
|
3809
3924
|
return 1;
|
|
3810
3925
|
}
|
|
3811
3926
|
}
|
|
@@ -3977,7 +4092,9 @@ function registerTeamSetupTools(server, apiClient, { localFiles }) {
|
|
|
3977
4092
|
project: args.project,
|
|
3978
4093
|
dryRun: !!args.dryRun,
|
|
3979
4094
|
client: apiClient,
|
|
3980
|
-
out: (...l) => lines.push(...l)
|
|
4095
|
+
out: (...l) => lines.push(...l),
|
|
4096
|
+
// Nobody is at a terminal: a project the team no longer serves is left as it is.
|
|
4097
|
+
unattended: true
|
|
3981
4098
|
});
|
|
3982
4099
|
return { ...text2(lines.join("\n")), ...code ? { isError: true } : {} };
|
|
3983
4100
|
}
|
|
@@ -3985,7 +4102,7 @@ function registerTeamSetupTools(server, apiClient, { localFiles }) {
|
|
|
3985
4102
|
}
|
|
3986
4103
|
|
|
3987
4104
|
// src/server.ts
|
|
3988
|
-
var SERVER_VERSION = true ? "0.1.
|
|
4105
|
+
var SERVER_VERSION = true ? "0.1.58" : "0.0.0-dev";
|
|
3989
4106
|
var READ_TOOLS = [
|
|
3990
4107
|
"get_context",
|
|
3991
4108
|
"get_checks",
|