gsd-pi 2.38.0-dev.63ad7e5 → 2.38.0-dev.7209774
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/resource-loader.js +34 -1
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto-loop.js +593 -516
- package/dist/resources/extensions/gsd/auto-post-unit.js +28 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -15
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/commands.js +2 -1
- package/dist/resources/extensions/gsd/doctor.js +20 -1
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/files.js +4 -0
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/guided-flow.js +82 -32
- package/dist/resources/extensions/gsd/index.js +22 -19
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +58 -0
- package/dist/resources/extensions/gsd/preferences.js +3 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -0
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto-loop.ts +472 -434
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +29 -15
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/commands.ts +2 -2
- package/src/resources/extensions/gsd/doctor.ts +22 -1
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/files.ts +3 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/guided-flow.ts +110 -38
- package/src/resources/extensions/gsd/index.ts +21 -16
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-types.ts +4 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +50 -0
- package/src/resources/extensions/gsd/preferences.ts +3 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/run-uat.md +2 -0
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +111 -37
- package/src/resources/extensions/gsd/types.ts +8 -0
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/mcp-client/index.ts +17 -1
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
resolveAgentEnd,
|
|
8
8
|
runUnit,
|
|
9
9
|
autoLoop,
|
|
10
|
+
detectStuck,
|
|
10
11
|
_resetPendingResolve,
|
|
11
12
|
_setActiveSession,
|
|
12
13
|
isSessionSwitchInFlight,
|
|
@@ -104,7 +105,6 @@ test("resolveAgentEnd resolves a pending runUnit promise", async () => {
|
|
|
104
105
|
"task",
|
|
105
106
|
"T01",
|
|
106
107
|
"do stuff",
|
|
107
|
-
undefined,
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
// Give the microtask queue a tick so runUnit reaches the await
|
|
@@ -136,7 +136,7 @@ test("double resolveAgentEnd only resolves once (second is dropped)", async () =
|
|
|
136
136
|
const event1 = makeEvent([{ id: 1 }]);
|
|
137
137
|
const event2 = makeEvent([{ id: 2 }]);
|
|
138
138
|
|
|
139
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt"
|
|
139
|
+
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
140
140
|
|
|
141
141
|
await new Promise((r) => setTimeout(r, 10));
|
|
142
142
|
|
|
@@ -161,7 +161,7 @@ test("runUnit returns cancelled when session creation fails", async () => {
|
|
|
161
161
|
const pi = makeMockPi();
|
|
162
162
|
const s = makeMockSession({ newSessionThrows: "connection refused" });
|
|
163
163
|
|
|
164
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt"
|
|
164
|
+
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
165
165
|
|
|
166
166
|
assert.equal(result.status, "cancelled");
|
|
167
167
|
assert.equal(result.event, undefined);
|
|
@@ -177,7 +177,7 @@ test("runUnit returns cancelled when session creation times out", async () => {
|
|
|
177
177
|
// Session returns cancelled: true (simulates the timeout race outcome)
|
|
178
178
|
const s = makeMockSession({ newSessionResult: { cancelled: true } });
|
|
179
179
|
|
|
180
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt"
|
|
180
|
+
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
181
181
|
|
|
182
182
|
assert.equal(result.status, "cancelled");
|
|
183
183
|
assert.equal(result.event, undefined);
|
|
@@ -192,7 +192,7 @@ test("runUnit returns cancelled when s.active is false before sendMessage", asyn
|
|
|
192
192
|
const s = makeMockSession();
|
|
193
193
|
s.active = false;
|
|
194
194
|
|
|
195
|
-
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt"
|
|
195
|
+
const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
196
196
|
|
|
197
197
|
assert.equal(result.status, "cancelled");
|
|
198
198
|
assert.equal(pi.calls.length, 0);
|
|
@@ -212,7 +212,7 @@ test("runUnit only arms resolve after newSession completes", async () => {
|
|
|
212
212
|
},
|
|
213
213
|
});
|
|
214
214
|
|
|
215
|
-
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt"
|
|
215
|
+
const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
|
|
216
216
|
|
|
217
217
|
await new Promise((r) => setTimeout(r, 30));
|
|
218
218
|
|
|
@@ -1043,7 +1043,7 @@ test("handleAgentEnd in auto.ts is a thin wrapper calling resolveAgentEnd", () =
|
|
|
1043
1043
|
|
|
1044
1044
|
// ── Stuck counter tests ──────────────────────────────────────────────────────
|
|
1045
1045
|
|
|
1046
|
-
test("stuck
|
|
1046
|
+
test("stuck detection: stops when sliding window detects same unit 3 consecutive times", async () => {
|
|
1047
1047
|
_resetPendingResolve();
|
|
1048
1048
|
|
|
1049
1049
|
const ctx = makeMockCtx();
|
|
@@ -1078,20 +1078,15 @@ test("stuck counter: stops when deriveState returns same unit 5 consecutive time
|
|
|
1078
1078
|
|
|
1079
1079
|
const loopPromise = autoLoop(ctx, pi, s, deps);
|
|
1080
1080
|
|
|
1081
|
-
//
|
|
1082
|
-
//
|
|
1083
|
-
//
|
|
1084
|
-
//
|
|
1085
|
-
//
|
|
1086
|
-
//
|
|
1081
|
+
// Sliding window: iteration 1 pushes [A], iteration 2 pushes [A,A],
|
|
1082
|
+
// iteration 3 pushes [A,A,A] → Rule 2 fires (3 consecutive) → Level 1 recovery.
|
|
1083
|
+
// Level 1 invalidates caches and continues. Iteration 4 pushes [A,A,A,A] →
|
|
1084
|
+
// Rule 2 fires again → Level 2 hard stop.
|
|
1085
|
+
// Iterations 1-3 each run a unit (3 resolves needed). Iteration 3 triggers
|
|
1086
|
+
// Level 1 (cache invalidation + continue). Iteration 4 triggers Level 2 (stop
|
|
1087
|
+
// before runUnit), so no 4th resolve needed.
|
|
1087
1088
|
|
|
1088
|
-
|
|
1089
|
-
// Iteration 2: derivedKey === lastDerivedUnit → sameUnitCount=1.
|
|
1090
|
-
// Iteration 3: sameUnitCount=2. Iteration 4: sameUnitCount=3.
|
|
1091
|
-
// Iteration 5: sameUnitCount=4. Iteration 6: sameUnitCount=5 → stop.
|
|
1092
|
-
// So we need to resolve 5 agent_end events (iterations 1-5 each run a unit).
|
|
1093
|
-
|
|
1094
|
-
for (let i = 0; i < 5; i++) {
|
|
1089
|
+
for (let i = 0; i < 3; i++) {
|
|
1095
1090
|
await new Promise((r) => setTimeout(r, 30));
|
|
1096
1091
|
resolveAgentEnd(makeEvent());
|
|
1097
1092
|
}
|
|
@@ -1106,17 +1101,13 @@ test("stuck counter: stops when deriveState returns same unit 5 consecutive time
|
|
|
1106
1101
|
stopReason.includes("Stuck"),
|
|
1107
1102
|
`stop reason should mention 'Stuck', got: ${stopReason}`,
|
|
1108
1103
|
);
|
|
1109
|
-
assert.ok(
|
|
1110
|
-
stopReason.includes("execute-task"),
|
|
1111
|
-
"stop reason should include unitType",
|
|
1112
|
-
);
|
|
1113
1104
|
assert.ok(
|
|
1114
1105
|
stopReason.includes("M001/S01/T01"),
|
|
1115
1106
|
"stop reason should include unitId",
|
|
1116
1107
|
);
|
|
1117
1108
|
});
|
|
1118
1109
|
|
|
1119
|
-
test("stuck
|
|
1110
|
+
test("stuck detection: window resets recovery when deriveState returns a different unit", async () => {
|
|
1120
1111
|
_resetPendingResolve();
|
|
1121
1112
|
|
|
1122
1113
|
const ctx = makeMockCtx();
|
|
@@ -1177,10 +1168,11 @@ test("stuck counter: resets when deriveState returns a different unit", async ()
|
|
|
1177
1168
|
|
|
1178
1169
|
await loopPromise;
|
|
1179
1170
|
|
|
1180
|
-
//
|
|
1171
|
+
// Level 1 recovery fires on iteration 3 (cache invalidation + continue),
|
|
1172
|
+
// then iteration 4 derives T02 — no Level 2 hard stop.
|
|
1181
1173
|
assert.ok(
|
|
1182
1174
|
!stopCalled,
|
|
1183
|
-
"stopAuto should NOT have been called —
|
|
1175
|
+
"stopAuto should NOT have been called — different unit broke stuck pattern",
|
|
1184
1176
|
);
|
|
1185
1177
|
assert.ok(
|
|
1186
1178
|
deriveCallCount >= 4,
|
|
@@ -1188,7 +1180,7 @@ test("stuck counter: resets when deriveState returns a different unit", async ()
|
|
|
1188
1180
|
);
|
|
1189
1181
|
});
|
|
1190
1182
|
|
|
1191
|
-
test("stuck
|
|
1183
|
+
test("stuck detection: does not push to window during verification retry", async () => {
|
|
1192
1184
|
_resetPendingResolve();
|
|
1193
1185
|
|
|
1194
1186
|
const ctx = makeMockCtx();
|
|
@@ -1250,10 +1242,10 @@ test("stuck counter: does not increment during verification retry", async () =>
|
|
|
1250
1242
|
await loopPromise;
|
|
1251
1243
|
|
|
1252
1244
|
// Even though same unit was derived 4 times, verification retries should
|
|
1253
|
-
// not
|
|
1245
|
+
// not push to the sliding window, so stuck detection should not have fired
|
|
1254
1246
|
assert.ok(
|
|
1255
1247
|
!stopReason.includes("Stuck"),
|
|
1256
|
-
`stuck
|
|
1248
|
+
`stuck detection should not fire during verification retries, got: ${stopReason}`,
|
|
1257
1249
|
);
|
|
1258
1250
|
assert.equal(
|
|
1259
1251
|
verifyCallCount,
|
|
@@ -1262,24 +1254,106 @@ test("stuck counter: does not increment during verification retry", async () =>
|
|
|
1262
1254
|
);
|
|
1263
1255
|
});
|
|
1264
1256
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1257
|
+
// ── detectStuck unit tests ────────────────────────────────────────────────────
|
|
1258
|
+
|
|
1259
|
+
test("detectStuck: returns null for fewer than 2 entries", () => {
|
|
1260
|
+
assert.equal(detectStuck([]), null);
|
|
1261
|
+
assert.equal(detectStuck([{ key: "A" }]), null);
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
test("detectStuck: Rule 1 — same error twice in a row", () => {
|
|
1265
|
+
const result = detectStuck([
|
|
1266
|
+
{ key: "A", error: "ENOENT: file not found" },
|
|
1267
|
+
{ key: "A", error: "ENOENT: file not found" },
|
|
1268
|
+
]);
|
|
1269
|
+
assert.ok(result?.stuck, "should detect same error repeated");
|
|
1270
|
+
assert.ok(result?.reason.includes("Same error repeated"));
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
test("detectStuck: Rule 1 — different errors do not trigger", () => {
|
|
1274
|
+
const result = detectStuck([
|
|
1275
|
+
{ key: "A", error: "ENOENT: file not found" },
|
|
1276
|
+
{ key: "A", error: "EACCES: permission denied" },
|
|
1277
|
+
]);
|
|
1278
|
+
assert.equal(result, null);
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
test("detectStuck: Rule 2 — same unit 3 consecutive times", () => {
|
|
1282
|
+
const result = detectStuck([
|
|
1283
|
+
{ key: "execute-task/M001/S01/T01" },
|
|
1284
|
+
{ key: "execute-task/M001/S01/T01" },
|
|
1285
|
+
{ key: "execute-task/M001/S01/T01" },
|
|
1286
|
+
]);
|
|
1287
|
+
assert.ok(result?.stuck);
|
|
1288
|
+
assert.ok(result?.reason.includes("3 consecutive times"));
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
test("detectStuck: Rule 2 — 2 consecutive does not trigger", () => {
|
|
1292
|
+
assert.equal(detectStuck([
|
|
1293
|
+
{ key: "A" },
|
|
1294
|
+
{ key: "A" },
|
|
1295
|
+
]), null);
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
test("detectStuck: Rule 3 — oscillation A→B→A→B", () => {
|
|
1299
|
+
const result = detectStuck([
|
|
1300
|
+
{ key: "A" },
|
|
1301
|
+
{ key: "B" },
|
|
1302
|
+
{ key: "A" },
|
|
1303
|
+
{ key: "B" },
|
|
1304
|
+
]);
|
|
1305
|
+
assert.ok(result?.stuck);
|
|
1306
|
+
assert.ok(result?.reason.includes("Oscillation"));
|
|
1307
|
+
});
|
|
1308
|
+
|
|
1309
|
+
test("detectStuck: Rule 3 — non-oscillation pattern A→B→C→B", () => {
|
|
1310
|
+
assert.equal(detectStuck([
|
|
1311
|
+
{ key: "A" },
|
|
1312
|
+
{ key: "B" },
|
|
1313
|
+
{ key: "C" },
|
|
1314
|
+
{ key: "B" },
|
|
1315
|
+
]), null);
|
|
1316
|
+
});
|
|
1317
|
+
|
|
1318
|
+
test("detectStuck: Rule 1 takes priority over Rule 2 when both match", () => {
|
|
1319
|
+
const result = detectStuck([
|
|
1320
|
+
{ key: "A", error: "test error" },
|
|
1321
|
+
{ key: "A", error: "test error" },
|
|
1322
|
+
{ key: "A", error: "test error" },
|
|
1323
|
+
]);
|
|
1324
|
+
assert.ok(result?.stuck);
|
|
1325
|
+
// Rule 1 fires first
|
|
1326
|
+
assert.ok(result?.reason.includes("Same error repeated"));
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
test("detectStuck: truncates long error strings", () => {
|
|
1330
|
+
const longError = "x".repeat(500);
|
|
1331
|
+
const result = detectStuck([
|
|
1332
|
+
{ key: "A", error: longError },
|
|
1333
|
+
{ key: "A", error: longError },
|
|
1334
|
+
]);
|
|
1335
|
+
assert.ok(result?.stuck);
|
|
1336
|
+
assert.ok(result!.reason.length < 300, "reason should be truncated");
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
test("stuck detection: logs debug output with stuck-detected phase", () => {
|
|
1340
|
+
// Structural test: verify the auto-loop.ts source contains
|
|
1341
|
+
// stuck-detected and stuck-counter-reset debug log phases, plus detectStuck
|
|
1268
1342
|
const src = readFileSync(
|
|
1269
1343
|
resolve(import.meta.dirname, "..", "auto-loop.ts"),
|
|
1270
1344
|
"utf-8",
|
|
1271
1345
|
);
|
|
1272
1346
|
assert.ok(
|
|
1273
1347
|
src.includes('"stuck-detected"'),
|
|
1274
|
-
"auto-loop.ts must log phase: 'stuck-detected' when stuck
|
|
1348
|
+
"auto-loop.ts must log phase: 'stuck-detected' when stuck detection fires",
|
|
1275
1349
|
);
|
|
1276
1350
|
assert.ok(
|
|
1277
1351
|
src.includes('"stuck-counter-reset"'),
|
|
1278
|
-
"auto-loop.ts must log phase: 'stuck-counter-reset' when
|
|
1352
|
+
"auto-loop.ts must log phase: 'stuck-counter-reset' when recovery resets on new unit",
|
|
1279
1353
|
);
|
|
1280
1354
|
assert.ok(
|
|
1281
|
-
src.includes("
|
|
1282
|
-
"auto-loop.ts must
|
|
1355
|
+
src.includes("detectStuck"),
|
|
1356
|
+
"auto-loop.ts must use detectStuck for sliding window analysis",
|
|
1283
1357
|
);
|
|
1284
1358
|
});
|
|
1285
1359
|
|
|
@@ -37,6 +37,21 @@ export interface AuditWarningJSON {
|
|
|
37
37
|
fixAvailable: boolean;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
export interface BrowserEvidenceCheckJSON {
|
|
41
|
+
description: string;
|
|
42
|
+
passed: boolean;
|
|
43
|
+
actual?: string;
|
|
44
|
+
evidence?: string;
|
|
45
|
+
error?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface BrowserEvidenceJSON {
|
|
49
|
+
url: string;
|
|
50
|
+
passed: boolean;
|
|
51
|
+
checks: BrowserEvidenceCheckJSON[];
|
|
52
|
+
duration: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
export interface EvidenceJSON {
|
|
41
56
|
schemaVersion: 1;
|
|
42
57
|
taskId: string;
|
|
@@ -49,6 +64,7 @@ export interface EvidenceJSON {
|
|
|
49
64
|
maxRetries?: number;
|
|
50
65
|
runtimeErrors?: RuntimeErrorJSON[];
|
|
51
66
|
auditWarnings?: AuditWarningJSON[];
|
|
67
|
+
browser?: BrowserEvidenceJSON;
|
|
52
68
|
}
|
|
53
69
|
|
|
54
70
|
/**
|
|
@@ -114,6 +114,22 @@ function getServerConfig(name: string): McpServerConfig | undefined {
|
|
|
114
114
|
return readConfigs().find((s) => s.name === name);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/** Resolve ${VAR} references in env values against process.env. */
|
|
118
|
+
function resolveEnv(env: Record<string, string>): Record<string, string> {
|
|
119
|
+
const resolved: Record<string, string> = {};
|
|
120
|
+
for (const [key, value] of Object.entries(env)) {
|
|
121
|
+
if (typeof value === "string") {
|
|
122
|
+
resolved[key] = value.replace(
|
|
123
|
+
/\$\{([^}]+)\}/g,
|
|
124
|
+
(_match, varName) => process.env[varName] ?? "",
|
|
125
|
+
);
|
|
126
|
+
} else {
|
|
127
|
+
resolved[key] = value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return resolved;
|
|
131
|
+
}
|
|
132
|
+
|
|
117
133
|
async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client> {
|
|
118
134
|
const existing = connections.get(name);
|
|
119
135
|
if (existing) return existing.client;
|
|
@@ -128,7 +144,7 @@ async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client>
|
|
|
128
144
|
transport = new StdioClientTransport({
|
|
129
145
|
command: config.command,
|
|
130
146
|
args: config.args,
|
|
131
|
-
env: config.env ? { ...process.env, ...config.env } as Record<string, string> : undefined,
|
|
147
|
+
env: config.env ? { ...process.env, ...resolveEnv(config.env) } as Record<string, string> : undefined,
|
|
132
148
|
cwd: config.cwd,
|
|
133
149
|
stderr: "pipe",
|
|
134
150
|
});
|