agenthub-multiagent-mcp 1.75.0 → 1.76.1

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.
Files changed (112) hide show
  1. package/dist/client.d.ts +19 -1
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +31 -0
  4. package/dist/client.js.map +1 -1
  5. package/dist/commands/setup-shell.js +11 -11
  6. package/dist/currentCaptureSession.d.ts +31 -0
  7. package/dist/currentCaptureSession.d.ts.map +1 -0
  8. package/dist/currentCaptureSession.js +54 -0
  9. package/dist/currentCaptureSession.js.map +1 -0
  10. package/dist/currentCaptureSession.test.d.ts +2 -0
  11. package/dist/currentCaptureSession.test.d.ts.map +1 -0
  12. package/dist/currentCaptureSession.test.js +55 -0
  13. package/dist/currentCaptureSession.test.js.map +1 -0
  14. package/dist/employee.d.ts +11 -0
  15. package/dist/employee.d.ts.map +1 -1
  16. package/dist/employee.js +64 -1
  17. package/dist/employee.js.map +1 -1
  18. package/dist/employee.test.js +88 -1
  19. package/dist/employee.test.js.map +1 -1
  20. package/dist/goshtiChannel/client.d.ts +9 -0
  21. package/dist/goshtiChannel/client.d.ts.map +1 -0
  22. package/dist/goshtiChannel/client.js +63 -0
  23. package/dist/goshtiChannel/client.js.map +1 -0
  24. package/dist/goshtiChannel/config.d.ts +42 -0
  25. package/dist/goshtiChannel/config.d.ts.map +1 -0
  26. package/dist/goshtiChannel/config.js +129 -0
  27. package/dist/goshtiChannel/config.js.map +1 -0
  28. package/dist/goshtiChannel/config.test.d.ts +2 -0
  29. package/dist/goshtiChannel/config.test.d.ts.map +1 -0
  30. package/dist/goshtiChannel/config.test.js +73 -0
  31. package/dist/goshtiChannel/config.test.js.map +1 -0
  32. package/dist/goshtiChannel/core.d.ts +63 -0
  33. package/dist/goshtiChannel/core.d.ts.map +1 -0
  34. package/dist/goshtiChannel/core.js +237 -0
  35. package/dist/goshtiChannel/core.js.map +1 -0
  36. package/dist/goshtiChannel/core.test.d.ts +2 -0
  37. package/dist/goshtiChannel/core.test.d.ts.map +1 -0
  38. package/dist/goshtiChannel/core.test.js +250 -0
  39. package/dist/goshtiChannel/core.test.js.map +1 -0
  40. package/dist/goshtiChannel/credential.d.ts +29 -0
  41. package/dist/goshtiChannel/credential.d.ts.map +1 -0
  42. package/dist/goshtiChannel/credential.js +160 -0
  43. package/dist/goshtiChannel/credential.js.map +1 -0
  44. package/dist/goshtiChannel/credential.test.d.ts +2 -0
  45. package/dist/goshtiChannel/credential.test.d.ts.map +1 -0
  46. package/dist/goshtiChannel/credential.test.js +127 -0
  47. package/dist/goshtiChannel/credential.test.js.map +1 -0
  48. package/dist/goshtiChannel/e2e.test.d.ts +2 -0
  49. package/dist/goshtiChannel/e2e.test.d.ts.map +1 -0
  50. package/dist/goshtiChannel/e2e.test.js +163 -0
  51. package/dist/goshtiChannel/e2e.test.js.map +1 -0
  52. package/dist/goshtiChannel/policy.d.ts +154 -0
  53. package/dist/goshtiChannel/policy.d.ts.map +1 -0
  54. package/dist/goshtiChannel/policy.js +240 -0
  55. package/dist/goshtiChannel/policy.js.map +1 -0
  56. package/dist/goshtiChannel/policy.test.d.ts +2 -0
  57. package/dist/goshtiChannel/policy.test.d.ts.map +1 -0
  58. package/dist/goshtiChannel/policy.test.js +263 -0
  59. package/dist/goshtiChannel/policy.test.js.map +1 -0
  60. package/dist/goshtiChannel/setup.d.ts +15 -0
  61. package/dist/goshtiChannel/setup.d.ts.map +1 -0
  62. package/dist/goshtiChannel/setup.js +125 -0
  63. package/dist/goshtiChannel/setup.js.map +1 -0
  64. package/dist/goshtiChannel/setup.test.d.ts +2 -0
  65. package/dist/goshtiChannel/setup.test.d.ts.map +1 -0
  66. package/dist/goshtiChannel/setup.test.js +96 -0
  67. package/dist/goshtiChannel/setup.test.js.map +1 -0
  68. package/dist/goshtiChannel/stream.d.ts +39 -0
  69. package/dist/goshtiChannel/stream.d.ts.map +1 -0
  70. package/dist/goshtiChannel/stream.js +174 -0
  71. package/dist/goshtiChannel/stream.js.map +1 -0
  72. package/dist/goshtiChannel/stream.test.d.ts +2 -0
  73. package/dist/goshtiChannel/stream.test.d.ts.map +1 -0
  74. package/dist/goshtiChannel/stream.test.js +164 -0
  75. package/dist/goshtiChannel/stream.test.js.map +1 -0
  76. package/dist/goshtiChannel.d.ts +22 -0
  77. package/dist/goshtiChannel.d.ts.map +1 -0
  78. package/dist/goshtiChannel.js +193 -0
  79. package/dist/goshtiChannel.js.map +1 -0
  80. package/dist/state.d.ts +2 -0
  81. package/dist/state.d.ts.map +1 -1
  82. package/dist/state.js.map +1 -1
  83. package/dist/tools/brainWriteCheck.test.d.ts +10 -0
  84. package/dist/tools/brainWriteCheck.test.d.ts.map +1 -0
  85. package/dist/tools/brainWriteCheck.test.js +67 -0
  86. package/dist/tools/brainWriteCheck.test.js.map +1 -0
  87. package/dist/tools/employeeTraining.d.ts +46 -0
  88. package/dist/tools/employeeTraining.d.ts.map +1 -0
  89. package/dist/tools/employeeTraining.js +329 -0
  90. package/dist/tools/employeeTraining.js.map +1 -0
  91. package/dist/tools/employeeTraining.test.d.ts +7 -0
  92. package/dist/tools/employeeTraining.test.d.ts.map +1 -0
  93. package/dist/tools/employeeTraining.test.js +190 -0
  94. package/dist/tools/employeeTraining.test.js.map +1 -0
  95. package/dist/tools/index.d.ts.map +1 -1
  96. package/dist/tools/index.js +155 -5
  97. package/dist/tools/index.js.map +1 -1
  98. package/dist/tools/runs.d.ts +43 -0
  99. package/dist/tools/runs.d.ts.map +1 -0
  100. package/dist/tools/runs.js +280 -0
  101. package/dist/tools/runs.js.map +1 -0
  102. package/dist/tools/runs.test.d.ts +9 -0
  103. package/dist/tools/runs.test.d.ts.map +1 -0
  104. package/dist/tools/runs.test.js +114 -0
  105. package/dist/tools/runs.test.js.map +1 -0
  106. package/dist/tools/tools.test.js +82 -2
  107. package/dist/tools/tools.test.js.map +1 -1
  108. package/package.json +79 -78
  109. package/skills/catalog.json +104 -102
  110. package/skills/commands/close-session.md +2 -2
  111. package/skills/commands/start-session.md +2 -2
  112. package/skills/manifest.json +67 -65
@@ -0,0 +1,250 @@
1
+ // The channel's behaviour end to end, with the chat server stood in by a fake:
2
+ // what reaches the session for a given post, what the reply tool will and will
3
+ // not do, the rate cap's summary, and the failures it reports.
4
+ import { describe, expect, it } from "vitest";
5
+ import { ChannelCore } from "./core.js";
6
+ import { MARKER_PROP } from "./policy.js";
7
+ const ME = { id: "me1", username: "sumit" };
8
+ function config(over = {}) {
9
+ return {
10
+ url: "https://chat.example.com",
11
+ trigger: "@claude",
12
+ allow: { users: [], channels: [] },
13
+ rate: { max: 10, periodSeconds: 60 },
14
+ context: { posts: 10, chars: 4000 },
15
+ ...over,
16
+ };
17
+ }
18
+ function fakeApi(over = {}) {
19
+ const posted = [];
20
+ const userLookups = [];
21
+ const users = {
22
+ me1: { id: "me1", username: "sumit", is_bot: false },
23
+ col1: { id: "col1", username: "alice", is_bot: false },
24
+ bot1: { id: "bot1", username: "deploybot", is_bot: true },
25
+ };
26
+ return {
27
+ posted,
28
+ userLookups,
29
+ me: async () => users.me1,
30
+ user: async (id) => {
31
+ userLookups.push(id);
32
+ const u = users[id];
33
+ if (!u)
34
+ throw new Error("404");
35
+ return u;
36
+ },
37
+ thread: async () => [],
38
+ createPost: async (p) => {
39
+ posted.push(p);
40
+ return { id: `new${posted.length}` };
41
+ },
42
+ ...over,
43
+ };
44
+ }
45
+ function event(post, extra = {}) {
46
+ return {
47
+ post: JSON.stringify({
48
+ id: "p1",
49
+ channel_id: "chan1",
50
+ user_id: "me1",
51
+ root_id: "",
52
+ message: "@claude what changed?",
53
+ type: "",
54
+ props: {},
55
+ create_at: 1000,
56
+ ...post,
57
+ }),
58
+ channel_type: "O",
59
+ channel_name: "town-square",
60
+ channel_display_name: "Town Square",
61
+ sender_name: "@sumit",
62
+ ...extra,
63
+ };
64
+ }
65
+ function setup(cfg = config(), api = fakeApi(), clock = { now: 0 }) {
66
+ const notes = [];
67
+ const timers = [];
68
+ const core = new ChannelCore({
69
+ api,
70
+ config: cfg,
71
+ me: ME,
72
+ notify: async (content, meta) => {
73
+ notes.push({ content, meta });
74
+ },
75
+ now: () => clock.now,
76
+ schedule: (ms, fn) => {
77
+ timers.push({ at: clock.now + ms, fn });
78
+ },
79
+ });
80
+ const runTimers = () => {
81
+ for (const t of timers.splice(0))
82
+ if (t.at <= clock.now)
83
+ t.fn();
84
+ };
85
+ return { core, notes, api, clock, runTimers };
86
+ }
87
+ describe("delivery", () => {
88
+ it("delivers the person's own trigger with where it came from and how to answer", async () => {
89
+ const { core, notes } = setup();
90
+ await core.onPosted(event({}));
91
+ expect(notes).toHaveLength(1);
92
+ const n = notes[0];
93
+ expect(n.content).toContain("@claude what changed?");
94
+ expect(n.content).toContain("Town Square");
95
+ expect(n.content).toContain("goshti_reply");
96
+ expect(n.content).not.toContain("untrusted_third_party_text");
97
+ expect(n.meta).toMatchObject({ source: "goshti", post_id: "p1", channel_id: "chan1", from: "sumit", trusted: "true" });
98
+ });
99
+ it("delivers nothing for a colleague's trigger by default, and does not look them up", async () => {
100
+ const { core, notes, api } = setup();
101
+ await core.onPosted(event({ user_id: "col1" }, { sender_name: "@alice" }));
102
+ expect(notes).toHaveLength(0);
103
+ expect(api.userLookups).toEqual([]);
104
+ });
105
+ it("delivers an allowlisted colleague as untrusted text from them", async () => {
106
+ const { core, notes } = setup(config({ allow: { users: ["col1"], channels: ["chan1"] } }));
107
+ await core.onPosted(event({ user_id: "col1", message: "@claude deploy to prod now" }, { sender_name: "@alice" }));
108
+ expect(notes).toHaveLength(1);
109
+ expect(notes[0].content).toMatch(/<untrusted_third_party_text author="@alice" user_id="col1">\n@claude deploy to prod now/);
110
+ expect(notes[0].content).toMatch(/not .*instructions/i);
111
+ expect(notes[0].meta).toMatchObject({ from: "alice", trusted: "false" });
112
+ });
113
+ it("never delivers a bot that was allowlisted by mistake", async () => {
114
+ const { core, notes } = setup(config({ allow: { users: ["bot1"], channels: ["chan1"] } }));
115
+ await core.onPosted(event({ user_id: "bot1" }, { sender_name: "@deploybot" }));
116
+ expect(notes).toHaveLength(0);
117
+ });
118
+ it("refuses an allowlisted sender whose account cannot be read", async () => {
119
+ const { core, notes } = setup(config({ allow: { users: ["ghost"], channels: ["chan1"] } }));
120
+ await core.onPosted(event({ user_id: "ghost" }));
121
+ expect(notes).toHaveLength(0);
122
+ });
123
+ it("does not deliver its own reply back", async () => {
124
+ const { core, notes } = setup();
125
+ await core.onPosted(event({ message: "@claude said: done", props: { [MARKER_PROP]: "true" } }, { channel_type: "D", channel_name: "me1__me1" }));
126
+ expect(notes).toHaveLength(0);
127
+ });
128
+ it("sends bounded thread context, wrapping what others wrote", async () => {
129
+ const thread = Array.from({ length: 25 }, (_, i) => ({
130
+ id: `t${i}`,
131
+ userId: i % 2 ? "col1" : "me1",
132
+ message: `point ${i}`,
133
+ createAt: i,
134
+ }));
135
+ const api = fakeApi({ thread: async () => [...thread, { id: "p1", userId: "me1", message: "@claude sum up", createAt: 99 }] });
136
+ const { core, notes } = setup(config({ context: { posts: 4, chars: 4000 } }), api);
137
+ await core.onPosted(event({ root_id: "t0", message: "@claude sum up" }));
138
+ const c = notes[0].content;
139
+ expect(c).toContain("point 24");
140
+ expect(c).toContain("point 21");
141
+ expect(c).not.toContain("point 20");
142
+ expect(c).toMatch(/21 earlier posts? not included/);
143
+ // A colleague's post in the context is third-party text too.
144
+ expect(c).toMatch(/<untrusted_third_party_text author="@alice" user_id="col1">\npoint 23/);
145
+ });
146
+ it("still delivers when the thread cannot be read, and says so", async () => {
147
+ const api = fakeApi({ thread: async () => { throw new Error("HTTP 500"); } });
148
+ const { core, notes } = setup(config(), api);
149
+ await core.onPosted(event({ root_id: "r1" }));
150
+ expect(notes).toHaveLength(1);
151
+ expect(notes[0].content).toMatch(/thread context could not be read/i);
152
+ });
153
+ });
154
+ describe("goshti_reply", () => {
155
+ it("posts into the delivered thread, marked as Claude's", async () => {
156
+ const { core, api } = setup();
157
+ await core.onPosted(event({ id: "p1", root_id: "root1" }));
158
+ const r = await core.reply("p1", "Two things changed.");
159
+ expect(r.ok).toBe(true);
160
+ expect(api.posted).toHaveLength(1);
161
+ expect(api.posted[0]).toMatchObject({ channel_id: "chan1", root_id: "root1" });
162
+ expect(api.posted[0].message).toMatch(/^Two things changed\.[\s\S]*via Claude, for @sumit/);
163
+ expect(api.posted[0].props[MARKER_PROP]).toBe("true");
164
+ });
165
+ it("starts the thread on a top-level post", async () => {
166
+ const { core, api } = setup();
167
+ await core.onPosted(event({ id: "top", root_id: "" }));
168
+ await core.reply("top", "ok");
169
+ expect(api.posted[0].root_id).toBe("top");
170
+ });
171
+ // Spec: "Reply to an unrelated thread".
172
+ it("refuses a thread that produced no delivery this session", async () => {
173
+ const { core, api } = setup();
174
+ await core.onPosted(event({ id: "pA", root_id: "" }));
175
+ const r = await core.reply("pB", "hello");
176
+ expect(r.ok).toBe(false);
177
+ expect(r.text).toMatch(/not delivered/i);
178
+ expect(api.posted).toHaveLength(0);
179
+ });
180
+ it("refuses a post that was seen but not delivered", async () => {
181
+ const { core, api } = setup();
182
+ await core.onPosted(event({ id: "c1", user_id: "col1" }));
183
+ expect((await core.reply("c1", "hi")).ok).toBe(false);
184
+ expect(api.posted).toHaveLength(0);
185
+ });
186
+ it("refuses an empty reply", async () => {
187
+ const { core } = setup();
188
+ await core.onPosted(event({}));
189
+ expect((await core.reply("p1", " ")).ok).toBe(false);
190
+ });
191
+ it("reports a failed post rather than claiming it was sent", async () => {
192
+ const api = fakeApi({ createPost: async () => { throw new Error("HTTP 403"); } });
193
+ const { core } = setup(config(), api);
194
+ await core.onPosted(event({}));
195
+ const r = await core.reply("p1", "x");
196
+ expect(r.ok).toBe(false);
197
+ expect(r.text).toContain("403");
198
+ });
199
+ });
200
+ describe("rate cap", () => {
201
+ // Spec: "Burst of triggers".
202
+ it("delivers ten of forty and sends one summary of the thirty held back", async () => {
203
+ const { core, notes, clock, runTimers } = setup();
204
+ for (let i = 0; i < 40; i++) {
205
+ clock.now = i * 1000;
206
+ await core.onPosted(event({ id: `b${i}` }));
207
+ }
208
+ expect(notes).toHaveLength(10);
209
+ clock.now = 60_001;
210
+ runTimers();
211
+ await Promise.resolve();
212
+ expect(notes).toHaveLength(11);
213
+ expect(notes[10].content).toMatch(/30 .*held back/);
214
+ expect(notes[10].meta).toMatchObject({ source: "goshti", type: "rate_limited", held: "30" });
215
+ // A held post was never delivered, so it cannot be replied to.
216
+ expect((await core.reply("b39", "x")).ok).toBe(false);
217
+ });
218
+ });
219
+ describe("failures reported into the session (rule 7)", () => {
220
+ it("says the channel is offline and why when the token is refused", async () => {
221
+ const { core, notes } = setup();
222
+ await core.reportOffline("token_refused");
223
+ expect(notes).toHaveLength(1);
224
+ expect(notes[0].content).toMatch(/offline/i);
225
+ expect(notes[0].content).toMatch(/revoked|expired/i);
226
+ expect(notes[0].content).toMatch(/goshti-channel setup/);
227
+ expect(notes[0].meta).toMatchObject({ source: "goshti", type: "channel_status", status: "offline", reason: "token_refused" });
228
+ });
229
+ it("tells the session about the first drop and the recovery, not every retry", async () => {
230
+ const { core, notes } = setup();
231
+ await core.reportDrop({ attempt: 1, givingUp: false, detail: "socket closed (1006)" });
232
+ await core.reportDrop({ attempt: 2, givingUp: false, detail: "socket closed (1006)" });
233
+ await core.reportDrop({ attempt: 3, givingUp: false, detail: "socket closed (1006)" });
234
+ await core.reportOnline();
235
+ expect(notes.map((n) => n.meta.status)).toEqual(["reconnecting", "online"]);
236
+ });
237
+ it("says when it gives up", async () => {
238
+ const { core, notes } = setup();
239
+ await core.reportDrop({ attempt: 1, givingUp: false, detail: "x" });
240
+ await core.reportDrop({ attempt: 11, givingUp: true, detail: "connection refused" });
241
+ expect(notes.at(-1).meta.status).toBe("offline");
242
+ expect(notes.at(-1).content).toMatch(/connection refused/);
243
+ });
244
+ it("does not announce being online at first connect", async () => {
245
+ const { core, notes } = setup();
246
+ await core.reportOnline();
247
+ expect(notes).toHaveLength(0);
248
+ });
249
+ });
250
+ //# sourceMappingURL=core.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.test.js","sourceRoot":"","sources":["../../src/goshtiChannel/core.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export declare const SERVICE = "goshti-channel";
2
+ export type Runner = (cmd: string, args: string[], input?: string) => {
3
+ status: number | null;
4
+ stdout: string;
5
+ stderr: string;
6
+ };
7
+ export interface Keychain {
8
+ name: string;
9
+ get(account: string): string | null;
10
+ /** False when the store refused; the caller then falls back to the file. */
11
+ set(account: string, secret: string): boolean;
12
+ remove(account: string): boolean;
13
+ }
14
+ export declare const defaultRunner: Runner;
15
+ /** The OS credential store for a platform, or null where there is none. */
16
+ export declare function platformKeychain(platform: string, run?: Runner): Keychain | null;
17
+ export interface Stores {
18
+ keychain: Keychain | null;
19
+ dir: string;
20
+ }
21
+ /** Store a token. Returns where: `os:<store>` or `file:<path>`. */
22
+ export declare function storeCredential(account: string, token: string, stores: Stores): string;
23
+ /** The stored token, or null. Throws when the file exists but others can read it. */
24
+ export declare function loadCredential(account: string, stores: Stores): {
25
+ token: string;
26
+ where: string;
27
+ } | null;
28
+ export declare function removeCredential(account: string, stores: Stores): void;
29
+ //# sourceMappingURL=credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../../src/goshtiChannel/credential.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,OAAO,mBAAmB,CAAC;AAExC,MAAM,MAAM,MAAM,GAAG,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,CAAC,EAAE,MAAM,KACX;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,4EAA4E;IAC5E,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,MAQ3B,CAAC;AAsBF,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,QAAQ,GAAG,IAAI,CA6C/F;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAqCD,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBtF;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKvG;AAgBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGtE"}
@@ -0,0 +1,160 @@
1
+ // Where the Goshti channel keeps the person's token (add-goshti-claude-connector §2.6).
2
+ //
3
+ // In the OS credential store where there is one — Keychain on macOS, the
4
+ // Secret Service on Linux (`secret-tool`), the Windows credential vault —
5
+ // otherwise in `credentials.json` with owner-only permissions beside the
6
+ // config. Never in an environment variable, because a variable is how a token
7
+ // ends up committed in a project's `.mcp.json` env block.
8
+ //
9
+ // The token never goes on a command line: every process on the machine can
10
+ // read another's arguments. Each store is driven with the secret on stdin.
11
+ import { spawnSync } from "node:child_process";
12
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ export const SERVICE = "goshti-channel";
15
+ export const defaultRunner = (cmd, args, input) => {
16
+ const r = spawnSync(cmd, args, {
17
+ input,
18
+ encoding: "utf8",
19
+ timeout: 15_000,
20
+ windowsHide: true,
21
+ });
22
+ return { status: r.error ? null : r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
23
+ };
24
+ function psEncoded(script) {
25
+ return Buffer.from(script, "utf16le").toString("base64");
26
+ }
27
+ const PS_VAULT = `$ErrorActionPreference='Stop'
28
+ try { [void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] } catch { exit 3 }
29
+ $v = New-Object Windows.Security.Credentials.PasswordVault
30
+ $a = [Console]::In.ReadLine()
31
+ `;
32
+ const PS_GET = `${PS_VAULT}try { $c = $v.Retrieve('${SERVICE}', $a); $c.RetrievePassword(); [Console]::Out.Write($c.Password) } catch { exit 1 }`;
33
+ const PS_SET = `${PS_VAULT}$t = [Console]::In.ReadLine()
34
+ try { $o = $v.Retrieve('${SERVICE}', $a); $v.Remove($o) } catch {}
35
+ try { $v.Add((New-Object Windows.Security.Credentials.PasswordCredential('${SERVICE}', $a, $t))) } catch { exit 1 }`;
36
+ const PS_DEL = `${PS_VAULT}try { $o = $v.Retrieve('${SERVICE}', $a); $v.Remove($o) } catch { exit 1 }`;
37
+ function quoteForSecurity(s) {
38
+ return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
39
+ }
40
+ /** The OS credential store for a platform, or null where there is none. */
41
+ export function platformKeychain(platform, run = defaultRunner) {
42
+ const ok = (r) => r.status === 0;
43
+ const value = (r) => {
44
+ if (!ok(r))
45
+ return null;
46
+ const v = r.stdout.replace(/[\r\n]+$/, "");
47
+ return v === "" ? null : v;
48
+ };
49
+ switch (platform) {
50
+ case "darwin":
51
+ return {
52
+ name: "macos-keychain",
53
+ get: (a) => value(run("security", ["find-generic-password", "-s", SERVICE, "-a", a, "-w"])),
54
+ // `security -i` reads its commands from stdin, which keeps `-w <token>`
55
+ // off the process list.
56
+ set: (a, s) => ok(run("security", ["-i"], `add-generic-password -U -s ${SERVICE} -a ${quoteForSecurity(a)} -w ${quoteForSecurity(s)}\n`)),
57
+ remove: (a) => ok(run("security", ["delete-generic-password", "-s", SERVICE, "-a", a])),
58
+ };
59
+ case "linux":
60
+ return {
61
+ name: "secret-service",
62
+ get: (a) => value(run("secret-tool", ["lookup", "service", SERVICE, "account", a])),
63
+ set: (a, s) => ok(run("secret-tool", ["store", "--label", "Goshti channel", "service", SERVICE, "account", a], s)),
64
+ remove: (a) => ok(run("secret-tool", ["clear", "service", SERVICE, "account", a])),
65
+ };
66
+ case "win32": {
67
+ const ps = (script, input) => run("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", psEncoded(script)], input);
68
+ return {
69
+ name: "windows-credential-vault",
70
+ get: (a) => value(ps(PS_GET, `${a}\n`)),
71
+ set: (a, s) => ok(ps(PS_SET, `${a}\n${s}\n`)),
72
+ remove: (a) => ok(ps(PS_DEL, `${a}\n`)),
73
+ };
74
+ }
75
+ default:
76
+ return null;
77
+ }
78
+ }
79
+ function credFile(dir) {
80
+ return join(dir, "credentials.json");
81
+ }
82
+ function readFileStore(dir) {
83
+ const file = credFile(dir);
84
+ if (!existsSync(file))
85
+ return {};
86
+ if (process.platform !== "win32" && (statSync(file).mode & 0o077) !== 0) {
87
+ throw new Error(`${file} is readable by others; refusing to use it. Run \`chmod 600 ${file}\` or \`goshti-channel setup\` again.`);
88
+ }
89
+ try {
90
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
91
+ const out = {};
92
+ for (const [k, v] of Object.entries(parsed.accounts ?? {}))
93
+ if (typeof v === "string")
94
+ out[k] = v;
95
+ return out;
96
+ }
97
+ catch {
98
+ return {};
99
+ }
100
+ }
101
+ function writeFileStore(dir, accounts) {
102
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
103
+ const file = credFile(dir);
104
+ const tmp = `${file}.tmp`;
105
+ writeFileSync(tmp, `${JSON.stringify({ accounts }, null, 2)}\n`, { mode: 0o600 });
106
+ try {
107
+ chmodSync(tmp, 0o600);
108
+ }
109
+ catch {
110
+ // Windows: the per-user profile ACL is the protection.
111
+ }
112
+ renameSync(tmp, file);
113
+ }
114
+ /** Store a token. Returns where: `os:<store>` or `file:<path>`. */
115
+ export function storeCredential(account, token, stores) {
116
+ if (stores.keychain?.set(account, token)) {
117
+ // A copy left in the file from an earlier fallback would outlive a
118
+ // rotation and be the one an attacker reads.
119
+ dropFromFile(account, stores.dir);
120
+ return `os:${stores.keychain.name}`;
121
+ }
122
+ let accounts = {};
123
+ try {
124
+ accounts = readFileStore(stores.dir);
125
+ }
126
+ catch {
127
+ accounts = {}; // a file others could read is replaced, not merged into
128
+ }
129
+ accounts[account] = token;
130
+ writeFileStore(stores.dir, accounts);
131
+ return `file:${credFile(stores.dir)}`;
132
+ }
133
+ /** The stored token, or null. Throws when the file exists but others can read it. */
134
+ export function loadCredential(account, stores) {
135
+ const fromStore = stores.keychain?.get(account);
136
+ if (fromStore)
137
+ return { token: fromStore, where: `os:${stores.keychain.name}` };
138
+ const token = readFileStore(stores.dir)[account];
139
+ return token ? { token, where: `file:${credFile(stores.dir)}` } : null;
140
+ }
141
+ function dropFromFile(account, dir) {
142
+ if (!existsSync(credFile(dir)))
143
+ return;
144
+ let accounts;
145
+ try {
146
+ accounts = readFileStore(dir);
147
+ }
148
+ catch {
149
+ accounts = {};
150
+ }
151
+ if (account in accounts || Object.keys(accounts).length === 0) {
152
+ delete accounts[account];
153
+ writeFileStore(dir, accounts);
154
+ }
155
+ }
156
+ export function removeCredential(account, stores) {
157
+ stores.keychain?.remove(account);
158
+ dropFromFile(account, stores.dir);
159
+ }
160
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../../src/goshtiChannel/credential.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=credential.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.test.d.ts","sourceRoot":"","sources":["../../src/goshtiChannel/credential.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ // Rule: the credential lives in the OS store, else in a file only its owner can
2
+ // read, and never in a project's MCP configuration (spec "keep its credential
3
+ // out of project files").
4
+ import { chmodSync, existsSync, mkdtempSync, readFileSync, statSync, writeFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { describe, expect, it } from "vitest";
8
+ import { loadCredential, platformKeychain, removeCredential, storeCredential, } from "./credential.js";
9
+ const TOKEN = "s3cr3t-personal-access-token";
10
+ const ACCOUNT = "https://chat.example.com";
11
+ function dir() {
12
+ return mkdtempSync(join(tmpdir(), "goshti-cred-"));
13
+ }
14
+ function memoryKeychain() {
15
+ const items = new Map();
16
+ return {
17
+ name: "test-store",
18
+ items,
19
+ get: (a) => items.get(a) ?? null,
20
+ set: (a, s) => (items.set(a, s), true),
21
+ remove: (a) => items.delete(a),
22
+ };
23
+ }
24
+ describe("storing the credential", () => {
25
+ it("uses the OS store when there is one, and writes no file", () => {
26
+ const d = dir();
27
+ const kc = memoryKeychain();
28
+ const where = storeCredential(ACCOUNT, TOKEN, { keychain: kc, dir: d });
29
+ expect(where).toBe("os:test-store");
30
+ expect(kc.items.get(ACCOUNT)).toBe(TOKEN);
31
+ expect(existsSync(join(d, "credentials.json"))).toBe(false);
32
+ expect(loadCredential(ACCOUNT, { keychain: kc, dir: d })).toEqual({ token: TOKEN, where: "os:test-store" });
33
+ });
34
+ it("falls back to an owner-only file when the OS store refuses", () => {
35
+ const d = dir();
36
+ const broken = { name: "broken", get: () => null, set: () => false, remove: () => false };
37
+ const where = storeCredential(ACCOUNT, TOKEN, { keychain: broken, dir: d });
38
+ const file = join(d, "credentials.json");
39
+ expect(where).toBe(`file:${file}`);
40
+ expect(JSON.parse(readFileSync(file, "utf8")).accounts[ACCOUNT]).toBe(TOKEN);
41
+ if (process.platform !== "win32")
42
+ expect(statSync(file).mode & 0o077).toBe(0);
43
+ expect(loadCredential(ACCOUNT, { keychain: broken, dir: d })?.token).toBe(TOKEN);
44
+ });
45
+ it("falls back to the file when there is no OS store at all", () => {
46
+ const d = dir();
47
+ expect(storeCredential(ACCOUNT, TOKEN, { keychain: null, dir: d })).toMatch(/^file:/);
48
+ expect(loadCredential(ACCOUNT, { keychain: null, dir: d })?.token).toBe(TOKEN);
49
+ });
50
+ it.skipIf(process.platform === "win32")("refuses a credential file others can read", () => {
51
+ const d = dir();
52
+ storeCredential(ACCOUNT, TOKEN, { keychain: null, dir: d });
53
+ chmodSync(join(d, "credentials.json"), 0o644);
54
+ expect(() => loadCredential(ACCOUNT, { keychain: null, dir: d })).toThrow(/readable by others/);
55
+ });
56
+ it("reports nothing stored as null", () => {
57
+ expect(loadCredential(ACCOUNT, { keychain: memoryKeychain(), dir: dir() })).toBeNull();
58
+ });
59
+ it("removes it from both places", () => {
60
+ const d = dir();
61
+ const kc = memoryKeychain();
62
+ storeCredential(ACCOUNT, TOKEN, { keychain: kc, dir: d });
63
+ storeCredential(ACCOUNT, TOKEN, { keychain: null, dir: d });
64
+ removeCredential(ACCOUNT, { keychain: kc, dir: d });
65
+ expect(loadCredential(ACCOUNT, { keychain: kc, dir: d })).toBeNull();
66
+ });
67
+ it("ignores an environment variable holding a token", () => {
68
+ // A variable is how a token ends up in `.mcp.json`'s env block.
69
+ process.env.GOSHTI_TOKEN = TOKEN;
70
+ try {
71
+ expect(loadCredential(ACCOUNT, { keychain: null, dir: dir() })).toBeNull();
72
+ }
73
+ finally {
74
+ delete process.env.GOSHTI_TOKEN;
75
+ }
76
+ });
77
+ it("does not leave the file readable by others even if it existed before", () => {
78
+ if (process.platform === "win32")
79
+ return;
80
+ const d = dir();
81
+ const file = join(d, "credentials.json");
82
+ writeFileSync(file, JSON.stringify({ accounts: {} }), { mode: 0o644 });
83
+ storeCredential(ACCOUNT, TOKEN, { keychain: null, dir: d });
84
+ expect(statSync(file).mode & 0o077).toBe(0);
85
+ });
86
+ });
87
+ describe("the OS stores", () => {
88
+ function recorder(status = 0, stdout = "") {
89
+ const calls = [];
90
+ return {
91
+ calls,
92
+ run: (cmd, args, input) => {
93
+ calls.push({ cmd, args, input });
94
+ return { status, stdout, stderr: "" };
95
+ },
96
+ };
97
+ }
98
+ // A command line is visible to every process on the machine; stdin is not.
99
+ for (const platform of ["darwin", "linux", "win32"]) {
100
+ it(`${platform}: never puts the token on a command line`, () => {
101
+ const r = recorder();
102
+ const kc = platformKeychain(platform, r.run);
103
+ expect(kc).not.toBeNull();
104
+ kc.set(ACCOUNT, TOKEN);
105
+ expect(r.calls.length).toBeGreaterThan(0);
106
+ for (const c of r.calls) {
107
+ expect(c.args.join(" ")).not.toContain(TOKEN);
108
+ expect(c.cmd).not.toContain(TOKEN);
109
+ }
110
+ expect(r.calls.some((c) => c.input?.includes(TOKEN))).toBe(true);
111
+ });
112
+ it(`${platform}: reads the token from the store's output`, () => {
113
+ const r = recorder(0, `${TOKEN}\n`);
114
+ expect(platformKeychain(platform, r.run).get(ACCOUNT)).toBe(TOKEN);
115
+ });
116
+ it(`${platform}: a failing store reads as nothing stored`, () => {
117
+ const r = recorder(1, "");
118
+ const kc = platformKeychain(platform, r.run);
119
+ expect(kc.get(ACCOUNT)).toBeNull();
120
+ expect(kc.set(ACCOUNT, TOKEN)).toBe(false);
121
+ });
122
+ }
123
+ it("has no store on an unknown platform", () => {
124
+ expect(platformKeychain("aix", recorder().run)).toBeNull();
125
+ });
126
+ });
127
+ //# sourceMappingURL=credential.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.test.js","sourceRoot":"","sources":["../../src/goshtiChannel/credential.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e.test.d.ts","sourceRoot":"","sources":["../../src/goshtiChannel/e2e.test.ts"],"names":[],"mappings":""}