@oisin-ee/oisinpi 0.7.2 → 0.8.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/CHANGELOG.md +9 -0
- package/node_modules/@oisin-ee/pi-guardrails/package.json +1 -1
- package/node_modules/@oisin-ee/pi-prewalk/README.md +2 -1
- package/node_modules/@oisin-ee/pi-prewalk/package.json +1 -1
- package/node_modules/@oisin-ee/pi-prewalk/src/adapter.ts +2 -0
- package/node_modules/@oisin-ee/pi-prewalk/src/generated/prewalk_core.d.ts +4 -0
- package/node_modules/@oisin-ee/pi-prewalk/src/generated/prewalk_core_bg.wasm +0 -0
- package/node_modules/@oisin-ee/pi-prewalk/src/ports.ts +1 -1
- package/node_modules/@oisin-ee/pi-prewalk/src/tasks.ts +48 -0
- package/node_modules/@oisin-ee/pi-todo/package.json +1 -1
- package/node_modules/@oisin-ee/pi-todo/src/contract-fixture.ts +103 -0
- package/node_modules/@oisin-ee/pi-todo/src/display.ts +8 -2
- package/node_modules/@oisin-ee/pi-todo/src/gate.ts +79 -0
- package/node_modules/@oisin-ee/pi-todo/src/generated/todo_core.d.ts +342 -5
- package/node_modules/@oisin-ee/pi-todo/src/generated/todo_core.js +222 -5
- package/node_modules/@oisin-ee/pi-todo/src/generated/todo_core_bg.wasm +0 -0
- package/node_modules/@oisin-ee/pi-todo/src/generated/todo_core_bg.wasm.d.ts +8 -1
- package/node_modules/@oisin-ee/pi-todo/src/guidance.ts +5 -1
- package/node_modules/@oisin-ee/pi-todo/src/handoff.ts +84 -0
- package/node_modules/@oisin-ee/pi-todo/src/import-fixture.ts +63 -0
- package/node_modules/@oisin-ee/pi-todo/src/index.ts +17 -43
- package/node_modules/@oisin-ee/pi-todo/src/lease-fixture.ts +95 -0
- package/node_modules/@oisin-ee/pi-todo/src/provider-fixture.ts +50 -0
- package/node_modules/@oisin-ee/pi-todo/src/provider.ts +289 -0
- package/node_modules/@oisin-ee/pi-todo/src/registration-fixture.ts +126 -0
- package/node_modules/@oisin-ee/pi-todo/src/repository.ts +31 -0
- package/node_modules/@oisin-ee/pi-todo/src/runtime-fixture.ts +209 -0
- package/node_modules/@oisin-ee/pi-todo/src/schema.ts +86 -0
- package/node_modules/@oisin-ee/pi-todo/src/seed-fixture.ts +35 -0
- package/node_modules/@oisin-ee/pi-todo/src/seed-transport.ts +52 -0
- package/node_modules/@oisin-ee/pi-todo/src/source.ts +33 -3
- package/node_modules/@oisin-ee/pi-todo/src/state.ts +78 -1
- package/node_modules/@oisin-ee/pi-todo/src/tool.ts +15 -14
- package/node_modules/@oisin-ee/pi-todo/src/wasm.ts +26 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @oisin-ee/oisinpi
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`50877ec`](https://github.com/oisin-ee/oisinpi/commit/50877ec0f9bba71b7f70d8bf8d3754191ac73364)]:
|
|
8
|
+
- @oisin-ee/pi-todo@0.8.0
|
|
9
|
+
- @oisin-ee/pi-prewalk@0.8.0
|
|
10
|
+
- @oisin-ee/pi-guardrails@0.8.0
|
|
11
|
+
|
|
3
12
|
## 0.7.2
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @oisin-ee/pi-prewalk
|
|
2
2
|
|
|
3
|
-
Prewalk starts with the active planner model. After the planning nudge,
|
|
3
|
+
Prewalk starts with the active planner model. After the planning nudge, validated local task activation opens the handoff gate.
|
|
4
|
+
Without the task-provider capability, a successful `todo` call opens the gate instead. Imported workers need no bookkeeping call.
|
|
4
5
|
The first subsequent `edit` or `write` result switches the session to the target model, even if that result failed.
|
|
5
6
|
Nested calls through codemode also count. Without a callable `todo` tool, the gate is open.
|
|
6
7
|
|
|
@@ -4,6 +4,7 @@ import type { BoundaryResult, SessionBoundaryDraft } from "@earendil-works/pi-co
|
|
|
4
4
|
import type { Context, Files, Host } from "./ports.ts";
|
|
5
5
|
import { branchRecords, calls } from "./branch.ts";
|
|
6
6
|
import type { CallEvidence } from "./branch.ts";
|
|
7
|
+
import { activeTask } from "./tasks.ts";
|
|
7
8
|
import { decide } from "./wasm.ts";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -117,6 +118,7 @@ class Adapter {
|
|
|
117
118
|
todo.exposure === "deferred" ||
|
|
118
119
|
this.#pi.getActiveTools().includes("todo"));
|
|
119
120
|
return {
|
|
121
|
+
active_unit: activeTask(this.#pi.events),
|
|
120
122
|
available: ctx.modelRegistry
|
|
121
123
|
.getAvailable()
|
|
122
124
|
.map((candidate) => `${candidate.provider}/${candidate.id}`),
|
|
@@ -55,6 +55,10 @@ export interface Facts {
|
|
|
55
55
|
* Is todo callable (directly or through codemode)?
|
|
56
56
|
*/
|
|
57
57
|
todo: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Current provider activation; absent preserves the legacy successful-todo rule.
|
|
60
|
+
*/
|
|
61
|
+
active_unit?: boolean | undefined;
|
|
58
62
|
/**
|
|
59
63
|
* Todo source identity for status.
|
|
60
64
|
*/
|
|
Binary file
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
interface ActiveProvider {
|
|
4
|
+
readonly active: () => unknown;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validates only the capability method this consumer needs.
|
|
9
|
+
* @param {unknown} value Capability response.
|
|
10
|
+
* @returns {boolean} Whether the active query is callable.
|
|
11
|
+
*/
|
|
12
|
+
const isProvider = (value: unknown): value is ActiveProvider =>
|
|
13
|
+
typeof value === "object" &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
"active" in value &&
|
|
16
|
+
typeof value.active === "function",
|
|
17
|
+
/**
|
|
18
|
+
* Queries current activation without loading todo or interpreting its snapshots.
|
|
19
|
+
* @param {Readonly<ExtensionAPI["events"]>} events Extension capability bus.
|
|
20
|
+
* @returns {boolean | undefined} Activation, or unavailable legacy capability.
|
|
21
|
+
*/
|
|
22
|
+
activeTask = (events: Readonly<ExtensionAPI["events"]>): boolean | undefined => {
|
|
23
|
+
const replies: unknown[] = [];
|
|
24
|
+
events.emit("oisin.tasks.acquire.v1", {
|
|
25
|
+
reply: (provider: unknown): void => {
|
|
26
|
+
replies.push(provider);
|
|
27
|
+
},
|
|
28
|
+
version: 1,
|
|
29
|
+
});
|
|
30
|
+
const [provider] = replies,
|
|
31
|
+
one = 1;
|
|
32
|
+
if (replies.length !== one || !isProvider(provider)) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const result: unknown = provider.active();
|
|
36
|
+
if (
|
|
37
|
+
typeof result !== "object" ||
|
|
38
|
+
result === null ||
|
|
39
|
+
!("ok" in result) ||
|
|
40
|
+
result.ok !== true ||
|
|
41
|
+
!("value" in result)
|
|
42
|
+
) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return result.value !== null && result.value !== undefined;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export { activeTask };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { TodoParams, TodoSession } from "./tool.ts";
|
|
2
|
+
import { STATE_ENTRY } from "./state.ts";
|
|
3
|
+
import type { SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import type { TodoList } from "./wasm.ts";
|
|
5
|
+
import { runTodo } from "./tool.ts";
|
|
6
|
+
|
|
7
|
+
interface Fixture {
|
|
8
|
+
readonly entries: SessionEntry[];
|
|
9
|
+
readonly session: TodoSession;
|
|
10
|
+
readonly call: (params: TodoParams) => TodoList;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a branch-backed caller using the real tool and WASM core.
|
|
15
|
+
* @param {readonly unknown[]} snapshots Existing stored snapshots.
|
|
16
|
+
* @returns {Fixture} The tool caller and Pi append seam.
|
|
17
|
+
*/
|
|
18
|
+
const first = 0,
|
|
19
|
+
second = 1,
|
|
20
|
+
third = 2,
|
|
21
|
+
last = -1,
|
|
22
|
+
fixture = (snapshots: readonly unknown[] = []): Fixture => {
|
|
23
|
+
const entries = snapshots.map((data): SessionEntry => ({
|
|
24
|
+
customType: STATE_ENTRY,
|
|
25
|
+
data,
|
|
26
|
+
id: crypto.randomUUID(),
|
|
27
|
+
parentId: null,
|
|
28
|
+
timestamp: "2026-10-20T00:00:00Z",
|
|
29
|
+
type: "custom",
|
|
30
|
+
})),
|
|
31
|
+
session: TodoSession = {
|
|
32
|
+
append: (customType, data): void => {
|
|
33
|
+
entries.push({
|
|
34
|
+
customType,
|
|
35
|
+
data,
|
|
36
|
+
id: crypto.randomUUID(),
|
|
37
|
+
parentId: entries.at(last)?.id ?? null,
|
|
38
|
+
timestamp: "2026-10-20T00:00:00Z",
|
|
39
|
+
type: "custom",
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
branch: () => entries,
|
|
43
|
+
sessionId: "test-session",
|
|
44
|
+
};
|
|
45
|
+
return { call: (params) => runTodo(params, session).details, entries, session };
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* A complete self-assigned contract for deterministic behavior tests.
|
|
49
|
+
* @returns {NonNullable<TodoParams["contract"]>} Authored contract fields.
|
|
50
|
+
*/
|
|
51
|
+
contract = (): NonNullable<TodoParams["contract"]> => ({
|
|
52
|
+
acceptance: {
|
|
53
|
+
argv: ["moon", "run", "todo-core:test"],
|
|
54
|
+
cwd: ".",
|
|
55
|
+
expected: "passes",
|
|
56
|
+
kind: "command",
|
|
57
|
+
},
|
|
58
|
+
assignment: { kind: "self" },
|
|
59
|
+
deliverable: "Executable task contracts",
|
|
60
|
+
dependsOn: [],
|
|
61
|
+
scope: { generates: [], owns: ["src/"], reads: ["README.md"], repositoryId: "oisinpi" },
|
|
62
|
+
}),
|
|
63
|
+
/**
|
|
64
|
+
* Returns the runtime ID from the first root in a tool result.
|
|
65
|
+
* @param {TodoList} list Real tool result.
|
|
66
|
+
* @returns {string} Runtime ID.
|
|
67
|
+
*/
|
|
68
|
+
firstId = (list: TodoList): string => {
|
|
69
|
+
const id = list.tasks.at(first)?.unit?.reference.unitId;
|
|
70
|
+
if (id === undefined) {
|
|
71
|
+
throw new Error("Expected a runtime unit ID");
|
|
72
|
+
}
|
|
73
|
+
return id;
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Requires a root identity at a known fixture position.
|
|
77
|
+
* @param {TodoList} list Tool result.
|
|
78
|
+
* @param {number} index Root position.
|
|
79
|
+
* @returns {string} Runtime ID.
|
|
80
|
+
*/
|
|
81
|
+
rootId = (list: TodoList, index: number): string => {
|
|
82
|
+
const id = list.tasks.at(index)?.unit?.reference.unitId;
|
|
83
|
+
if (id === undefined) {
|
|
84
|
+
throw new Error("Expected root identity");
|
|
85
|
+
}
|
|
86
|
+
return id;
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Requires a child identity from the first outcome.
|
|
90
|
+
* @param {TodoList} list Tool result.
|
|
91
|
+
* @param {number} index Child position.
|
|
92
|
+
* @returns {string} Runtime ID.
|
|
93
|
+
*/
|
|
94
|
+
childId = (list: TodoList, index: number): string => {
|
|
95
|
+
const id = list.tasks.at(first)?.subtasks?.at(index)?.unit?.reference.unitId;
|
|
96
|
+
if (id === undefined) {
|
|
97
|
+
throw new Error("Expected child identity");
|
|
98
|
+
}
|
|
99
|
+
return id;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export { childId, contract, first, firstId, fixture, last, rootId, second, third };
|
|
103
|
+
export type { Fixture };
|
|
@@ -41,8 +41,14 @@ const emptyCount = 0,
|
|
|
41
41
|
active = list.tasks.flatMap((task) => [
|
|
42
42
|
...(task.status === "in_progress" ? [task.content] : []),
|
|
43
43
|
...(task.subtasks ?? [])
|
|
44
|
-
.filter(
|
|
45
|
-
|
|
44
|
+
.filter(
|
|
45
|
+
(child: Readonly<Pick<Subtask, "content" | "status">>) =>
|
|
46
|
+
child.status === "in_progress",
|
|
47
|
+
)
|
|
48
|
+
.map(
|
|
49
|
+
(child: Readonly<Pick<Subtask, "content" | "status">>) =>
|
|
50
|
+
`${task.content} → ${child.content}`,
|
|
51
|
+
),
|
|
46
52
|
]),
|
|
47
53
|
current =
|
|
48
54
|
active.length > emptyCount
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { TaskProvider } from "./provider.ts";
|
|
3
|
+
import { ownsTodo } from "./lifecycle.ts";
|
|
4
|
+
|
|
5
|
+
/** Exact structured reads and workflow controls, never command-text inference. */
|
|
6
|
+
const controls = new Set([
|
|
7
|
+
"ask",
|
|
8
|
+
"codemode",
|
|
9
|
+
"interview",
|
|
10
|
+
"todo",
|
|
11
|
+
"tool_search",
|
|
12
|
+
"read",
|
|
13
|
+
"ls",
|
|
14
|
+
"find",
|
|
15
|
+
"grep",
|
|
16
|
+
"hypa_read",
|
|
17
|
+
"hypa_ls",
|
|
18
|
+
"hypa_find",
|
|
19
|
+
"hypa_grep",
|
|
20
|
+
"web_search",
|
|
21
|
+
"web_fetch",
|
|
22
|
+
"lsp_diagnostics",
|
|
23
|
+
"ctx_search",
|
|
24
|
+
"ctx_stats",
|
|
25
|
+
"mcp__codebase_memory__search_graph",
|
|
26
|
+
"mcp__codebase_memory__get_code_snippet",
|
|
27
|
+
"mcp__codebase_memory__trace_path",
|
|
28
|
+
"mcp__codebase_memory__detect_changes",
|
|
29
|
+
"hindsight_search_knowledge_pages",
|
|
30
|
+
"hindsight_list_knowledge_pages",
|
|
31
|
+
"hindsight_read_knowledge_page",
|
|
32
|
+
"hindsight_reflect",
|
|
33
|
+
"hindsight_sync_status",
|
|
34
|
+
"hindsight_diagnose",
|
|
35
|
+
"hindsight_capture_initiative",
|
|
36
|
+
"mcp__dogsled__spawn",
|
|
37
|
+
"mcp__dogsled__send",
|
|
38
|
+
"mcp__dogsled__cancel",
|
|
39
|
+
"mcp__dogsled__close",
|
|
40
|
+
"mcp__dogsled__stop",
|
|
41
|
+
"mcp__dogsled__read",
|
|
42
|
+
"mcp__dogsled__status",
|
|
43
|
+
"mcp__dogsled__inbox",
|
|
44
|
+
]),
|
|
45
|
+
/**
|
|
46
|
+
* Checks actual calls and leases execution-bearing calls.
|
|
47
|
+
* @param {Readonly<ExtensionAPI>} pi Runtime hooks and metadata.
|
|
48
|
+
* @param {Readonly<TaskProvider>} provider Task state and leases.
|
|
49
|
+
*/
|
|
50
|
+
registerGate = (
|
|
51
|
+
pi: Readonly<Pick<ExtensionAPI, "on" | "getAllTools">>,
|
|
52
|
+
provider: Readonly<TaskProvider>,
|
|
53
|
+
): void => {
|
|
54
|
+
pi.on("tool_call", (event: Readonly<{ toolName: string; toolCallId: string }>, ctx) => {
|
|
55
|
+
if (!ownsTodo(pi)) {
|
|
56
|
+
return { block: false };
|
|
57
|
+
}
|
|
58
|
+
provider.context(ctx);
|
|
59
|
+
if (controls.has(event.toolName)) {
|
|
60
|
+
return { block: false };
|
|
61
|
+
}
|
|
62
|
+
const active = provider.capability().active();
|
|
63
|
+
if (!active.ok || active.value === null) {
|
|
64
|
+
return {
|
|
65
|
+
block: true,
|
|
66
|
+
reason: active.ok
|
|
67
|
+
? "Start a complete self-assigned leaf with todo before shell, code, mutation, or unknown tools."
|
|
68
|
+
: active.error.message,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
provider.lease(event.toolCallId, active.value.ref);
|
|
72
|
+
return { block: false };
|
|
73
|
+
});
|
|
74
|
+
pi.on("tool_execution_end", (event: Readonly<{ toolCallId: string }>) => {
|
|
75
|
+
provider.release(event.toolCallId);
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export { registerGate };
|