pi-feats 0.1.5 → 0.1.7
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/README.md +48 -5
- package/extensions/api-server/README.md +21 -1
- package/extensions/api-server/application-runtime.ts +65 -4
- package/extensions/api-server/application-store.ts +5 -5
- package/extensions/api-server/index.ts +6 -2
- package/extensions/api-server/profile-store.ts +81 -34
- package/extensions/api-server/server.ts +179 -42
- package/extensions/cli-resources.ts +125 -94
- package/extensions/cli-tui-mode.ts +7 -0
- package/extensions/context-memory/index.ts +6 -1
- package/extensions/guardrails/index.ts +2 -1
- package/extensions/lib/application-context.ts +2 -0
- package/extensions/lib/cli-tui-mode.ts +72 -0
- package/extensions/lib/context-memory.ts +6 -1
- package/extensions/lib/package-resources.ts +58 -0
- package/extensions/lib/pi-command.ts +11 -0
- package/extensions/lib/profile-sandbox.ts +11 -3
- package/extensions/lib/remote-hosts.ts +7 -5
- package/extensions/lib/workflow-evaluator.ts +113 -0
- package/extensions/lib/workflow-harness.ts +409 -43
- package/extensions/pi-console-webui/app/[section]/page.tsx +1 -1
- package/extensions/pi-console-webui/app/globals.css +3 -0
- package/extensions/pi-console-webui/components/application-handler-editor.tsx +1 -1
- package/extensions/pi-console-webui/components/application-sessions.tsx +2 -2
- package/extensions/pi-console-webui/components/application-settings.tsx +12 -6
- package/extensions/pi-console-webui/components/chat-workspace.tsx +17 -7
- package/extensions/pi-console-webui/components/console-page.tsx +1 -0
- package/extensions/pi-console-webui/components/console-state.tsx +1 -1
- package/extensions/pi-console-webui/components/console.tsx +26 -9
- package/extensions/pi-console-webui/components/guardrails-panel.tsx +2 -2
- package/extensions/pi-console-webui/components/profile-model-form.tsx +2 -2
- package/extensions/pi-console-webui/components/pulse-resources.tsx +4 -3
- package/extensions/pi-console-webui/components/sequential-workflow-config.tsx +32 -0
- package/extensions/pi-console-webui/components/skill-resources.tsx +4 -3
- package/extensions/pi-console-webui/components/ui/input.tsx +1 -1
- package/extensions/pi-console-webui/index.ts +2 -1
- package/extensions/pi-console-webui/lib/admin-models.ts +6 -4
- package/extensions/pi-console-webui/lib/page-metadata.ts +1 -0
- package/extensions/profile-ssh.ts +2 -2
- package/extensions/profiles.ts +17 -9
- package/extensions/pulse/index.ts +35 -17
- package/extensions/pulse/store.ts +29 -7
- package/extensions/sequential-workflow.ts +121 -79
- package/extensions/skill-sources/store.ts +29 -10
- package/package.json +19 -9
- package/scripts/build-console-webui.mjs +7 -0
- package/scripts/console-webui-cache.mjs +79 -0
- package/scripts/ensure-console-build.mjs +43 -0
- package/skills/sequential-workflow/SKILL.md +4 -3
- package/themes/legacy-dark.json +85 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-feats",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A modular Pi package for profiles, sandboxing, remote access, applications, guardrails, skills, session management, observability, and web-based operations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"scripts",
|
|
30
30
|
"schemas",
|
|
31
31
|
"skills",
|
|
32
|
+
"themes",
|
|
32
33
|
"README.md",
|
|
33
34
|
"LICENSE",
|
|
34
35
|
"THIRD_PARTY_NOTICES.md",
|
|
@@ -40,18 +41,18 @@
|
|
|
40
41
|
"node": ">=22"
|
|
41
42
|
},
|
|
42
43
|
"scripts": {
|
|
43
|
-
"build:web": "
|
|
44
|
+
"build:web": "node scripts/build-console-webui.mjs",
|
|
45
|
+
"build:web:next": "cd extensions/pi-console-webui && npx --no-install next build",
|
|
44
46
|
"ensure:nono": "sh scripts/install-nono.sh",
|
|
45
|
-
"postinstall": "npm run ensure:nono &&
|
|
46
|
-
"test": "npm run test:
|
|
47
|
-
"test:
|
|
47
|
+
"postinstall": "npm run ensure:nono && node scripts/ensure-console-build.mjs",
|
|
48
|
+
"test": "npm run test:extensions && npm run build:web",
|
|
49
|
+
"test:extensions": "node --experimental-strip-types --test tests/*.test.ts"
|
|
48
50
|
},
|
|
49
51
|
"dependencies": {
|
|
50
52
|
"@codemirror/lang-javascript": "^6.2.5",
|
|
51
53
|
"@codemirror/lang-json": "^6.0.2",
|
|
52
54
|
"@codemirror/lang-markdown": "^6.5.2",
|
|
53
55
|
"@composio/core": "^0.18.1",
|
|
54
|
-
"@earendil-works/pi-ai": "^0.85.1",
|
|
55
56
|
"@fastify/websocket": "^11.3.0",
|
|
56
57
|
"@homebridge/node-pty-prebuilt-multiarch": "^0.14.1",
|
|
57
58
|
"@radix-ui/react-slot": "^1.2.4",
|
|
@@ -79,14 +80,17 @@
|
|
|
79
80
|
"remark-gfm": "^4.0.1",
|
|
80
81
|
"tailwind-merge": "^3.0.2",
|
|
81
82
|
"tailwindcss": "^3.4.17",
|
|
82
|
-
"typebox": "^1.3.30",
|
|
83
83
|
"typescript": "^5.7.2"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
|
-
"@earendil-works/pi-
|
|
86
|
+
"@earendil-works/pi-ai": "*",
|
|
87
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
88
|
+
"@earendil-works/pi-tui": "*",
|
|
89
|
+
"typebox": "*"
|
|
87
90
|
},
|
|
88
91
|
"pi": {
|
|
89
92
|
"extensions": [
|
|
93
|
+
"./extensions/cli-tui-mode.ts",
|
|
90
94
|
"./extensions/api-server",
|
|
91
95
|
"./extensions/browser-harness",
|
|
92
96
|
"./extensions/cli-resources.ts",
|
|
@@ -104,9 +108,15 @@
|
|
|
104
108
|
"skills": [
|
|
105
109
|
"./skills"
|
|
106
110
|
],
|
|
111
|
+
"themes": [
|
|
112
|
+
"./themes/*.json"
|
|
113
|
+
],
|
|
107
114
|
"image": "https://raw.githubusercontent.com/rjaskonis/pi-feats/v0.1.4/assets/pi-feats-preview.png"
|
|
108
115
|
},
|
|
109
116
|
"devDependencies": {
|
|
110
|
-
"@
|
|
117
|
+
"@earendil-works/pi-ai": "^0.85.1",
|
|
118
|
+
"@earendil-works/pi-tui": "^0.85.1",
|
|
119
|
+
"@types/ws": "^8.18.1",
|
|
120
|
+
"typebox": "^1.3.30"
|
|
111
121
|
}
|
|
112
122
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { packageRoot, saveBuildCache } from "./console-webui-cache.mjs";
|
|
3
|
+
|
|
4
|
+
const result = spawnSync(process.platform === "win32" ? "npm.cmd" : "npm", ["run", "build:web:next"], { cwd: packageRoot, stdio: "inherit" });
|
|
5
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
6
|
+
await saveBuildCache();
|
|
7
|
+
console.log("Cached Pi Console WebUI build for future updates.");
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { cp, mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
|
+
import { dirname, join, relative } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
export const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
|
+
export const webuiRoot = join(packageRoot, "extensions", "pi-console-webui");
|
|
11
|
+
const agentRoot = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
|
|
12
|
+
export const cacheRoot = process.env.PI_FEATS_WEB_BUILD_CACHE_DIR ?? join(agentRoot, "cache", "pi-feats", "console-webui");
|
|
13
|
+
const cacheBuild = join(cacheRoot, "next-build");
|
|
14
|
+
const metadataPath = join(cacheRoot, "metadata.json");
|
|
15
|
+
const targetBuild = join(webuiRoot, ".next");
|
|
16
|
+
|
|
17
|
+
async function sourceHash(path) {
|
|
18
|
+
const hash = createHash("sha256");
|
|
19
|
+
const visit = async (directory) => {
|
|
20
|
+
for (const entry of (await readdir(directory, { withFileTypes: true })).sort((left, right) => left.name.localeCompare(right.name))) {
|
|
21
|
+
if ([".next", "node_modules"].includes(entry.name)) continue;
|
|
22
|
+
const fullPath = join(directory, entry.name);
|
|
23
|
+
if (entry.isDirectory()) await visit(fullPath);
|
|
24
|
+
else if (entry.isFile()) {
|
|
25
|
+
hash.update(relative(webuiRoot, fullPath));
|
|
26
|
+
hash.update(await readFile(fullPath));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
await visit(path);
|
|
31
|
+
return hash.digest("hex");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const gitCommit = () => {
|
|
35
|
+
try { return execFileSync("git", ["rev-parse", "HEAD"], { cwd: packageRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim(); }
|
|
36
|
+
catch { return undefined; }
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export async function buildMetadata() {
|
|
40
|
+
const next = JSON.parse(await readFile(join(packageRoot, "node_modules", "next", "package.json"), "utf8"));
|
|
41
|
+
return { sourceHash: await sourceHash(webuiRoot), nodeVersion: process.version, nextVersion: next.version, commit: gitCommit(), builtAt: new Date().toISOString() };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function loadCache() {
|
|
45
|
+
try { return JSON.parse(await readFile(metadataPath, "utf8")); }
|
|
46
|
+
catch { return undefined; }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function cacheStatus() {
|
|
50
|
+
const metadata = await buildMetadata();
|
|
51
|
+
const cached = await loadCache();
|
|
52
|
+
if (!cached || !existsSync(join(cacheBuild, "BUILD_ID"))) return { state: "missing", metadata };
|
|
53
|
+
if (cached.nodeVersion !== metadata.nodeVersion || cached.nextVersion !== metadata.nextVersion) return { state: "incompatible", metadata, cached };
|
|
54
|
+
if (cached.sourceHash !== metadata.sourceHash) return { state: "changed", metadata, cached };
|
|
55
|
+
return { state: "compatible", metadata, cached };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function restoreCachedBuild() {
|
|
59
|
+
if (!existsSync(join(cacheBuild, "BUILD_ID"))) return false;
|
|
60
|
+
await rm(targetBuild, { recursive: true, force: true });
|
|
61
|
+
await cp(cacheBuild, targetBuild, { recursive: true });
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function saveBuildCache(metadata) {
|
|
66
|
+
if (!metadata) metadata = await buildMetadata();
|
|
67
|
+
if (!existsSync(join(targetBuild, "BUILD_ID"))) throw new Error("Next.js completed without producing .next/BUILD_ID.");
|
|
68
|
+
const staging = join(cacheRoot, `next-build-${process.pid}-${Date.now()}`);
|
|
69
|
+
await mkdir(cacheRoot, { recursive: true });
|
|
70
|
+
await rm(staging, { recursive: true, force: true });
|
|
71
|
+
await cp(targetBuild, staging, { recursive: true });
|
|
72
|
+
await rm(cacheBuild, { recursive: true, force: true });
|
|
73
|
+
await rename(staging, cacheBuild);
|
|
74
|
+
await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\n`, "utf8");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function clearBuildCache() {
|
|
78
|
+
await rm(cacheRoot, { recursive: true, force: true });
|
|
79
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { clearBuildCache, cacheStatus, packageRoot, restoreCachedBuild } from "./console-webui-cache.mjs";
|
|
4
|
+
|
|
5
|
+
const mode = process.env.PI_FEATS_BUILD_WEB;
|
|
6
|
+
if (process.env.PI_FEATS_CLEAR_WEB_CACHE === "1") {
|
|
7
|
+
await clearBuildCache();
|
|
8
|
+
console.log("Cleared the cached Pi Console WebUI build.");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const build = () => {
|
|
12
|
+
const result = spawnSync(process.platform === "win32" ? "npm.cmd" : "npm", ["run", "build:web"], { cwd: packageRoot, stdio: "inherit" });
|
|
13
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const prompt = async (message) => {
|
|
17
|
+
const readline = createInterface({ input: process.stdin, output: process.stdout });
|
|
18
|
+
const answer = (await readline.question(message)).trim().toLowerCase();
|
|
19
|
+
readline.close();
|
|
20
|
+
return answer === "" || answer === "y" || answer === "yes";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (mode === "1") {
|
|
24
|
+
console.log("Rebuilding Pi Console WebUI (PI_FEATS_BUILD_WEB=1).");
|
|
25
|
+
build();
|
|
26
|
+
} else if (mode === "0") {
|
|
27
|
+
console.log("Skipping Pi Console WebUI rebuild (PI_FEATS_BUILD_WEB=0).");
|
|
28
|
+
} else {
|
|
29
|
+
const status = await cacheStatus();
|
|
30
|
+
if (status.state === "compatible" && await restoreCachedBuild()) {
|
|
31
|
+
console.log("Restored cached Pi Console WebUI build; no frontend changes were detected.");
|
|
32
|
+
} else {
|
|
33
|
+
const message = status.state === "changed"
|
|
34
|
+
? "Pi Console WebUI changed in this update.\n\nRebuild now? [Y/n]\n y Rebuild now (recommended)\n n Keep the previous Console build\n> "
|
|
35
|
+
: "No compatible Pi Console WebUI build is available.\n\nBuild now? [Y/n]\n> ";
|
|
36
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY || await prompt(message)) {
|
|
37
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) console.log("Rebuilding Pi Console WebUI in a non-interactive install.");
|
|
38
|
+
build();
|
|
39
|
+
} else {
|
|
40
|
+
console.log("Skipped Pi Console WebUI rebuild. The Console may not match this package version until you run `npm run build:web`.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -62,9 +62,10 @@ Do not inspect, resume, or otherwise select a persisted workflow merely because
|
|
|
62
62
|
|
|
63
63
|
- For an `action`, perform the action and call `sequential_workflow_record_result` with `phase: "action"` and a verifiable result summary.
|
|
64
64
|
- For a `collect`, request the required information from the user. After receiving it, call `sequential_workflow_record_result` with `phase: "collect"` and the received response.
|
|
65
|
-
- For a `workflow` task,
|
|
66
|
-
- If a task has `criteria`, call `sequential_workflow_evaluate`
|
|
65
|
+
- For a `workflow` task, call `sequential_workflow_create_subworkflow` with both `parentWorkflowId` and `parentTaskId` for that current task. The parent task waits automatically; do not record a result for it.
|
|
66
|
+
- If a task has `criteria`, call `sequential_workflow_evaluate` with `outcome: "accept"`, `"retry"`, or `"fail"`. Do not advance before acceptance.
|
|
67
|
+
- Use `retry` only when another execution could change the outcome. After recording evidence, use `fail` when the task cannot safely progress; this ends the workflow without advancing or consuming retry attempts.
|
|
67
68
|
- For an `evaluate`, assess the available information according to the instruction and call `sequential_workflow_evaluate`.
|
|
68
69
|
- If an evaluation rejects an `action`, correct or repeat the current action. If it rejects a `collect`, explain what is missing and request the information again. A rejected `workflow` task becomes runnable again and may create a replacement child.
|
|
69
70
|
|
|
70
|
-
`
|
|
71
|
+
`sequential_workflow_create` creates only root workflows and hydrates a focused `pending_definition`; it has no parent parameters and never creates a child. `sequential_workflow_create_subworkflow` creates the hierarchical relationship and operational dependency for a current `workflow` task. Use `sequential_workflow_status` without an ID to list this session's active workflows or with `workflowId` to inspect an owned execution. Status never changes focus. When the user requests cancellation, call `sequential_workflow_cancel` with the workflow ID. Cancellation is available across sessions in the same profile and does not require adoption. It cancels only that workflow; a cancelled child is surfaced to its parent for evaluation and descendants are not cancelled automatically. `/workflow-cancel <workflowId>` remains available as an explicit user control.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "legacy-dark",
|
|
4
|
+
"vars": {
|
|
5
|
+
"cyan": "#00d7ff",
|
|
6
|
+
"blue": "#5f87ff",
|
|
7
|
+
"green": "#b5bd68",
|
|
8
|
+
"red": "#cc6666",
|
|
9
|
+
"yellow": "#ffff00",
|
|
10
|
+
"text": "#d4d4d4",
|
|
11
|
+
"gray": "#808080",
|
|
12
|
+
"dimGray": "#666666",
|
|
13
|
+
"darkGray": "#505050",
|
|
14
|
+
"accent": "#8abeb7",
|
|
15
|
+
"selectedBg": "#3a3a4a",
|
|
16
|
+
"userMsgBg": "#343541",
|
|
17
|
+
"toolPendingBg": "#282832",
|
|
18
|
+
"toolSuccessBg": "#283228",
|
|
19
|
+
"toolErrorBg": "#3c2828",
|
|
20
|
+
"customMsgBg": "#2d2838"
|
|
21
|
+
},
|
|
22
|
+
"colors": {
|
|
23
|
+
"accent": "accent",
|
|
24
|
+
"border": "blue",
|
|
25
|
+
"borderAccent": "cyan",
|
|
26
|
+
"borderMuted": "darkGray",
|
|
27
|
+
"success": "green",
|
|
28
|
+
"error": "red",
|
|
29
|
+
"warning": "yellow",
|
|
30
|
+
"muted": "gray",
|
|
31
|
+
"dim": "dimGray",
|
|
32
|
+
"text": "text",
|
|
33
|
+
"thinkingText": "gray",
|
|
34
|
+
"selectedBg": "selectedBg",
|
|
35
|
+
"scrollbarTrack": "darkGray",
|
|
36
|
+
"scrollbarThumb": "text",
|
|
37
|
+
"searchMatchBg": "selectedBg",
|
|
38
|
+
"searchMatchText": "text",
|
|
39
|
+
"userMessageBg": "userMsgBg",
|
|
40
|
+
"userMessageText": "text",
|
|
41
|
+
"customMessageBg": "customMsgBg",
|
|
42
|
+
"customMessageText": "text",
|
|
43
|
+
"customMessageLabel": "#9575cd",
|
|
44
|
+
"toolPendingBg": "toolPendingBg",
|
|
45
|
+
"toolSuccessBg": "toolSuccessBg",
|
|
46
|
+
"toolErrorBg": "toolErrorBg",
|
|
47
|
+
"toolTitle": "text",
|
|
48
|
+
"toolOutput": "gray",
|
|
49
|
+
"mdHeading": "#f0c674",
|
|
50
|
+
"mdLink": "#81a2be",
|
|
51
|
+
"mdLinkUrl": "dimGray",
|
|
52
|
+
"mdCode": "accent",
|
|
53
|
+
"mdCodeBlock": "green",
|
|
54
|
+
"mdCodeBlockBorder": "gray",
|
|
55
|
+
"mdQuote": "gray",
|
|
56
|
+
"mdQuoteBorder": "gray",
|
|
57
|
+
"mdHr": "gray",
|
|
58
|
+
"mdListBullet": "accent",
|
|
59
|
+
"toolDiffAdded": "green",
|
|
60
|
+
"toolDiffRemoved": "red",
|
|
61
|
+
"toolDiffContext": "gray",
|
|
62
|
+
"syntaxComment": "#6A9955",
|
|
63
|
+
"syntaxKeyword": "#569CD6",
|
|
64
|
+
"syntaxFunction": "#DCDCAA",
|
|
65
|
+
"syntaxVariable": "#9CDCFE",
|
|
66
|
+
"syntaxString": "#CE9178",
|
|
67
|
+
"syntaxNumber": "#B5CEA8",
|
|
68
|
+
"syntaxType": "#4EC9B0",
|
|
69
|
+
"syntaxOperator": "#D4D4D4",
|
|
70
|
+
"syntaxPunctuation": "#D4D4D4",
|
|
71
|
+
"thinkingOff": "darkGray",
|
|
72
|
+
"thinkingMinimal": "#6e6e6e",
|
|
73
|
+
"thinkingLow": "#5f87af",
|
|
74
|
+
"thinkingMedium": "#81a2be",
|
|
75
|
+
"thinkingHigh": "#b294bb",
|
|
76
|
+
"thinkingXhigh": "#d183e8",
|
|
77
|
+
"thinkingMax": "#ff5fff",
|
|
78
|
+
"bashMode": "green"
|
|
79
|
+
},
|
|
80
|
+
"export": {
|
|
81
|
+
"pageBg": "#18181e",
|
|
82
|
+
"cardBg": "#1e1e24",
|
|
83
|
+
"infoBg": "#3c3728"
|
|
84
|
+
}
|
|
85
|
+
}
|