pi-para 0.5.2 → 0.6.0
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/ARCHITECTURE.md +160 -0
- package/CHANGELOG.md +51 -0
- package/CONFIGURATION.md +243 -0
- package/README.md +140 -237
- package/SETUP.md +196 -112
- package/STRUCTURE.md +140 -0
- package/package.json +86 -18
- package/scripts/build-assets.mjs +29 -0
- package/scripts/install.ps1 +55 -0
- package/scripts/install.sh +63 -0
- package/scripts/smoke-install.mjs +63 -0
- package/skills/para/SKILL.md +1 -1
- package/skills/setup/SKILL.md +1 -1
- package/src/atomic-write.ts +17 -0
- package/src/capture.ts +4 -4
- package/src/cli-legacy.ts +43 -0
- package/src/cli.ts +133 -28
- package/src/commands.ts +203 -243
- package/src/config.ts +355 -0
- package/src/context.ts +29 -14
- package/src/credentials.ts +100 -0
- package/src/daemon.ts +1 -1
- package/src/doctor.ts +209 -0
- package/src/gepa/index.ts +1 -1
- package/src/index.ts +119 -40
- package/src/maintainer.ts +4 -4
- package/src/model-resolver.ts +96 -0
- package/src/paths.ts +48 -0
- package/src/processor.ts +4 -4
- package/src/qmd-providers.ts +63 -0
- package/src/query.ts +15 -1
- package/src/repair.ts +49 -0
- package/src/scheduler/controls.ts +125 -0
- package/src/scheduler/index.ts +210 -0
- package/src/scheduler/leases.ts +98 -0
- package/src/scheduler/session-capture.ts +146 -0
- package/src/scheduler/state.ts +304 -0
- package/src/session-tools.ts +1 -1
- package/src/settings.ts +126 -0
- package/src/setup.ts +116 -0
- package/src/status.ts +115 -0
- package/src/store.ts +116 -31
- package/src/summarize.ts +72 -16
- package/src/templates/prompts.ts +1 -1
- package/src/tools.ts +280 -90
- package/src/wiki-tool-guidance.ts +84 -0
- package/src/wiki.ts +98 -26
- package/dist/capture.d.ts +0 -34
- package/dist/capture.d.ts.map +0 -1
- package/dist/capture.js +0 -461
- package/dist/capture.js.map +0 -1
- package/dist/cli.d.ts +0 -15
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -405
- package/dist/cli.js.map +0 -1
- package/dist/commands.d.ts +0 -15
- package/dist/commands.d.ts.map +0 -1
- package/dist/commands.js +0 -786
- package/dist/commands.js.map +0 -1
- package/dist/context.d.ts +0 -61
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -289
- package/dist/context.js.map +0 -1
- package/dist/daemon.d.ts +0 -49
- package/dist/daemon.d.ts.map +0 -1
- package/dist/daemon.js +0 -226
- package/dist/daemon.js.map +0 -1
- package/dist/frontmatter.d.ts +0 -59
- package/dist/frontmatter.d.ts.map +0 -1
- package/dist/frontmatter.js +0 -170
- package/dist/frontmatter.js.map +0 -1
- package/dist/gepa/dataset.d.ts +0 -36
- package/dist/gepa/dataset.d.ts.map +0 -1
- package/dist/gepa/dataset.js +0 -148
- package/dist/gepa/dataset.js.map +0 -1
- package/dist/gepa/evaluator.d.ts +0 -51
- package/dist/gepa/evaluator.d.ts.map +0 -1
- package/dist/gepa/evaluator.js +0 -317
- package/dist/gepa/evaluator.js.map +0 -1
- package/dist/gepa/index.d.ts +0 -66
- package/dist/gepa/index.d.ts.map +0 -1
- package/dist/gepa/index.js +0 -240
- package/dist/gepa/index.js.map +0 -1
- package/dist/gepa/llm.d.ts +0 -35
- package/dist/gepa/llm.d.ts.map +0 -1
- package/dist/gepa/llm.js +0 -268
- package/dist/gepa/llm.js.map +0 -1
- package/dist/gepa/optimized/capture-prompt.txt +0 -65
- package/dist/gepa/optimizer.d.ts +0 -29
- package/dist/gepa/optimizer.d.ts.map +0 -1
- package/dist/gepa/optimizer.js +0 -249
- package/dist/gepa/optimizer.js.map +0 -1
- package/dist/gepa/targets.d.ts +0 -39
- package/dist/gepa/targets.d.ts.map +0 -1
- package/dist/gepa/targets.js +0 -326
- package/dist/gepa/targets.js.map +0 -1
- package/dist/gepa/types.d.ts +0 -168
- package/dist/gepa/types.d.ts.map +0 -1
- package/dist/gepa/types.js +0 -124
- package/dist/gepa/types.js.map +0 -1
- package/dist/index.d.ts +0 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -294
- package/dist/index.js.map +0 -1
- package/dist/ingest.d.ts +0 -88
- package/dist/ingest.d.ts.map +0 -1
- package/dist/ingest.js +0 -105
- package/dist/ingest.js.map +0 -1
- package/dist/link-discovery.d.ts +0 -40
- package/dist/link-discovery.d.ts.map +0 -1
- package/dist/link-discovery.js +0 -122
- package/dist/link-discovery.js.map +0 -1
- package/dist/link-utils.d.ts +0 -30
- package/dist/link-utils.d.ts.map +0 -1
- package/dist/link-utils.js +0 -145
- package/dist/link-utils.js.map +0 -1
- package/dist/lint.d.ts +0 -39
- package/dist/lint.d.ts.map +0 -1
- package/dist/lint.js +0 -827
- package/dist/lint.js.map +0 -1
- package/dist/maintainer.d.ts +0 -24
- package/dist/maintainer.d.ts.map +0 -1
- package/dist/maintainer.js +0 -358
- package/dist/maintainer.js.map +0 -1
- package/dist/processor.d.ts +0 -14
- package/dist/processor.d.ts.map +0 -1
- package/dist/processor.js +0 -361
- package/dist/processor.js.map +0 -1
- package/dist/query.d.ts +0 -69
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js +0 -107
- package/dist/query.js.map +0 -1
- package/dist/raw.d.ts +0 -57
- package/dist/raw.d.ts.map +0 -1
- package/dist/raw.js +0 -219
- package/dist/raw.js.map +0 -1
- package/dist/redact.d.ts +0 -21
- package/dist/redact.d.ts.map +0 -1
- package/dist/redact.js +0 -143
- package/dist/redact.js.map +0 -1
- package/dist/scope.d.ts +0 -54
- package/dist/scope.d.ts.map +0 -1
- package/dist/scope.js +0 -161
- package/dist/scope.js.map +0 -1
- package/dist/scripts/bulk-link-fix.d.ts +0 -9
- package/dist/scripts/bulk-link-fix.d.ts.map +0 -1
- package/dist/scripts/bulk-link-fix.js +0 -106
- package/dist/scripts/bulk-link-fix.js.map +0 -1
- package/dist/session-tools.d.ts +0 -33
- package/dist/session-tools.d.ts.map +0 -1
- package/dist/session-tools.js +0 -211
- package/dist/session-tools.js.map +0 -1
- package/dist/state.d.ts +0 -54
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js +0 -176
- package/dist/state.js.map +0 -1
- package/dist/store.d.ts +0 -56
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -227
- package/dist/store.js.map +0 -1
- package/dist/summarize.d.ts +0 -56
- package/dist/summarize.d.ts.map +0 -1
- package/dist/summarize.js +0 -231
- package/dist/summarize.js.map +0 -1
- package/dist/tag-registry.d.ts +0 -56
- package/dist/tag-registry.d.ts.map +0 -1
- package/dist/tag-registry.js +0 -146
- package/dist/tag-registry.js.map +0 -1
- package/dist/templates/prompts.d.ts +0 -63
- package/dist/templates/prompts.d.ts.map +0 -1
- package/dist/templates/prompts.js +0 -260
- package/dist/templates/prompts.js.map +0 -1
- package/dist/tools.d.ts +0 -26
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -1033
- package/dist/tools.js.map +0 -1
- package/dist/watcher.d.ts +0 -25
- package/dist/watcher.d.ts.map +0 -1
- package/dist/watcher.js +0 -84
- package/dist/watcher.js.map +0 -1
- package/dist/webui/client/dist/index.html +0 -1885
- package/dist/webui/server.d.ts +0 -31
- package/dist/webui/server.d.ts.map +0 -1
- package/dist/webui/server.js +0 -566
- package/dist/webui/server.js.map +0 -1
- package/dist/wiki.d.ts +0 -103
- package/dist/wiki.d.ts.map +0 -1
- package/dist/wiki.js +0 -428
- package/dist/wiki.js.map +0 -1
- package/scripts/gepa/__pycache__/dataset.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/lm_providers.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/metric.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/program.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/wiki_reader.cpython-313.pyc +0 -0
- package/scripts/gepa/uv.lock +0 -2241
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* v8 ignore start */
|
|
3
|
+
// Cross-platform post-tsc asset copy (replaces POSIX mkdir -p/cp in npm build).
|
|
4
|
+
import { cp, mkdir, readdir } from "node:fs/promises";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { join, resolve, dirname } from "node:path";
|
|
8
|
+
|
|
9
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
|
|
11
|
+
// 1. Web UI client bundle
|
|
12
|
+
const webuiSrc = join(root, "src", "webui", "client", "dist", "index.html");
|
|
13
|
+
const webuiDestDir = join(root, "dist", "webui", "client", "dist");
|
|
14
|
+
await mkdir(webuiDestDir, { recursive: true });
|
|
15
|
+
if (existsSync(webuiSrc)) {
|
|
16
|
+
await cp(webuiSrc, join(webuiDestDir, "index.html"));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. GEPA optimized prompt text files (optional)
|
|
20
|
+
const gepaSrcDir = join(root, "src", "gepa", "optimized");
|
|
21
|
+
const gepaDestDir = join(root, "dist", "gepa", "optimized");
|
|
22
|
+
await mkdir(gepaDestDir, { recursive: true });
|
|
23
|
+
if (existsSync(gepaSrcDir)) {
|
|
24
|
+
for (const entry of await readdir(gepaSrcDir)) {
|
|
25
|
+
if (entry.endsWith(".txt")) {
|
|
26
|
+
await cp(join(gepaSrcDir, entry), join(gepaDestDir, entry));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# pi-para — Interactive Setup (Windows)
|
|
2
|
+
# Usage:
|
|
3
|
+
# irm https://raw.githubusercontent.com/picassio/pi-para/main/scripts/install.ps1 | iex
|
|
4
|
+
|
|
5
|
+
Write-Host ""
|
|
6
|
+
Write-Host " 🗂️ pi-para — Setup" -ForegroundColor Cyan
|
|
7
|
+
Write-Host " ──────────────────"
|
|
8
|
+
Write-Host ""
|
|
9
|
+
|
|
10
|
+
$package = "pi-para"
|
|
11
|
+
$packageLatest = "$package@latest"
|
|
12
|
+
# qmd-engine (embedded search SDK) requires Node >= 22.
|
|
13
|
+
$minMajor = 22
|
|
14
|
+
|
|
15
|
+
$nodeVer = (node -v 2>$null) -replace '^v',''
|
|
16
|
+
if (-not $nodeVer) {
|
|
17
|
+
Write-Host " ✗ Node.js not found on PATH." -ForegroundColor Red
|
|
18
|
+
Write-Host " Install Node.js (>= $minMajor) from https://nodejs.org, then re-run." -ForegroundColor Yellow
|
|
19
|
+
exit 1
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
$parts = $nodeVer.Split('.')
|
|
23
|
+
$major = [int]$parts[0]
|
|
24
|
+
if ($major -lt $minMajor) {
|
|
25
|
+
Write-Host " ✗ Node.js $nodeVer is too old (pi-para requires Node >= $minMajor)" -ForegroundColor Red
|
|
26
|
+
Write-Host " Upgrade Node.js: https://nodejs.org" -ForegroundColor Yellow
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Resolve npx.cmd explicitly. Bare `npx` resolves to npx.ps1, which fails
|
|
31
|
+
# under restricted PowerShell execution policies.
|
|
32
|
+
$npx = $null
|
|
33
|
+
$npxCmd = Get-Command npx.cmd -ErrorAction SilentlyContinue
|
|
34
|
+
if ($npxCmd) {
|
|
35
|
+
$npx = $npxCmd.Source
|
|
36
|
+
} else {
|
|
37
|
+
$nodeCmd = Get-Command node -ErrorAction SilentlyContinue
|
|
38
|
+
if ($nodeCmd) {
|
|
39
|
+
$candidate = Join-Path (Split-Path $nodeCmd.Source) "npx.cmd"
|
|
40
|
+
if (Test-Path $candidate) { $npx = $candidate }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (-not $npx) {
|
|
44
|
+
Write-Host " ✗ npx.cmd not found." -ForegroundColor Red
|
|
45
|
+
Write-Host " Install Node.js (>= $minMajor) from https://nodejs.org, then re-run." -ForegroundColor Yellow
|
|
46
|
+
exit 1
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Write-Host " → Using $npx (Node $nodeVer)" -ForegroundColor Gray
|
|
50
|
+
Write-Host ""
|
|
51
|
+
|
|
52
|
+
# Always pin @latest so npx does a registry lookup instead of reusing an older
|
|
53
|
+
# cached package.
|
|
54
|
+
& $npx -y $packageLatest setup @args
|
|
55
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# pi-para — Interactive Setup
|
|
5
|
+
# Usage:
|
|
6
|
+
# curl -fsSL https://raw.githubusercontent.com/picassio/pi-para/main/scripts/install.sh | bash
|
|
7
|
+
|
|
8
|
+
PACKAGE="pi-para"
|
|
9
|
+
# qmd-engine (embedded search SDK) requires Node >= 22.
|
|
10
|
+
MIN_NODE_MAJOR=22
|
|
11
|
+
MIN_NODE_MINOR=0
|
|
12
|
+
|
|
13
|
+
check_node_version() {
|
|
14
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
15
|
+
return 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
local version major minor
|
|
19
|
+
version=$(node -v 2>/dev/null | sed 's/^v//')
|
|
20
|
+
major=$(echo "$version" | cut -d. -f1)
|
|
21
|
+
minor=$(echo "$version" | cut -d. -f2)
|
|
22
|
+
|
|
23
|
+
if [ "${major:-0}" -lt "$MIN_NODE_MAJOR" ]; then
|
|
24
|
+
return 1
|
|
25
|
+
fi
|
|
26
|
+
if [ "$major" -eq "$MIN_NODE_MAJOR" ] && [ "${minor:-0}" -lt "$MIN_NODE_MINOR" ]; then
|
|
27
|
+
return 1
|
|
28
|
+
fi
|
|
29
|
+
return 0
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
main() {
|
|
33
|
+
echo ""
|
|
34
|
+
echo " 🗂️ pi-para — Setup"
|
|
35
|
+
echo " ──────────────────"
|
|
36
|
+
echo ""
|
|
37
|
+
|
|
38
|
+
if check_node_version && command -v npx >/dev/null 2>&1; then
|
|
39
|
+
local node_version
|
|
40
|
+
node_version=$(node -v 2>/dev/null | sed 's/^v//')
|
|
41
|
+
echo " → Using npx (Node $node_version)"
|
|
42
|
+
echo ""
|
|
43
|
+
|
|
44
|
+
# Always pin @latest so npx does a registry lookup instead of reusing an
|
|
45
|
+
# older cached package. Redirect stdin from /dev/tty when available so
|
|
46
|
+
# interactive prompts still work under curl | bash.
|
|
47
|
+
if [ -r /dev/tty ]; then
|
|
48
|
+
npx -y "$PACKAGE@latest" setup "$@" </dev/tty
|
|
49
|
+
else
|
|
50
|
+
npx -y "$PACKAGE@latest" setup "$@"
|
|
51
|
+
fi
|
|
52
|
+
else
|
|
53
|
+
echo " ✗ Node $MIN_NODE_MAJOR.$MIN_NODE_MINOR+ with npx is required."
|
|
54
|
+
echo ""
|
|
55
|
+
echo " Install Node from https://nodejs.org, then run:"
|
|
56
|
+
echo ""
|
|
57
|
+
echo " npx $PACKAGE@latest setup"
|
|
58
|
+
echo ""
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
main "$@"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* v8 ignore start */
|
|
3
|
+
import { mkdtemp, rm, access } from "node:fs/promises";
|
|
4
|
+
import { constants } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join, resolve, dirname } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { promisify } from "node:util";
|
|
10
|
+
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
13
|
+
const cli = join(root, "dist", "cli.js");
|
|
14
|
+
|
|
15
|
+
async function main() {
|
|
16
|
+
await access(cli, constants.R_OK).catch(() => {
|
|
17
|
+
throw new Error("dist/cli.js not found. Run npm run build before smoke-install.");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const home = await mkdtemp(join(tmpdir(), "pi-para-smoke-"));
|
|
21
|
+
// os.homedir() reads HOME on POSIX and USERPROFILE on Windows — set both.
|
|
22
|
+
const env = { ...process.env, HOME: home, USERPROFILE: home };
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
await run([cli, "setup", "--yes", "--local", root], env);
|
|
26
|
+
|
|
27
|
+
const status = JSON.parse((await run([cli, "status", "--json"], env)).stdout);
|
|
28
|
+
assert(status.configPath?.startsWith(home), "status configPath should use smoke HOME");
|
|
29
|
+
assert(status.wikiDir?.startsWith(home), "status wikiDir should use smoke HOME");
|
|
30
|
+
assert(typeof status.pages?.total === "number", "status pages.total should be numeric");
|
|
31
|
+
assert(typeof status.scheduler?.queued === "number", "status scheduler.queued should be numeric");
|
|
32
|
+
|
|
33
|
+
const doctor = JSON.parse((await run([cli, "doctor", "--json"], env)).stdout);
|
|
34
|
+
assert(doctor.ok === true, "doctor should pass in smoke HOME");
|
|
35
|
+
|
|
36
|
+
console.log("pi-para smoke install passed");
|
|
37
|
+
console.log(` HOME: ${home}`);
|
|
38
|
+
console.log(` Config: ${status.configPath}`);
|
|
39
|
+
console.log(` Wiki: ${status.wikiDir}`);
|
|
40
|
+
} finally {
|
|
41
|
+
if (!process.env.PI_PARA_KEEP_SMOKE_HOME) {
|
|
42
|
+
await rm(home, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function run(args, env) {
|
|
48
|
+
const [file, ...rest] = args;
|
|
49
|
+
return execFileAsync(process.execPath, [file, ...rest], {
|
|
50
|
+
cwd: root,
|
|
51
|
+
env,
|
|
52
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function assert(condition, message) {
|
|
57
|
+
if (!condition) throw new Error(message);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main().catch((err) => {
|
|
61
|
+
console.error(err instanceof Error ? err.message : err);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
package/skills/para/SKILL.md
CHANGED
|
@@ -45,7 +45,7 @@ Write to the wiki immediately when you:
|
|
|
45
45
|
- Learn how a system actually works (vs. how you assumed)
|
|
46
46
|
- Establish a convention or pattern others should follow
|
|
47
47
|
|
|
48
|
-
Use `
|
|
48
|
+
Use `wiki_edit` for surgical updates to existing pages. Use `wiki_write(mode: 'append')` to add new sections and `wiki_write(mode: 'replace')` only for intentional full-page rewrites. Don't defer — context and reasoning degrade with time.
|
|
49
49
|
|
|
50
50
|
## 4. When Debugging — Search First
|
|
51
51
|
|
package/skills/setup/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup
|
|
3
|
-
description: Set up pi-para PARA knowledge base extension.
|
|
3
|
+
description: Set up pi-para PARA knowledge base extension. Configures no-daemon scheduler runtime, embedded QMD SDK, provider profiles, and diagnostics. Use when user asks to install, set up, or configure pi-para wiki.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# pi-para Setup
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { closeSync, fsyncSync, openSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
|
|
6
|
+
export async function atomicWriteFile(path: string, content: string, mode?: number): Promise<void> {
|
|
7
|
+
await mkdir(dirname(path), { recursive: true });
|
|
8
|
+
const tempPath = join(dirname(path), `.${randomUUID()}.tmp`);
|
|
9
|
+
const fd = openSync(tempPath, "w", mode);
|
|
10
|
+
try {
|
|
11
|
+
writeFileSync(fd, content, "utf-8");
|
|
12
|
+
fsyncSync(fd);
|
|
13
|
+
} finally {
|
|
14
|
+
closeSync(fd);
|
|
15
|
+
}
|
|
16
|
+
renameSync(tempPath, path);
|
|
17
|
+
}
|
package/src/capture.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* Both are fully automatic — no user confirmation prompts.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { Model } from "@
|
|
12
|
-
import { Agent } from "@
|
|
13
|
-
import type { AgentMessage, AgentEvent } from "@
|
|
14
|
-
import type { ModelRegistry } from "@
|
|
11
|
+
import type { Model } from "@earendil-works/pi-ai";
|
|
12
|
+
import { Agent } from "@earendil-works/pi-agent-core";
|
|
13
|
+
import type { AgentMessage, AgentEvent } from "@earendil-works/pi-agent-core";
|
|
14
|
+
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
15
15
|
import type { QMDStore } from "qmd-engine";
|
|
16
16
|
|
|
17
17
|
import type { ProjectScope } from "./scope.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const LEGACY_DAEMON_COMMANDS = new Set([
|
|
2
|
+
"start",
|
|
3
|
+
"stop",
|
|
4
|
+
"legacy-status",
|
|
5
|
+
"process",
|
|
6
|
+
"process-recent",
|
|
7
|
+
"retry-failed",
|
|
8
|
+
"history",
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export function isLegacyDaemonCommand(command: string | undefined): boolean {
|
|
12
|
+
return command !== undefined && LEGACY_DAEMON_COMMANDS.has(command);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatLegacyDaemonWarning(command: string): string {
|
|
16
|
+
const replacement = replacementForLegacyCommand(command);
|
|
17
|
+
return [
|
|
18
|
+
`[pi-para] Warning: '${command}' is a deprecated legacy daemon command.`,
|
|
19
|
+
"pi-para now uses an in-process scheduler while Pi is open; no system daemon is required.",
|
|
20
|
+
replacement ? `Use ${replacement} for the current workflow.` : "Use 'pi-para tasks' or '/wiki-scheduler status' for the current workflow.",
|
|
21
|
+
].join("\n");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function replacementForLegacyCommand(command: string): string | null {
|
|
25
|
+
switch (command) {
|
|
26
|
+
case "start":
|
|
27
|
+
return "'pi-para setup' and restart Pi";
|
|
28
|
+
case "stop":
|
|
29
|
+
return "'/wiki-scheduler status' or close/restart Pi sessions";
|
|
30
|
+
case "legacy-status":
|
|
31
|
+
return "'pi-para tasks' or '/wiki-scheduler status'";
|
|
32
|
+
case "process":
|
|
33
|
+
return "'pi-para capture-recent --hours N' or '/wiki-capture'";
|
|
34
|
+
case "process-recent":
|
|
35
|
+
return "'pi-para capture-recent --hours N'";
|
|
36
|
+
case "retry-failed":
|
|
37
|
+
return "'pi-para tasks retry'";
|
|
38
|
+
case "history":
|
|
39
|
+
return "'pi-para tasks history'";
|
|
40
|
+
default:
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* CLI for pi-para
|
|
3
|
+
* CLI for pi-para.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* pi-para-daemon start [--foreground]
|
|
7
|
-
* pi-para-daemon stop
|
|
8
|
-
* pi-para-daemon status
|
|
9
|
-
* pi-para-daemon process <session_file>
|
|
10
|
-
* pi-para-daemon process-recent [--hours N]
|
|
11
|
-
* pi-para-daemon retry-failed
|
|
12
|
-
* pi-para-daemon history [--scope NAME]
|
|
5
|
+
* The old pi-para-daemon commands remain as deprecated compatibility aliases.
|
|
13
6
|
*/
|
|
14
7
|
|
|
15
8
|
import { join } from "node:path";
|
|
@@ -19,6 +12,7 @@ import { existsSync, readdirSync, statSync } from "node:fs";
|
|
|
19
12
|
import { Daemon } from "./daemon.js";
|
|
20
13
|
import { StateDB } from "./state.js";
|
|
21
14
|
import { RegistryWatcher } from "./watcher.js";
|
|
15
|
+
import { formatLegacyDaemonWarning, isLegacyDaemonCommand } from "./cli-legacy.js";
|
|
22
16
|
|
|
23
17
|
// -- Model setup -------------------------------------------------------------
|
|
24
18
|
// Use MiniMax via the same config as qmd-engine
|
|
@@ -26,7 +20,7 @@ import { RegistryWatcher } from "./watcher.js";
|
|
|
26
20
|
async function createModel(modelArg?: string) {
|
|
27
21
|
const { parse } = await import("yaml");
|
|
28
22
|
const { readFileSync } = await import("node:fs");
|
|
29
|
-
const { getModel, getProviders, getEnvApiKey } = await import("@
|
|
23
|
+
const { getModel, getProviders, getEnvApiKey } = await import("@earendil-works/pi-ai/compat");
|
|
30
24
|
|
|
31
25
|
// 0. Try config.json daemonModel
|
|
32
26
|
if (!modelArg) {
|
|
@@ -53,7 +47,7 @@ async function createModel(modelArg?: string) {
|
|
|
53
47
|
// Resolve API key: try AuthStorage first (OAuth), then env vars
|
|
54
48
|
let authStore: any = null;
|
|
55
49
|
try {
|
|
56
|
-
const { AuthStorage } = await import("@
|
|
50
|
+
const { AuthStorage } = await import("@earendil-works/pi-coding-agent");
|
|
57
51
|
authStore = AuthStorage.create();
|
|
58
52
|
} catch {}
|
|
59
53
|
const getApiKey = async (p: string) => {
|
|
@@ -71,9 +65,9 @@ async function createModel(modelArg?: string) {
|
|
|
71
65
|
|
|
72
66
|
// 2. Try pi's auth storage (auth.json) — supports OAuth (Anthropic, GitHub Copilot, etc.)
|
|
73
67
|
try {
|
|
74
|
-
const { AuthStorage } = await import("@
|
|
68
|
+
const { AuthStorage } = await import("@earendil-works/pi-coding-agent");
|
|
75
69
|
const authStorage = AuthStorage.create();
|
|
76
|
-
const { getModels } = await import("@
|
|
70
|
+
const { getModels } = await import("@earendil-works/pi-ai/compat");
|
|
77
71
|
|
|
78
72
|
// Check providers in preference order: anthropic first (best quality)
|
|
79
73
|
const preferredProviders = ["anthropic", "openai", "openrouter", "google-antigravity", "github-copilot"];
|
|
@@ -103,7 +97,7 @@ async function createModel(modelArg?: string) {
|
|
|
103
97
|
for (const provider of providers) {
|
|
104
98
|
const key = getEnvApiKey(provider);
|
|
105
99
|
if (key) {
|
|
106
|
-
const { getModels } = await import("@
|
|
100
|
+
const { getModels } = await import("@earendil-works/pi-ai/compat");
|
|
107
101
|
const models = getModels(provider as any);
|
|
108
102
|
const sorted = [...models].sort((a, b) => (b.contextWindow ?? 0) - (a.contextWindow ?? 0));
|
|
109
103
|
const picked = sorted.find(m => !m.reasoning) ?? sorted[0];
|
|
@@ -150,7 +144,102 @@ async function main() {
|
|
|
150
144
|
const command = args[0];
|
|
151
145
|
const wikiDir = join(homedir(), ".pi", "wiki");
|
|
152
146
|
|
|
147
|
+
if (isLegacyDaemonCommand(command)) {
|
|
148
|
+
console.warn(formatLegacyDaemonWarning(command));
|
|
149
|
+
console.warn("");
|
|
150
|
+
}
|
|
151
|
+
|
|
153
152
|
switch (command) {
|
|
153
|
+
case "setup": {
|
|
154
|
+
const dryRun = args.includes("--dry-run");
|
|
155
|
+
const localIdx = args.indexOf("--local");
|
|
156
|
+
const localPath = localIdx >= 0 ? args[localIdx + 1] : undefined;
|
|
157
|
+
const { runSetup, formatSetupResult } = await import("./setup.js");
|
|
158
|
+
const result = await runSetup({ yes: args.includes("--yes"), dryRun, localPath });
|
|
159
|
+
console.log(formatSetupResult(result));
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case "doctor": {
|
|
164
|
+
const json = args.includes("--json");
|
|
165
|
+
const { runDoctor, formatDoctorResult } = await import("./doctor.js");
|
|
166
|
+
const result = await runDoctor({
|
|
167
|
+
fix: args.includes("--fix"),
|
|
168
|
+
testCaptureModel: args.includes("--test-capture-model"),
|
|
169
|
+
});
|
|
170
|
+
console.log(json ? JSON.stringify(result, null, 2) : formatDoctorResult(result));
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
case "tasks": {
|
|
175
|
+
const sub = args[1] ?? "list";
|
|
176
|
+
const {
|
|
177
|
+
listSchedulerTasks,
|
|
178
|
+
retryFailedSchedulerTasks,
|
|
179
|
+
getSchedulerTask,
|
|
180
|
+
listSchedulerHistory,
|
|
181
|
+
formatQueueItems,
|
|
182
|
+
formatQueueItem,
|
|
183
|
+
formatSchedulerHistory,
|
|
184
|
+
} = await import("./scheduler/controls.js");
|
|
185
|
+
if (sub === "retry") {
|
|
186
|
+
const taskIdx = args.indexOf("--task");
|
|
187
|
+
const taskName = taskIdx >= 0 ? args[taskIdx + 1] : undefined;
|
|
188
|
+
const count = retryFailedSchedulerTasks(wikiDir, { taskName });
|
|
189
|
+
console.log(`Requeued ${count} failed task${count === 1 ? "" : "s"}.`);
|
|
190
|
+
} else if (sub === "show") {
|
|
191
|
+
const id = parseInt(args[2] ?? "", 10);
|
|
192
|
+
if (!Number.isFinite(id)) { console.error("Usage: pi-para tasks show <id>"); process.exit(1); }
|
|
193
|
+
console.log(formatQueueItem(getSchedulerTask(wikiDir, id)));
|
|
194
|
+
} else if (sub === "history") {
|
|
195
|
+
const taskIdx = args.indexOf("--task");
|
|
196
|
+
const limitIdx = args.indexOf("--limit");
|
|
197
|
+
const taskName = taskIdx >= 0 ? args[taskIdx + 1] : undefined;
|
|
198
|
+
const limit = limitIdx >= 0 ? parseInt(args[limitIdx + 1] ?? "20", 10) : 20;
|
|
199
|
+
console.log(formatSchedulerHistory(listSchedulerHistory(wikiDir, { taskName, limit })));
|
|
200
|
+
} else {
|
|
201
|
+
const statusIdx = args.indexOf("--status");
|
|
202
|
+
const status = statusIdx >= 0 ? args[statusIdx + 1] as any : undefined;
|
|
203
|
+
console.log(formatQueueItems(listSchedulerTasks(wikiDir, { status })));
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
case "capture-recent": {
|
|
209
|
+
const hoursIdx = args.indexOf("--hours");
|
|
210
|
+
const hours = hoursIdx >= 0 ? parseInt(args[hoursIdx + 1] ?? "24") : 24;
|
|
211
|
+
const { queueCaptureRecent, formatQueueCaptureRecentResult } = await import("./scheduler/controls.js");
|
|
212
|
+
const result = await queueCaptureRecent({ wikiDir, hours });
|
|
213
|
+
console.log(formatQueueCaptureRecentResult(result));
|
|
214
|
+
console.log("Queued captures run when a Pi session with pi-para is open.");
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
case "providers": {
|
|
219
|
+
const sub = args[1] ?? "list";
|
|
220
|
+
const { readSecretStore, setSecret, removeSecret, redactCredential } = await import("./credentials.js");
|
|
221
|
+
if (sub === "set-secret") {
|
|
222
|
+
const name = args[2];
|
|
223
|
+
const value = args[3];
|
|
224
|
+
if (!name || !value) { console.error("Usage: pi-para providers set-secret <name> <value>"); process.exit(1); }
|
|
225
|
+
await setSecret(name, value);
|
|
226
|
+
console.log(`Stored secret:${name}`);
|
|
227
|
+
} else if (sub === "remove-secret") {
|
|
228
|
+
const name = args[2];
|
|
229
|
+
if (!name) { console.error("Usage: pi-para providers remove-secret <name>"); process.exit(1); }
|
|
230
|
+
await removeSecret(name);
|
|
231
|
+
console.log(`Removed secret:${name}`);
|
|
232
|
+
} else {
|
|
233
|
+
const secrets = await readSecretStore();
|
|
234
|
+
const names = Object.keys(secrets.secrets);
|
|
235
|
+
console.log("pi-para providers");
|
|
236
|
+
console.log(" Credential policy: Pi AuthStorage preferred; pi-para secrets fallback; env vars not used by setup.");
|
|
237
|
+
if (names.length === 0) console.log(" No pi-para local secrets configured.");
|
|
238
|
+
for (const name of names) console.log(` secret:${name} = ${redactCredential(secrets.secrets[name])}`);
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
|
|
154
243
|
case "start": {
|
|
155
244
|
const modelIdx = args.indexOf("--model");
|
|
156
245
|
const modelArg = modelIdx >= 0 ? args[modelIdx + 1] : undefined;
|
|
@@ -210,6 +299,14 @@ async function main() {
|
|
|
210
299
|
}
|
|
211
300
|
|
|
212
301
|
case "status": {
|
|
302
|
+
const json = args.includes("--json");
|
|
303
|
+
const { getPiParaStatus, formatPiParaStatus } = await import("./status.js");
|
|
304
|
+
const result = await getPiParaStatus();
|
|
305
|
+
console.log(json ? JSON.stringify(result, null, 2) : formatPiParaStatus(result));
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
case "legacy-status": {
|
|
213
310
|
const state = new StateDB(wikiDir);
|
|
214
311
|
const pid = state.getState("daemon_pid");
|
|
215
312
|
const startedAt = state.getState("daemon_started_at");
|
|
@@ -358,7 +455,7 @@ async function main() {
|
|
|
358
455
|
break;
|
|
359
456
|
}
|
|
360
457
|
default:
|
|
361
|
-
console.log(`pi-para
|
|
458
|
+
console.log(`pi-para gepa — GEPA prompt optimizer (DSPy GEPA via uv)
|
|
362
459
|
|
|
363
460
|
Subcommands:
|
|
364
461
|
optimize Run DSPy GEPA optimization
|
|
@@ -387,25 +484,33 @@ Config (persistent defaults in ~/.pi/wiki/config.json):
|
|
|
387
484
|
}
|
|
388
485
|
|
|
389
486
|
default:
|
|
390
|
-
console.log(`pi-para
|
|
487
|
+
console.log(`pi-para — PARA wiki extension CLI
|
|
488
|
+
|
|
489
|
+
Primary commands:
|
|
490
|
+
setup Configure pi-para for this machine (--yes, --dry-run, --local PATH)
|
|
491
|
+
doctor Validate install/config/wiki/QMD health (--fix, --json, --test-capture-model)
|
|
492
|
+
tasks Show scheduler queue (--status queued|running|done|failed)
|
|
493
|
+
tasks show <id> Show one queued/running/done/failed task payload
|
|
494
|
+
tasks history Show scheduler history [--task NAME] [--limit N]
|
|
495
|
+
tasks retry Requeue failed scheduler tasks [--task NAME]
|
|
496
|
+
status Show config/wiki/scheduler status (--json)
|
|
497
|
+
capture-recent Queue recent completed sessions for capture (--hours N)
|
|
498
|
+
providers List credential refs and local secrets
|
|
499
|
+
providers set-secret <name> <value>
|
|
500
|
+
providers remove-secret <name>
|
|
501
|
+
gepa <subcommand> GEPA prompt optimizer (optimize, list, targets, compare)
|
|
391
502
|
|
|
392
|
-
|
|
393
|
-
start
|
|
394
|
-
stop
|
|
395
|
-
status
|
|
503
|
+
Legacy compatibility commands:
|
|
504
|
+
start Deprecated daemon foreground mode
|
|
505
|
+
stop Deprecated daemon stop
|
|
506
|
+
legacy-status Legacy daemon status and recent history
|
|
396
507
|
process <file> Process a single session file
|
|
397
508
|
process-recent Process unprocessed sessions (--hours N, default 24)
|
|
398
509
|
retry-failed Retry all failed sessions
|
|
399
510
|
history Show processing history (--scope NAME to filter)
|
|
400
|
-
gepa <subcommand> GEPA prompt optimizer (optimize, list, targets, compare)
|
|
401
|
-
|
|
402
|
-
Options:
|
|
403
|
-
--model <provider/id> Use specific model (e.g. anthropic/claude-sonnet-4)
|
|
404
511
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
2. Pi's model registry (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.)
|
|
408
|
-
3. ~/.config/qmd/index.yml chat provider (MiniMax, OpenRouter, etc.)`);
|
|
512
|
+
Credential policy:
|
|
513
|
+
Use Pi AuthStorage or ~/.pi/para/secrets.json. Setup does not use env vars for API keys.`);
|
|
409
514
|
break;
|
|
410
515
|
}
|
|
411
516
|
}
|