@yunazgr/pi-companion 0.3.0 → 0.3.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.
- package/README.md +5 -3
- package/docs/automations.md +38 -1
- package/package.json +1 -1
- package/skills/companion-automations/SKILL.md +2 -0
- package/src/automation-mcp.ts +1 -1
- package/src/automation.ts +9 -3
- package/src/bridge.ts +5 -1
- package/src/protocol.ts +1 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight, local-first remote control for Pi sessions.
|
|
4
4
|
|
|
5
|
-
**New in 0.3.
|
|
5
|
+
**New in 0.3.1:** claymorphic automation workspaces with searchable, status-filtered, paginated lists; Summary/History tabs and calendar-style run cards; sanitized Markdown/ADF/JSON results; a staged job editor with strict validation and optional failed-action retries (up to 5, default 10-second interval). Per-automation history keeps the latest 30 runs by default, with 10 per page. Automated sessions are clearly marked as answers-only. Type `/` in a normal session to discover available commands, skills, and prompt templates. See [automations](docs/automations.md).
|
|
6
6
|
|
|
7
7
|
Pi Companion is deliberately not another agent runtime. Pi owns execution and conversation state. A single Rust daemon owns session discovery, pairing, temporary file exchange, browser fan-out, and the embedded web UI.
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ The UI is a static SvelteKit application. There is no Node runtime in production
|
|
|
15
15
|
<img src="docs/mobile.webp" alt="Session detail on a phone" width="28%" />
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
Screenshots use demo sessions, not private conversation data, and are regenerated with `node tools/screenshots.mjs` (see [Running locally from source](#running-locally-from-source)). See the [session menu](docs/session-menu.webp), [desktop session rows](docs/session-list-desktop.webp) and [mobile session list](docs/session-list.webp), plus [attachment previews](docs/attachments.webp), [file-grouped changes](docs/changes.webp) and [connection recovery](docs/connection-error.webp).
|
|
18
|
+
Screenshots use demo sessions, not private conversation data, and are regenerated with `node tools/screenshots.mjs` (see [Running locally from source](#running-locally-from-source)). See the [session menu](docs/session-menu.webp), [desktop session rows](docs/session-list-desktop.webp) and [mobile session list](docs/session-list.webp), plus [attachment previews](docs/attachments.webp), [file-grouped changes](docs/changes.webp) and [connection recovery](docs/connection-error.webp). Explore the new [automation list](docs/automations.webp), [summary](docs/automation-detail.webp), [run history](docs/automation-history.webp), [job editor](docs/automation-editor.webp), and [rich results](docs/automation-result.webp).
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
@@ -354,7 +354,7 @@ Clone the repository, then:
|
|
|
354
354
|
|
|
355
355
|
`npm run serve` builds the embedded Svelte UI and starts the Rust daemon in the foreground. It prints:
|
|
356
356
|
|
|
357
|
-
Pi Companion v0.3.
|
|
357
|
+
Pi Companion v0.3.1
|
|
358
358
|
|
|
359
359
|
Console http://127.0.0.1:43721
|
|
360
360
|
Paired devices http://127.0.0.1:43722
|
|
@@ -392,6 +392,8 @@ To regenerate the README screenshots from demo sessions (your running daemon is
|
|
|
392
392
|
npm run ui:build && cargo build --release --manifest-path server/Cargo.toml
|
|
393
393
|
node tools/screenshots.mjs
|
|
394
394
|
|
|
395
|
+
The generator also refreshes automation list/detail/history/editor/results, automated session, and [slash-command suggestions](docs/slash-commands.webp) screenshots. Type `/` in a shared session to search its available extension commands, skills, and prompt templates; use ↑/↓ and Tab/Enter to choose, then send when ready. Built-in terminal-only commands and ordinary tool names are not included. Automated answers-only sessions never expose this picker.
|
|
396
|
+
|
|
395
397
|
It needs Playwright and `cwebp`. Set `PLAYWRIGHT=/path/to/node_modules/playwright/index.mjs` if Playwright isn't installed in this repo, and `CHROME=/path/to/chrome` to use an existing browser.
|
|
396
398
|
|
|
397
399
|
To test the same behavior as a published install, stop any development daemon first and install the package normally:
|
package/docs/automations.md
CHANGED
|
@@ -1,7 +1,41 @@
|
|
|
1
|
-
# Automations (0.3.
|
|
1
|
+
# Automations (0.3.1)
|
|
2
2
|
|
|
3
3
|
Automations are persisted, named JSON scripts run by the Companion daemon. Open **Automations** in the navigation to view definitions, start/stop runs, and inspect timestamped run history. Click a run to view its captured output and Pi summary. Desktop console users can create, edit, delete, and enable/disable definitions; mobile and paired-device users can only inspect and start/stop them.
|
|
4
4
|
|
|
5
|
+
## Workspace & editor
|
|
6
|
+
|
|
7
|
+
The claymorphic automation collection supports name search, Enabled/Disabled filters, ten-item pagination, and its own scrollable card region. The detail workspace has **Summary** and **Run history** tabs; history is newest-first with calendar tiles, duration, status filters, and ten-item pagination over each automation’s retained history (latest 30 finished runs by default, configurable 1–1000).
|
|
8
|
+
|
|
9
|
+
The job editor separates name, enablement, UTC cron, optional retry policy, preconditions, actions, and post-actions. Each step is a reorderable JSON DSL object with Command/Pi templates. Saving validates the definition, cron ranges, action types, arguments, absolute directories, timeouts, step count, and retry bounds; the daemon validates again before persistence. Only computer desktop administrators can author definitions.
|
|
10
|
+
|
|
11
|
+
Run results have a formatted and raw view. Formatted results split daemon execution phases, render sanitized Markdown (including tables, links, code, and diagrams), recognise whole/fenced JSON, and render Atlassian Document Format (`type: "doc"`) or `{ "adf": ... }` documents. ADF supports headings, lists, marks, tables, panels, and safe links; unsupported nodes preserve their text, and attachments are placeholders. HTML/scripts and executable link protocols are not trusted. Raw output remains available for inspection and copying.
|
|
12
|
+
|
|
13
|
+
## Screenshots
|
|
14
|
+
|
|
15
|
+
Screenshots use only demo data. The same generator refreshes the existing overview, session, and mobile screenshots too.
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+

|
|
19
|
+

|
|
20
|
+

|
|
21
|
+

|
|
22
|
+

|
|
23
|
+

|
|
24
|
+

|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## History retention
|
|
28
|
+
|
|
29
|
+
`historyLimit` is an optional integer **1–1000**, default **30**. Each automation retains its latest N finished runs, replacing older history as newer runs finish. Lowering the limit prunes older runs immediately on save; active runs are retained until finished. The same policy is applied on daemon startup. Deleted run results cannot be recovered from the dashboard. Run history pages show **10 items** at a time.
|
|
30
|
+
|
|
31
|
+
Automations also appear below running sessions on the overview. Automated sessions are labelled **Automated · answers only** in session cards, tables, and the session workspace. Their browser controls allow question answers but not steering, planning, uploads, or code changes; backend restrictions remain authoritative.
|
|
32
|
+
|
|
33
|
+
## Optional retries
|
|
34
|
+
|
|
35
|
+
`maxRetries` is an optional integer **0–5** (default **0**, no retries). `retryIntervalSeconds` is an optional integer **1–86400** (default **10 seconds**). Only a failed main action is retried; completed steps do not repeat, and precondition skips and finalizers are never retried. Stop cancels an active process or retry delay. Save-time validation requires the total retry-delay budget to be shorter than the shortest daily UTC trigger gap (a conservative bound for schedules limited to selected dates). Before each wait, the daemon also skips a retry that would reach the next scheduled trigger. It cannot guarantee action duration; overlapping runs remain prohibited. Attempt diagnostics are included in run output, and finalizers execute after the final outcome unless stopped.
|
|
36
|
+
|
|
37
|
+
**Retries can duplicate side effects**, including model calls and remote submissions after ambiguous failures. Enable them only for retry-safe work; the PR-review automation should keep retries off. Existing definitions without either field retain their original behavior.
|
|
38
|
+
|
|
5
39
|
## JSON DSL
|
|
6
40
|
|
|
7
41
|
```json
|
|
@@ -9,6 +43,9 @@ Automations are persisted, named JSON scripts run by the Companion daemon. Open
|
|
|
9
43
|
"name": "Daily repository check",
|
|
10
44
|
"enabled": true,
|
|
11
45
|
"schedule": "0 9 * * 1-5",
|
|
46
|
+
"maxRetries": 0,
|
|
47
|
+
"retryIntervalSeconds": 10,
|
|
48
|
+
"historyLimit": 30,
|
|
12
49
|
"preconditions": [
|
|
13
50
|
{ "type": "command", "command": "git", "args": ["rev-parse", "--is-inside-work-tree"], "cwd": "/absolute/project" }
|
|
14
51
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yunazgr/pi-companion",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Local-first remote control for Pi sessions: live activity feed, steering, git diff, file drop and phone pairing from a single Rust daemon.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -32,6 +32,8 @@ Read the current definition with `get` before `update`, `enable`, or `disable`.
|
|
|
32
32
|
- `schedule` is a five-field **UTC** cron expression; `null` means manual only. The daemon must be running for scheduling. There is no catch-up while it is stopped.
|
|
33
33
|
- Commands use executable plus argument array, **no implicit shell**. Shell syntax must never be passed as an executable. Avoid explicit shells unless the user requested and authorized them.
|
|
34
34
|
- Preconditions gate execution. Actions run sequentially. Post-actions are the cleanup/finalization stage; inspect the run result to determine failures.
|
|
35
|
+
- Optional `maxRetries` (integer 0–5, default 0) and `retryIntervalSeconds` (integer 1–86400, default 10) retry only the failed main action, never completed steps, preconditions, or finalizers. Stop cancels a retry delay. Retries may duplicate side effects or model usage: obtain authorization, and keep them off for non-idempotent remote submissions.
|
|
36
|
+
- Optional `historyLimit` (integer 1–1000, default 30) keeps the latest N finished runs per automation. Lowering it immediately removes older history on save. Retry delays must fit before the next scheduled trigger.
|
|
35
37
|
- A Pi action starts a daemon-owned, read-only Companion session: users can answer asks, but cannot steer, prompt, upload, request changes, or edit its plan. The agent itself still has ordinary Pi tool permissions.
|
|
36
38
|
- Pi must be installed on PATH and configured with model credentials. Its final assistant output is saved in run history.
|
|
37
39
|
|
package/src/automation-mcp.ts
CHANGED
|
@@ -31,7 +31,7 @@ async function receive(line: string) {
|
|
|
31
31
|
case "initialize": {
|
|
32
32
|
const versions = ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
33
33
|
const requested = message.params?.protocolVersion;
|
|
34
|
-
reply({ protocolVersion: versions.includes(String(requested)) ? requested : versions[0], capabilities: { tools: {} }, serverInfo: { name: "pi-companion-automations", version: "0.3.
|
|
34
|
+
reply({ protocolVersion: versions.includes(String(requested)) ? requested : versions[0], capabilities: { tools: {} }, serverInfo: { name: "pi-companion-automations", version: "0.3.1" } });
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
case "ping": reply({}); return;
|
package/src/automation.ts
CHANGED
|
@@ -10,6 +10,9 @@ export type AutomationDefinition = {
|
|
|
10
10
|
preconditions: AutomationAction[];
|
|
11
11
|
actions: AutomationAction[];
|
|
12
12
|
postActions: AutomationAction[];
|
|
13
|
+
historyLimit?: number;
|
|
14
|
+
maxRetries?: number;
|
|
15
|
+
retryIntervalSeconds?: number;
|
|
13
16
|
};
|
|
14
17
|
export type AutomationParams = {
|
|
15
18
|
action: "list" | "get" | "create" | "update" | "delete" | "enable" | "disable" | "start" | "stop" | "runs" | "run";
|
|
@@ -48,7 +51,10 @@ export const automationTool = {
|
|
|
48
51
|
schedule: { type: ["string", "null"], description: "Five-field UTC cron; null for manual only." },
|
|
49
52
|
preconditions: { type: "array", items: actionSchema },
|
|
50
53
|
actions: { type: "array", minItems: 1, items: actionSchema },
|
|
51
|
-
postActions: { type: "array", items: actionSchema }
|
|
54
|
+
postActions: { type: "array", items: actionSchema },
|
|
55
|
+
historyLimit: { type: "integer", minimum: 1, maximum: 1000, description: "Retain latest N finished runs; default 30." },
|
|
56
|
+
maxRetries: { type: "integer", minimum: 0, maximum: 5, description: "Optional retries of the failed main action only; default 0. May repeat side effects." },
|
|
57
|
+
retryIntervalSeconds: { type: "integer", minimum: 1, maximum: 86400, description: "Optional delay between retries; default 10 seconds; total retry delay must fit before the next scheduled trigger." }
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
60
|
}
|
|
@@ -92,8 +98,8 @@ export async function executeAutomation(params: AutomationParams, signal?: Abort
|
|
|
92
98
|
case "enable": case "disable": {
|
|
93
99
|
const current = await request(path) as AutomationDefinition;
|
|
94
100
|
// PUT only definition fields, never server-generated metadata.
|
|
95
|
-
const { name, schedule, preconditions, actions, postActions } = current;
|
|
96
|
-
return request(path, "PUT", { name, schedule, preconditions, actions, postActions, enabled: params.action === "enable" });
|
|
101
|
+
const { name, schedule, preconditions, actions, postActions, maxRetries, retryIntervalSeconds, historyLimit } = current;
|
|
102
|
+
return request(path, "PUT", { name, schedule, preconditions, actions, postActions, maxRetries, retryIntervalSeconds, historyLimit, enabled: params.action === "enable" });
|
|
97
103
|
}
|
|
98
104
|
case "start": case "stop": return request(path + "/" + params.action, "POST");
|
|
99
105
|
case "runs": return request(path + "/runs");
|
package/src/bridge.ts
CHANGED
|
@@ -70,7 +70,11 @@ export class CompanionBridge implements AskChannel {
|
|
|
70
70
|
shortTitle: name?.trim() || cwd.split(/[\\/]/).filter(Boolean).pop() || "Pi",
|
|
71
71
|
mainModel: ctx.model?.id ?? null,
|
|
72
72
|
effort: ctx.thinkingLevel ?? this.pi.getThinkingLevel?.() ?? null,
|
|
73
|
-
telemetry: this.telemetry.snapshot(ctx)
|
|
73
|
+
telemetry: this.telemetry.snapshot(ctx),
|
|
74
|
+
// Expose only executable slash commands, not local source paths or credentials.
|
|
75
|
+
commands: (this.pi.getCommands?.() ?? []).slice(0, 500).map(command => ({
|
|
76
|
+
name: command.name, description: command.description?.slice(0, 500), source: command.source
|
|
77
|
+
}))
|
|
74
78
|
};
|
|
75
79
|
const patch: Partial<SessionSnapshot> = {};
|
|
76
80
|
for (const key of Object.keys(next) as Array<keyof typeof next>) {
|
package/src/protocol.ts
CHANGED
|
@@ -61,6 +61,7 @@ export type SessionSnapshot = {
|
|
|
61
61
|
effort?: string | null;
|
|
62
62
|
telemetry?: SessionTelemetry;
|
|
63
63
|
remoteEnabled: boolean;
|
|
64
|
+
commands?: { name: string; description?: string; source: 'extension' | 'prompt' | 'skill' }[];
|
|
64
65
|
connectedAt: string;
|
|
65
66
|
/** Questions waiting for an answer. Kept in the snapshot so late-joining browsers see them. */
|
|
66
67
|
asks: AskRequest[];
|