tandem-editor 0.7.0 → 0.7.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.
File without changes
package/dist/cli/index.js CHANGED
@@ -51,15 +51,29 @@ __export(setup_exports, {
51
51
  validateChannelShimPrereq: () => validateChannelShimPrereq
52
52
  });
53
53
  import { randomUUID } from "crypto";
54
- import { existsSync, readFileSync as readFileSync2 } from "fs";
54
+ import { existsSync, readdirSync, readFileSync as readFileSync2 } from "fs";
55
55
  import { copyFile, mkdir, rename, unlink, writeFile } from "fs/promises";
56
56
  import { homedir } from "os";
57
57
  import { basename, dirname as dirname2, join, resolve as resolve2 } from "path";
58
58
  import { fileURLToPath as fileURLToPath2 } from "url";
59
59
  function buildMcpEntries(channelPath, opts = {}) {
60
- const tandemEntry = { type: "http", url: `${MCP_URL}/mcp` };
61
- if (opts.token) {
62
- tandemEntry.headers = { Authorization: `Bearer ${opts.token}` };
60
+ const isDesktop = opts.targetKind === "claude-desktop";
61
+ let tandemEntry;
62
+ if (isDesktop) {
63
+ const env = { TANDEM_URL: MCP_URL };
64
+ if (opts.token) {
65
+ env.TANDEM_AUTH_TOKEN = opts.token;
66
+ }
67
+ tandemEntry = {
68
+ command: "npx",
69
+ args: ["-y", "tandem-editor", "mcp-stdio"],
70
+ env
71
+ };
72
+ } else {
73
+ tandemEntry = { type: "http", url: `${MCP_URL}/mcp` };
74
+ if (opts.token) {
75
+ tandemEntry.headers = { Authorization: `Bearer ${opts.token}` };
76
+ }
63
77
  }
64
78
  const entries = { tandem: tandemEntry };
65
79
  if (opts.withChannelShim) {
@@ -81,7 +95,7 @@ function detectTargets(opts = {}) {
81
95
  const claudeCodeConfig = join(home, ".claude.json");
82
96
  const claudeCodeDir = join(home, ".claude");
83
97
  if (opts.force || existsSync(claudeCodeConfig) || existsSync(claudeCodeDir)) {
84
- targets.push({ label: "Claude Code", configPath: claudeCodeConfig });
98
+ targets.push({ label: "Claude Code", configPath: claudeCodeConfig, kind: "claude-code" });
85
99
  }
86
100
  let desktopConfig = null;
87
101
  if (process.platform === "win32") {
@@ -99,7 +113,33 @@ function detectTargets(opts = {}) {
99
113
  desktopConfig = join(home, ".config", "claude", "claude_desktop_config.json");
100
114
  }
101
115
  if (desktopConfig && (opts.force || existsSync(desktopConfig))) {
102
- targets.push({ label: "Claude Desktop", configPath: desktopConfig });
116
+ targets.push({ label: "Claude Desktop", configPath: desktopConfig, kind: "claude-desktop" });
117
+ }
118
+ if (process.platform === "win32") {
119
+ const localAppData = opts.localAppDataOverride ?? process.env.LOCALAPPDATA ?? join(home, "AppData", "Local");
120
+ const packagesDir = join(localAppData, "Packages");
121
+ try {
122
+ const entries = readdirSync(packagesDir);
123
+ for (const pkg of entries.filter((n) => n.startsWith("Claude_"))) {
124
+ const msixConfig = join(
125
+ packagesDir,
126
+ pkg,
127
+ "LocalCache",
128
+ "Roaming",
129
+ "Claude",
130
+ "claude_desktop_config.json"
131
+ );
132
+ if (opts.force || existsSync(msixConfig)) {
133
+ const suffix = entries.filter((n) => n.startsWith("Claude_")).length > 1 ? ` (${pkg.slice(0, 12)}\u2026)` : "";
134
+ targets.push({
135
+ label: `Claude Desktop MSIX${suffix}`,
136
+ configPath: msixConfig,
137
+ kind: "claude-desktop"
138
+ });
139
+ }
140
+ }
141
+ } catch {
142
+ }
103
143
  }
104
144
  return targets;
105
145
  }
@@ -167,13 +207,14 @@ function validateChannelShimPrereq(channelPath) {
167
207
  }
168
208
  async function applyConfigWithToken(token, opts = {}) {
169
209
  const targets = detectTargets({ force: opts.force });
170
- const entries = buildMcpEntries(CHANNEL_DIST, {
171
- withChannelShim: opts.withChannelShim,
172
- token: token ?? void 0
173
- });
174
210
  let updated = 0;
175
211
  const errors = [];
176
212
  for (const t of targets) {
213
+ const entries = buildMcpEntries(CHANNEL_DIST, {
214
+ withChannelShim: opts.withChannelShim,
215
+ token: token ?? void 0,
216
+ targetKind: t.kind
217
+ });
177
218
  try {
178
219
  await applyConfig(t.configPath, entries);
179
220
  updated++;
@@ -204,9 +245,12 @@ Run 'npm run build' first, or drop --with-channel-shim to use the plugin monitor
204
245
  console.error(` Found: ${t.label} (${t.configPath})`);
205
246
  }
206
247
  console.error("\nWriting MCP configuration...");
207
- const entries = buildMcpEntries(CHANNEL_DIST, { withChannelShim: opts.withChannelShim });
208
248
  let failures = 0;
209
249
  for (const t of targets) {
250
+ const entries = buildMcpEntries(CHANNEL_DIST, {
251
+ withChannelShim: opts.withChannelShim,
252
+ targetKind: t.kind
253
+ });
210
254
  try {
211
255
  await applyConfig(t.configPath, entries);
212
256
  console.error(` \x1B[32m\u2713\x1B[0m ${t.label}`);
@@ -1320,7 +1364,7 @@ process.once("unhandledRejection", (reason) => {
1320
1364
  `);
1321
1365
  process.exit(1);
1322
1366
  });
1323
- var version = true ? "0.7.0" : "0.0.0-dev";
1367
+ var version = true ? "0.7.1" : "0.0.0-dev";
1324
1368
  var args = process.argv.slice(2);
1325
1369
  var isStdioMode = args[0] === "mcp-stdio" || args[0] === "channel";
1326
1370
  if (!isStdioMode) {