pi-pier 0.1.4 → 0.2.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/package.json +1 -1
- package/schemas/role-manifest.schema.json +1 -2
- package/src/bootstrap.ts +18 -22
- package/src/core/grid-shape.ts +13 -14
- package/src/core/subagent.ts +325 -857
- package/src/core/terminal.ts +25 -28
- package/src/core/todo.ts +47 -53
- package/src/gc-core.ts +15 -15
- package/src/git-adapter.ts +104 -0
- package/src/herdr-client.ts +76 -68
- package/src/history-store.ts +70 -36
- package/src/index-locks.ts +105 -0
- package/src/index-master.ts +113 -0
- package/src/index-notices.ts +43 -0
- package/src/index-pipe.ts +73 -0
- package/src/index-runtime.ts +23 -0
- package/src/index-worker.ts +39 -0
- package/src/index.ts +134 -386
- package/src/ledger.ts +15 -17
- package/src/lock-core.ts +15 -29
- package/src/manifest-compose.ts +9 -23
- package/src/notice-buffer.ts +9 -14
- package/src/pane-title.ts +24 -24
- package/src/pi-surface.ts +22 -29
- package/src/pipe-channel.ts +67 -34
- package/src/platform-paths.ts +72 -0
- package/src/progress-core.ts +26 -24
- package/src/reconcile-core.ts +25 -24
- package/src/role-loader.ts +32 -35
- package/src/role-manifest.ts +24 -28
- package/src/roles/master.json +2 -2
- package/src/roles/worker-default.json +3 -3
- package/src/runtime-policy.ts +66 -0
- package/src/session-tail.ts +46 -45
- package/src/settle-wake-core.ts +19 -18
- package/src/slim-frame.ts +45 -44
- package/src/stale-core.ts +23 -21
- package/src/storage-layout.ts +80 -0
- package/src/subagent-core.ts +151 -94
- package/src/subagent-gc.ts +237 -0
- package/src/subagent-git-io.ts +80 -0
- package/src/subagent-launch.ts +110 -0
- package/src/subagent-poll-loop.ts +285 -0
- package/src/subagent-poller.ts +90 -0
- package/src/subagent-port.ts +27 -0
- package/src/subagent-scope.ts +4 -4
- package/src/subagent-session-io.ts +143 -0
- package/src/subagent-spawn.ts +156 -0
- package/src/terminal-core.ts +56 -54
- package/src/todo-core.ts +27 -64
- package/src/todo-read-hook.ts +28 -24
- package/src/todo-reminder-core.ts +89 -0
- package/src/todos-service.ts +36 -25
- package/src/tool-gate.ts +7 -28
- package/src/vocab.ts +18 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-pier",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "pier: pi extension that fuses pi agent sessions with the herdr pane/tab orchestrator — todo_write loop closure + interactive subagents in isolated panes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/bootstrap.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bootstrap the master Cordis tree (D78 mount topology, D80 ecosystem adoption, D81 split).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* env PI_HERDR_HMR=1,缺一即跳过——生产路径零 watcher)。
|
|
4
|
+
* Load the group, timer, and HMR plugins in order so declarations resolve and HMR stays a
|
|
5
|
+
* development-only path (`--expose-internals` plus PI_HERDR_HMR=1); production has no watcher.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Workers bypass this module (C3/D81) because short-lived processes mount manually without
|
|
8
|
+
* loader or HMR; this module and subagent-scope.ts are master-only dynamic imports.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
* loader entry(热换面 = entry,D80③ 手动 mount 不热换)。
|
|
10
|
+
* Core modules will gradually become loader entries; manual mounts remain non-hot-reloaded (D80③).
|
|
13
11
|
*/
|
|
14
12
|
import { Context } from '@deepseek-ai/cordis';
|
|
15
13
|
import Loader from '@deepseek-ai/cordis-plugin-loader';
|
|
@@ -23,17 +21,17 @@ export interface BootstrapHooks {
|
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
export interface CordisApp {
|
|
26
|
-
/**
|
|
24
|
+
/** Root owns subagent scopes and lifecycle effects. */
|
|
27
25
|
root: Context;
|
|
28
|
-
/**
|
|
26
|
+
/** False preserves the bare-tree fallback, matching the baseline behavior. */
|
|
29
27
|
loaderReady: boolean;
|
|
30
|
-
/**
|
|
28
|
+
/** HMR is enabled only in the development posture. */
|
|
31
29
|
hmrActive: boolean;
|
|
32
|
-
/**
|
|
30
|
+
/** Shared ledger compensates HMR disposal and handles session_shutdown cleanup. */
|
|
33
31
|
ledger: DisposeLedger;
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
/**
|
|
34
|
+
/** HMR requires Node's --expose-internals flag (D80①). */
|
|
37
35
|
export function detectExposeInternals(): boolean {
|
|
38
36
|
return process.execArgv.some((a) => a === '--expose-internals' || a.startsWith('--expose-internals='));
|
|
39
37
|
}
|
|
@@ -41,13 +39,12 @@ export function detectExposeInternals(): boolean {
|
|
|
41
39
|
export async function createCordisApp(hooks: BootstrapHooks = {}): Promise<CordisApp> {
|
|
42
40
|
const root = new Context();
|
|
43
41
|
const ledger = new DisposeLedger();
|
|
44
|
-
//
|
|
45
|
-
// (entry config 过不了活实例,loader 会变换 config;provide/get 是 hmr/timer 同款机制)
|
|
42
|
+
// Inject the ledger through Cordis DI because loader transforms entry config and cannot carry live instances.
|
|
46
43
|
root.provide('pi-herdr.ledger', ledger);
|
|
47
44
|
if (hooks.onDispose) {
|
|
48
45
|
root.effect(() => () => { hooks.onDispose?.(); }, 'session-root');
|
|
49
46
|
}
|
|
50
|
-
//
|
|
47
|
+
// Resolve relative entry names (./core/...) from this module's directory.
|
|
51
48
|
root.baseUrl = pathToFileURL(path.dirname(fileURLToPath(import.meta.url))).href + '/';
|
|
52
49
|
|
|
53
50
|
let loaderReady = false;
|
|
@@ -56,7 +53,7 @@ export async function createCordisApp(hooks: BootstrapHooks = {}): Promise<Cordi
|
|
|
56
53
|
await root.plugin(Loader);
|
|
57
54
|
const withLoader = root as Context & { loader?: { builtins: Record<string, unknown> } };
|
|
58
55
|
if (withLoader.loader) {
|
|
59
|
-
withLoader.loader.builtins.group = Group; // D80
|
|
56
|
+
withLoader.loader.builtins.group = Group; // D80③: declarations resolve cordis:group through this builtin.
|
|
60
57
|
loaderReady = true;
|
|
61
58
|
}
|
|
62
59
|
} catch (err) {
|
|
@@ -79,9 +76,8 @@ export async function createCordisApp(hooks: BootstrapHooks = {}): Promise<Cordi
|
|
|
79
76
|
});
|
|
80
77
|
hmrActive = true;
|
|
81
78
|
console.error('[pi-herdr] hmr active (dev posture: --expose-internals + PI_HERDR_HMR=1)');
|
|
82
|
-
// D80
|
|
83
|
-
//
|
|
84
|
-
// 收割(d87 世代化:重挂后的 disposeKey 只杀登记世代及之前,新世代豁免)。
|
|
79
|
+
// D80⑤: HMR already disposes old fiber effects; this hook additionally retires old pi-surface generations.
|
|
80
|
+
// d87 keeps generations registered after the reload boundary alive; disposeKey retires only older entries.
|
|
85
81
|
root.on('hmr/reload', (reloads: unknown) => {
|
|
86
82
|
try {
|
|
87
83
|
const files: string[] = [];
|
|
@@ -93,11 +89,11 @@ export async function createCordisApp(hooks: BootstrapHooks = {}): Promise<Cordi
|
|
|
93
89
|
if (n > 0) console.error(`[pi-herdr] ledger: compensated ${n} disposal(s) for ${files.join(', ')}`);
|
|
94
90
|
}
|
|
95
91
|
} catch {
|
|
96
|
-
/*
|
|
92
|
+
/* Best-effort compensation; disposal failures are non-fatal. */
|
|
97
93
|
}
|
|
98
94
|
});
|
|
99
95
|
} catch (err) {
|
|
100
|
-
// D80
|
|
96
|
+
// D80②: a failed HMR mount degrades to zero watchers while the rest of the tree remains usable.
|
|
101
97
|
console.error(`[pi-herdr] hmr mount failed (degraded): ${err instanceof Error ? err.message : String(err)}`);
|
|
102
98
|
}
|
|
103
99
|
}
|
package/src/core/grid-shape.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* D97
|
|
2
|
+
* D97: Always split the largest cell downward so spawned panes remain full-width strips.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Heat reflow narrows unfocused cells, but full-width strips keep the slim-frame title
|
|
5
|
+
* readable on one line. The previous grid topology produced narrow vertical cells whose
|
|
6
|
+
* titles wrapped into unreadable columns. The overlay threshold complements both layouts:
|
|
7
|
+
* new strips cross the row limit, while existing columns cross the column limit.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* herdr 0.8.2 defines ratio as the first child's share. Because layout.apply creates a
|
|
10
|
+
* new shell rather than attaching an existing pane, spawn-time incremental splits must
|
|
11
|
+
* establish this topology; heat reflow owns only later sizing.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
export type ShapeNode =
|
|
15
15
|
| { type: 'pane'; paneId: string }
|
|
16
16
|
| { type: 'split'; direction: string; ratio: number; first: ShapeNode; second: ShapeNode };
|
|
17
17
|
|
|
18
|
-
/**
|
|
18
|
+
/** Tolerate layout.export shape variants because pane leaves may nest pane_id. */
|
|
19
19
|
export function parseShapeTree(raw: unknown): ShapeNode | null {
|
|
20
20
|
if (!raw || typeof raw !== 'object') return null;
|
|
21
21
|
const o = raw as Record<string, unknown>;
|
|
@@ -49,7 +49,7 @@ export interface PaneCell {
|
|
|
49
49
|
h: number;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/**
|
|
52
|
+
/** Use a representative TUI aspect ratio so preorder cell comparisons reflect screen area. */
|
|
53
53
|
export function paneCells(root: ShapeNode, width = 200, height = 50): PaneCell[] {
|
|
54
54
|
const cells: PaneCell[] = [];
|
|
55
55
|
const walk = (node: ShapeNode, x: number, y: number, w: number, h: number): void => {
|
|
@@ -71,10 +71,9 @@ export function paneCells(root: ShapeNode, width = 200, height = 50): PaneCell[]
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* exclude = 不许动的格子(board 等无 agent 常驻 shell)。
|
|
74
|
+
* Split the largest eligible cell downward; preorder tie-breaking keeps the choice stable.
|
|
75
|
+
* At D97's 200x50 model and ten-pane cap, strips eventually become slim title frames by design.
|
|
76
|
+
* Exclusions protect resident non-agent panes such as the board from worker splits.
|
|
78
77
|
*/
|
|
79
78
|
export function pickGridSplit(
|
|
80
79
|
root: ShapeNode,
|