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 +1 -1
- package/src/init.mjs +32 -14
- package/src/taxonomy.mjs +12 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.2.
|
|
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
|
-
//
|
|
182
|
-
|
|
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', '-
|
|
193
|
+
return { command: 'powershell', args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath] };
|
|
188
194
|
}
|
|
189
|
-
return { command: 'bash', args: [
|
|
195
|
+
return { command: 'bash', args: [scriptPath] };
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
// Derive the default vault folder name from the project folder: `.<project>-vault`.
|