ultimate-pi 0.6.0 → 0.6.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.
@@ -1,30 +1,44 @@
1
1
  # ultimate-pi harness — local secrets and paths (gitignored .env)
2
- # Fill in values below; re-run /harness-setup to add newly introduced keys only.
2
+ # Created by /harness-setup (harness-sync-env.mjs). Re-run setup to append newly introduced keys only.
3
3
 
4
- # Telemetry (set false to disable harness PostHog events)
4
+ # --- Telemetry ---
5
+ # Harness domain events (harness-telemetry.ts); set false to disable harness_* only
5
6
  HARNESS_TELEMETRY_ENABLED=true
6
7
 
7
- # harness-web (Scrapling scrape + pluggable search)
8
+ # --- harness-web (Scrapling scrape + pluggable search) ---
8
9
  HARNESS_WEB_FETCH_MODE=stealth
9
10
  HARNESS_WEB_SEARCH_ENGINE=ddg_html
10
- # SearXNG (when HARNESS_WEB_SEARCH_ENGINE=searxng):
11
+ # When HARNESS_WEB_SEARCH_ENGINE=searxng (bootstrap via harness-searxng-bootstrap.mjs):
11
12
  # HARNESS_WEB_SEARXNG_URL=http://127.0.0.1:8080
12
13
  # HARNESS_WEB_PROXY=
13
14
  # HARNESS_WEB_RATE_LIMIT_MS=2000
14
15
  # HARNESS_WEB_TIMEOUT_MS=30000
15
16
 
16
- # PostHog (optional)
17
+ # --- VCC compaction (env-only; no JSON config files) ---
18
+ # Default: VCC handles /compact and auto-compaction. Set false for Pi LLM compaction:
19
+ # HARNESS_VCC_COMPACTION=false
20
+ # HARNESS_VCC_DEBUG=true
21
+
22
+ # --- PostHog (optional) ---
23
+ # Project key — required for harness_* telemetry when HARNESS_TELEMETRY_ENABLED=true
17
24
  # POSTHOG_API_KEY=
25
+ # POSTHOG_HOST=https://us.i.posthog.com
26
+ # POSTHOG_ENABLED=true
18
27
  # POSTHOG_PROJECT_NAME=ultimate-pi
19
28
  # POSTHOG_PRIVACY_MODE=false
29
+ # Personal API key — PostHog MCP / posthog-analyst skill only
30
+ # POSTHOG_PERSONAL_API_KEY=
31
+ # POSTHOG_MCP_FEATURES=llm_analytics
20
32
 
21
- # Graphify semantic extract (optional; `graphify update .` needs no key)
33
+ # --- Graphify semantic extract (optional; `graphify update .` needs no key) ---
22
34
  # GEMINI_API_KEY=
23
35
  # GOOGLE_API_KEY=
24
36
  # OPENAI_API_KEY=
37
+ # OPENAI_API_BASE=
25
38
 
26
- # Pi VCC compaction config path (project-relative)
27
- PI_VCC_CONFIG_PATH=.pi/pi-vcc-config.json
39
+ # --- Wiki / Obsidian vault (optional) ---
40
+ VAULT_WIKI_PATH=vault/wiki
28
41
 
29
- # Wiki / vault (optional — Obsidian layer)
30
- # VAULT_WIKI_PATH=vault/wiki
42
+ # --- Sentrux gate (optional) ---
43
+ # Require Sentrux stub for harness-verify (see .pi/scripts/harness-verify.mjs)
44
+ # HARNESS_SENTRUX_REQUIRED=true
@@ -21,6 +21,7 @@ import {
21
21
  readFile,
22
22
  writeFile,
23
23
  } from "node:fs/promises";
24
+ import { randomBytes } from "node:crypto";
24
25
  import { constants } from "node:fs";
25
26
  import { join, dirname } from "node:path";
26
27
  import { fileURLToPath } from "node:url";
@@ -50,7 +51,10 @@ const SETTINGS_PATH = join(CORE_CONFIG, "settings.yml");
50
51
  const COMPOSE_PATH = join(SEARXNG_DIR, "docker-compose.yml");
51
52
  const ENV_COMPOSE = join(SEARXNG_DIR, ".env");
52
53
 
53
- const HARNESS_SETTINGS = `use_default_settings: true
54
+ const DEFAULT_SECRET = "ultrasecretkey";
55
+
56
+ function buildHarnessSettings(secret) {
57
+ return `use_default_settings: true
54
58
 
55
59
  search:
56
60
  formats:
@@ -58,9 +62,11 @@ search:
58
62
  - json
59
63
 
60
64
  server:
65
+ secret_key: "${secret}"
61
66
  limiter: false
62
67
  public_instance: false
63
68
  `;
69
+ }
64
70
 
65
71
  async function exists(path) {
66
72
  try {
@@ -138,6 +144,69 @@ async function readComposePort() {
138
144
  return DEFAULT_PORT;
139
145
  }
140
146
 
147
+ function parseEnvValue(raw) {
148
+ return raw.trim().replace(/^["']|["']$/g, "");
149
+ }
150
+
151
+ async function readComposeSecret() {
152
+ if (!(await exists(ENV_COMPOSE))) return null;
153
+ const text = await readFile(ENV_COMPOSE, "utf8");
154
+ for (const line of text.split("\n")) {
155
+ const m = line.match(/^SEARXNG_SECRET=(.+)$/);
156
+ if (m) {
157
+ const val = parseEnvValue(m[1]);
158
+ if (val && val !== DEFAULT_SECRET) return val;
159
+ }
160
+ }
161
+ return null;
162
+ }
163
+
164
+ async function readSettingsSecret() {
165
+ if (!(await exists(SETTINGS_PATH))) return null;
166
+ const text = await readFile(SETTINGS_PATH, "utf8");
167
+ const m = text.match(/^\s*secret_key:\s*["']?([^"'\n#]+)["']?\s*$/m);
168
+ if (!m) return null;
169
+ const val = m[1].trim();
170
+ return val && val !== DEFAULT_SECRET ? val : null;
171
+ }
172
+
173
+ function generateSecret() {
174
+ return randomBytes(32).toString("hex");
175
+ }
176
+
177
+ async function getOrCreateSecret() {
178
+ return (
179
+ (await readComposeSecret()) ||
180
+ (await readSettingsSecret()) ||
181
+ generateSecret()
182
+ );
183
+ }
184
+
185
+ async function upsertComposeSecret(secret) {
186
+ let content = "";
187
+ if (await exists(ENV_COMPOSE)) {
188
+ content = await readFile(ENV_COMPOSE, "utf8");
189
+ }
190
+ const line = `SEARXNG_SECRET=${secret}`;
191
+ const re = /^SEARXNG_SECRET=.*$/m;
192
+ if (re.test(content)) {
193
+ content = content.replace(re, line);
194
+ } else {
195
+ const sep = content.endsWith("\n") || content.length === 0 ? "" : "\n";
196
+ content = `${content}${sep}${line}\n`;
197
+ }
198
+ await writeFile(ENV_COMPOSE, content, "utf8");
199
+ }
200
+
201
+ async function settingsNeedUpdate() {
202
+ if (!(await exists(SETTINGS_PATH))) return true;
203
+ const text = await readFile(SETTINGS_PATH, "utf8");
204
+ if (!text.includes("json")) return true;
205
+ if (text.includes(DEFAULT_SECRET)) return true;
206
+ if (!/^\s*secret_key:/m.test(text)) return true;
207
+ return false;
208
+ }
209
+
141
210
  async function ensureSearxngLayout() {
142
211
  await mkdir(CORE_CONFIG, { recursive: true });
143
212
  if (!(await exists(COMPOSE_PATH))) {
@@ -152,12 +221,28 @@ async function ensureSearxngLayout() {
152
221
  }
153
222
  await copyFile(example, ENV_COMPOSE);
154
223
  }
155
- const needsSettings =
156
- !(await exists(SETTINGS_PATH)) ||
157
- !(await readFile(SETTINGS_PATH, "utf8")).includes("json");
158
- if (needsSettings) {
159
- await writeFile(SETTINGS_PATH, HARNESS_SETTINGS, "utf8");
160
- console.log(`✓ Wrote ${SETTINGS_PATH} (json format, limiter off)`);
224
+ const secret = await getOrCreateSecret();
225
+ await upsertComposeSecret(secret);
226
+ console.log(`✓ Set SEARXNG_SECRET in ${ENV_COMPOSE}`);
227
+ if (await settingsNeedUpdate()) {
228
+ try {
229
+ await writeFile(SETTINGS_PATH, buildHarnessSettings(secret), "utf8");
230
+ console.log(
231
+ `✓ Wrote ${SETTINGS_PATH} (json format, limiter off, secret_key set)`,
232
+ );
233
+ } catch (err) {
234
+ if (err && typeof err === "object" && "code" in err && err.code === "EACCES") {
235
+ console.warn(
236
+ `⚠ Could not write ${SETTINGS_PATH} (permission denied). ` +
237
+ "SEARXNG_SECRET in .env is set — restart containers. " +
238
+ `Fix ownership: chown -R $USER:$USER ${SEARXNG_DIR}`,
239
+ );
240
+ } else {
241
+ throw err;
242
+ }
243
+ }
244
+ } else {
245
+ console.log(`✓ ${SETTINGS_PATH} already configured`);
161
246
  }
162
247
  }
163
248
 
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [v0.6.1] — 2026-05-17
8
+
9
+ ### 🐛 Fixes
10
+
11
+ - **SearXNG bootstrap:** generate `SEARXNG_SECRET` and set `server.secret_key` so containers no longer crash on the default `ultrasecretkey` (SearXNG 2026.4+).
12
+ - **Harness env template:** remove obsolete `PI_VCC_CONFIG_PATH`; add env-only VCC, PostHog MCP, Sentrux, and default `VAULT_WIKI_PATH` keys aligned with `/harness-setup`.
13
+
7
14
  ## [v0.6.0] — 2026-05-17
8
15
 
9
16
  ### ✨ Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-pi",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Ultimate AI coding harness for pi.dev — extensible skills, Obsidian wiki knowledge layer, compressed context, deterministic output",
5
5
  "keywords": [
6
6
  "pi-package",