wendkeep 0.2.1 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Automatically capture AI coding agent sessions (Claude Code, Codex) as local Markdown in your Obsidian vault — turn-by-turn history, cost/token tracking, auto-extracted decisions/bugs/learnings, rendered in the graph. Local-first.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/init.mjs CHANGED
@@ -3,7 +3,8 @@
3
3
  // OBSIDIAN_VAULT_PATH into .claude/settings.json, and adds the mcpvault server to
4
4
  // .mcp.json. Idempotent: re-running only adds what is missing.
5
5
  import { spawnSync } from 'node:child_process';
6
- import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
6
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
7
8
  import { basename, isAbsolute, join, resolve } from 'node:path';
8
9
  import { createInterface } from 'node:readline/promises';
9
10
  import {
@@ -19,6 +20,7 @@ import {
19
20
  companionMcpPatch,
20
21
  companionHookSpecs,
21
22
  cavemanInstallerCommand,
23
+ cavemanInstallerUrl,
22
24
  } from './taxonomy.mjs';
23
25
  import { renderVaultReadme } from './vault-readme.mjs';
24
26
  import { canInteractiveSelect, selectCompanionsInteractive } from './companion-select.mjs';
@@ -118,6 +120,32 @@ export function mergeMcp(existing, { vaultPath, withVault = true, companions = [
118
120
  return m;
119
121
  }
120
122
 
123
+ // Run caveman's cross-agent installer (non-Claude skill coverage). Downloads the
124
+ // script to a temp file and runs it as a FILE — piping to iex/bash leaves the
125
+ // script's self-path null and the installer aborts. Best-effort, fail-soft: the
126
+ // Claude Code plugin entry is already wired regardless.
127
+ async function runCavemanInstaller(log) {
128
+ const url = cavemanInstallerUrl();
129
+ const ext = process.platform === 'win32' ? 'ps1' : 'sh';
130
+ const tmp = join(tmpdir(), `wendkeep-caveman-install-${process.pid}.${ext}`);
131
+ log(`\n caveman: fetching cross-agent installer (best-effort): ${url}`);
132
+ try {
133
+ const res = await fetch(url);
134
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
135
+ writeFileSync(tmp, await res.text(), 'utf8');
136
+ const cmd = cavemanInstallerCommand(process.platform, tmp);
137
+ log(` caveman: running ${cmd.command} ${cmd.args.join(' ')}`);
138
+ const r = spawnSync(cmd.command, cmd.args, { stdio: 'inherit' });
139
+ if (r.status !== 0) {
140
+ log(` [!] caveman installer exited ${r.status ?? '?'} — Claude Code plugin entry still wired; rerun manually if needed.`);
141
+ }
142
+ } catch (e) {
143
+ log(` [!] caveman installer skipped (${e.message}) — Claude Code plugin entry still wired.`);
144
+ } finally {
145
+ try { rmSync(tmp, { force: true }); } catch { /* temp cleanup best-effort */ }
146
+ }
147
+ }
148
+
121
149
  // --- main -------------------------------------------------------------------
122
150
 
123
151
  export async function runInit(argv) {
@@ -148,11 +176,12 @@ export async function runInit(argv) {
148
176
  } else if (args.companions !== undefined) {
149
177
  companions = resolveCompanions({ companionsFlag: args.companions });
150
178
  } else if (process.stdin.isTTY && !args.yes) {
151
- log('\nCompanions (plugins/MCP opcionais — context-mode é a principal):');
152
179
  if (canInteractiveSelect()) {
180
+ log(''); // the checkbox menu renders its own header
153
181
  companions = await selectCompanionsInteractive(COMPANIONS);
154
182
  } else {
155
183
  // Text fallback (no raw-mode TTY): list + comma input with clear instructions.
184
+ log('\nCompanions (plugins/MCP opcionais — context-mode é a principal):');
156
185
  for (const c of COMPANIONS) log(` ${c.default ? '[x]' : '[ ]'} ${c.label}`);
157
186
  const def = resolveCompanions({}).join(',');
158
187
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -231,18 +260,7 @@ export async function runInit(argv) {
231
260
  // caveman has no MCP / agnostic-hook path: on non-Claude agents its skills come
232
261
  // from its own cross-agent installer. Best-effort, fail-soft — the Claude Code
233
262
  // plugin entry is already wired in settings.json regardless.
234
- if (companions.includes('caveman')) {
235
- const cmd = cavemanInstallerCommand();
236
- log(`\n caveman: running cross-agent installer (best-effort): ${cmd.command} ${cmd.args.join(' ')}`);
237
- try {
238
- const r = spawnSync(cmd.command, cmd.args, { stdio: 'inherit' });
239
- if (r.status !== 0) {
240
- log(` [!] caveman installer exited ${r.status ?? '?'} — Claude Code plugin entry still wired; rerun manually if needed.`);
241
- }
242
- } catch (e) {
243
- log(` [!] caveman installer could not run (${e.code || e.message}) — Claude Code plugin entry still wired.`);
244
- }
245
- }
263
+ if (companions.includes('caveman')) await runCavemanInstaller(log);
246
264
 
247
265
  log('\nNext steps:');
248
266
  log(` 1. Open the vault in Obsidian: "Open folder as vault" -> ${vaultPath}`);
package/src/taxonomy.mjs CHANGED
@@ -178,15 +178,21 @@ export function companionHookSpecs(ids) {
178
178
  return specs;
179
179
  }
180
180
 
181
- // Build the platform-appropriate command to run caveman's own cross-agent installer
182
- // (used on non-Claude agents — caveman has no MCP/agnostic-hook path). Pure: returns
183
- // {command, args}; the caller decides whether to spawn it.
184
- export function cavemanInstallerCommand(platform = process.platform) {
181
+ // The caveman installer URL for this platform (.ps1 on Windows, .sh elsewhere).
182
+ export function cavemanInstallerUrl(platform = process.platform) {
185
183
  const { sh, ps1 } = COMPANION_BY_ID.caveman.installer;
184
+ return platform === 'win32' ? ps1 : sh;
185
+ }
186
+
187
+ // Command to run caveman's installer FROM A LOCAL FILE. We download the script to a
188
+ // temp file and run it as a file (not `irm|iex` / `curl|bash`) so the script gets a
189
+ // real $PSCommandPath/$0 — piping to iex leaves that null and the installer aborts
190
+ // ("cannot bind argument to parameter 'Path'"). Pure: returns {command, args}.
191
+ export function cavemanInstallerCommand(platform = process.platform, scriptPath) {
186
192
  if (platform === 'win32') {
187
- return { command: 'powershell', args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', `irm ${ps1} | iex`] };
193
+ return { command: 'powershell', args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath] };
188
194
  }
189
- return { command: 'bash', args: ['-c', `curl -fsSL ${sh} | bash`] };
195
+ return { command: 'bash', args: [scriptPath] };
190
196
  }
191
197
 
192
198
  // Derive the default vault folder name from the project folder: `.<project>-vault`.