@docyrus/docyrus 0.0.40 → 0.0.42
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 +7 -0
- package/main.js +3708 -1173
- package/main.js.map +4 -4
- package/package.json +8 -7
- package/resources/pi-agent/extensions/control.ts +0 -8
- package/resources/pi-agent/extensions/knowledge.ts +0 -7
- package/resources/pi-agent/extensions/loop.ts +1 -5
- package/resources/pi-agent/extensions/pi-bash-live-view/package.json +1 -1
- package/resources/pi-agent/extensions/pi-custom-compaction/events/register-events.ts +0 -10
- package/resources/pi-agent/extensions/pi-custom-compaction/package.json +4 -4
- package/resources/pi-agent/extensions/plan.ts +95 -4
- package/resources/pi-agent/extensions/prompt-editor.ts +0 -18
- package/resources/pi-agent/extensions/prompt-url-widget.ts +0 -4
- package/resources/pi-agent/extensions/review.ts +0 -4
- package/resources/pi-agent/extensions/tasks.ts +497 -0
- package/resources/pi-agent/extensions/todos.ts +102 -2
- package/resources/pi-agent/skills/agent-browser/SKILL.md +779 -0
- package/resources/pi-agent/skills/agent-browser/references/authentication.md +303 -0
- package/resources/pi-agent/skills/agent-browser/references/commands.md +295 -0
- package/resources/pi-agent/skills/agent-browser/references/profiling.md +120 -0
- package/resources/pi-agent/skills/agent-browser/references/proxy-support.md +194 -0
- package/resources/pi-agent/skills/agent-browser/references/session-management.md +193 -0
- package/resources/pi-agent/skills/agent-browser/references/snapshot-refs.md +219 -0
- package/resources/pi-agent/skills/agent-browser/references/video-recording.md +173 -0
- package/resources/pi-agent/skills/agent-browser/templates/authenticated-session.sh +105 -0
- package/resources/pi-agent/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/resources/pi-agent/skills/agent-browser/templates/form-automation.sh +62 -0
- package/resources/pi-agent/skills/docyrus-platform/references/docyrus-cli-usage.md +73 -0
- package/resources/pi-agent/skills/grill-me/SKILL.md +109 -0
- package/server-loader.js +24270 -3381
- package/server-loader.js.map +4 -4
|
@@ -65,6 +65,12 @@ const DEFAULT_TODO_SETTINGS = {
|
|
|
65
65
|
};
|
|
66
66
|
const LOCK_TTL_MS = 30 * 60 * 1000;
|
|
67
67
|
|
|
68
|
+
interface ITodoCliEnvironment {
|
|
69
|
+
executable: string;
|
|
70
|
+
entryPath: string;
|
|
71
|
+
scope: "local" | "global";
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
interface TodoFrontMatter {
|
|
69
75
|
id: string;
|
|
70
76
|
title: string;
|
|
@@ -72,6 +78,7 @@ interface TodoFrontMatter {
|
|
|
72
78
|
status: string;
|
|
73
79
|
created_at: string;
|
|
74
80
|
assigned_to_session?: string;
|
|
81
|
+
parent_task_id?: string;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
interface TodoRecord extends TodoFrontMatter {
|
|
@@ -111,6 +118,7 @@ const TodoParams = Type.Object({
|
|
|
111
118
|
body: Type.Optional(
|
|
112
119
|
Type.String({ description: "Long-form details (markdown). Update replaces; append adds." }),
|
|
113
120
|
),
|
|
121
|
+
parentTaskId: Type.Optional(Type.String({ description: "Optional canonical project task id for linked local subtasks" })),
|
|
114
122
|
force: Type.Optional(Type.Boolean({ description: "Override another session's assignment" })),
|
|
115
123
|
});
|
|
116
124
|
|
|
@@ -150,6 +158,71 @@ function formatTodoId(id: string): string {
|
|
|
150
158
|
return `${TODO_ID_PREFIX}${id}`;
|
|
151
159
|
}
|
|
152
160
|
|
|
161
|
+
function readCliEnvironment(env: NodeJS.ProcessEnv = process.env): ITodoCliEnvironment {
|
|
162
|
+
const executable = env.DOCYRUS_CLI_EXECUTABLE?.trim();
|
|
163
|
+
const entryPath = env.DOCYRUS_CLI_ENTRY?.trim();
|
|
164
|
+
const scope = env.DOCYRUS_CLI_SCOPE?.trim() as "local" | "global" | undefined;
|
|
165
|
+
|
|
166
|
+
if (!executable || !entryPath || (scope !== "local" && scope !== "global")) {
|
|
167
|
+
throw new Error("Missing Docyrus CLI runtime env. Expected DOCYRUS_CLI_EXECUTABLE, DOCYRUS_CLI_ENTRY, and DOCYRUS_CLI_SCOPE.");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
executable,
|
|
172
|
+
entryPath,
|
|
173
|
+
scope,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function runProjectPlanCliJson<TValue>(
|
|
178
|
+
environment: ITodoCliEnvironment,
|
|
179
|
+
pi: ExtensionAPI,
|
|
180
|
+
ctx: ExtensionContext,
|
|
181
|
+
args: string[],
|
|
182
|
+
): Promise<TValue> {
|
|
183
|
+
const scopedArgs = environment.scope === "global" ? ["-g", ...args] : args;
|
|
184
|
+
const result = await pi.exec(environment.executable, [environment.entryPath, ...scopedArgs, "--json"], {
|
|
185
|
+
cwd: ctx.cwd,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const stdout = result.stdout?.toString().trim() || "";
|
|
189
|
+
const stderr = result.stderr?.toString().trim() || "";
|
|
190
|
+
const output = stdout || stderr;
|
|
191
|
+
if (result.code !== 0 || !output) {
|
|
192
|
+
throw new Error(output || `Command exited with code ${result.code ?? "unknown"}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return JSON.parse(output) as TValue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function validateParentTaskId(parentTaskId: string | undefined, pi: ExtensionAPI, ctx: ExtensionContext): Promise<string | undefined> {
|
|
199
|
+
const normalized = parentTaskId?.trim();
|
|
200
|
+
if (!normalized) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const environment = readCliEnvironment();
|
|
205
|
+
const payload = await runProjectPlanCliJson<{
|
|
206
|
+
id?: string;
|
|
207
|
+
assignee?: string;
|
|
208
|
+
}>(environment, pi, ctx, [
|
|
209
|
+
"project-plan",
|
|
210
|
+
"get-task",
|
|
211
|
+
"--taskId",
|
|
212
|
+
normalized,
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
if (!payload.id) {
|
|
216
|
+
throw new Error(`Task "${normalized}" was not found.`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (payload.assignee !== "agent") {
|
|
220
|
+
throw new Error(`Task "${payload.id}" is assigned to "${payload.assignee}" and cannot own local agent subtasks.`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return payload.id;
|
|
224
|
+
}
|
|
225
|
+
|
|
153
226
|
function normalizeTodoId(id: string): string {
|
|
154
227
|
let trimmed = id.trim();
|
|
155
228
|
if (trimmed.startsWith("#")) {
|
|
@@ -198,7 +271,8 @@ function sortTodos(todos: TodoFrontMatter[]): TodoFrontMatter[] {
|
|
|
198
271
|
function buildTodoSearchText(todo: TodoFrontMatter): string {
|
|
199
272
|
const tags = todo.tags.join(" ");
|
|
200
273
|
const assignment = todo.assigned_to_session ? `assigned:${todo.assigned_to_session}` : "";
|
|
201
|
-
|
|
274
|
+
const parentTask = todo.parent_task_id ? `task:${todo.parent_task_id}` : "";
|
|
275
|
+
return `${formatTodoId(todo.id)} ${todo.id} ${todo.title} ${tags} ${todo.status} ${assignment} ${parentTask}`.trim();
|
|
202
276
|
}
|
|
203
277
|
|
|
204
278
|
function filterTodos(todos: TodoFrontMatter[], query: string): TodoFrontMatter[] {
|
|
@@ -375,6 +449,7 @@ class TodoSelectorComponent extends Container implements Focusable {
|
|
|
375
449
|
const statusColor = closed ? "dim" : "success";
|
|
376
450
|
const tagText = todo.tags.length ? ` [${todo.tags.join(", ")}]` : "";
|
|
377
451
|
const assignmentText = renderAssignmentSuffix(this.theme, todo, this.currentSessionId);
|
|
452
|
+
const parentTaskText = todo.parent_task_id ? this.theme.fg("muted", ` ↳ ${todo.parent_task_id}`) : "";
|
|
378
453
|
const line =
|
|
379
454
|
prefix +
|
|
380
455
|
this.theme.fg("accent", formatTodoId(todo.id)) +
|
|
@@ -382,6 +457,7 @@ class TodoSelectorComponent extends Container implements Focusable {
|
|
|
382
457
|
this.theme.fg(titleColor, todo.title || "(untitled)") +
|
|
383
458
|
this.theme.fg("muted", tagText) +
|
|
384
459
|
assignmentText +
|
|
460
|
+
parentTaskText +
|
|
385
461
|
" " +
|
|
386
462
|
this.theme.fg(statusColor, `(${todo.status || "open"})`);
|
|
387
463
|
this.listContainer.addChild(new Text(line, 0, 0));
|
|
@@ -798,6 +874,7 @@ function parseFrontMatter(text: string, idFallback: string): TodoFrontMatter {
|
|
|
798
874
|
status: "open",
|
|
799
875
|
created_at: "",
|
|
800
876
|
assigned_to_session: undefined,
|
|
877
|
+
parent_task_id: undefined,
|
|
801
878
|
};
|
|
802
879
|
|
|
803
880
|
const trimmed = text.trim();
|
|
@@ -813,6 +890,9 @@ function parseFrontMatter(text: string, idFallback: string): TodoFrontMatter {
|
|
|
813
890
|
if (typeof parsed.assigned_to_session === "string" && parsed.assigned_to_session.trim()) {
|
|
814
891
|
data.assigned_to_session = parsed.assigned_to_session;
|
|
815
892
|
}
|
|
893
|
+
if (typeof parsed.parent_task_id === "string" && parsed.parent_task_id.trim()) {
|
|
894
|
+
data.parent_task_id = parsed.parent_task_id.trim();
|
|
895
|
+
}
|
|
816
896
|
if (Array.isArray(parsed.tags)) {
|
|
817
897
|
data.tags = parsed.tags.filter((tag): tag is string => typeof tag === "string");
|
|
818
898
|
}
|
|
@@ -890,6 +970,7 @@ function parseTodoContent(content: string, idFallback: string): TodoRecord {
|
|
|
890
970
|
status: parsed.status,
|
|
891
971
|
created_at: parsed.created_at,
|
|
892
972
|
assigned_to_session: parsed.assigned_to_session,
|
|
973
|
+
parent_task_id: parsed.parent_task_id,
|
|
893
974
|
body: body ?? "",
|
|
894
975
|
};
|
|
895
976
|
}
|
|
@@ -903,6 +984,7 @@ function serializeTodo(todo: TodoRecord): string {
|
|
|
903
984
|
status: todo.status,
|
|
904
985
|
created_at: todo.created_at,
|
|
905
986
|
assigned_to_session: todo.assigned_to_session || undefined,
|
|
987
|
+
parent_task_id: todo.parent_task_id || undefined,
|
|
906
988
|
},
|
|
907
989
|
null,
|
|
908
990
|
2,
|
|
@@ -1039,6 +1121,7 @@ async function listTodos(todosDir: string): Promise<TodoFrontMatter[]> {
|
|
|
1039
1121
|
status: parsed.status,
|
|
1040
1122
|
created_at: parsed.created_at,
|
|
1041
1123
|
assigned_to_session: parsed.assigned_to_session,
|
|
1124
|
+
parent_task_id: parsed.parent_task_id,
|
|
1042
1125
|
});
|
|
1043
1126
|
} catch {
|
|
1044
1127
|
// ignore unreadable todo
|
|
@@ -1072,6 +1155,7 @@ function listTodosSync(todosDir: string): TodoFrontMatter[] {
|
|
|
1072
1155
|
status: parsed.status,
|
|
1073
1156
|
created_at: parsed.created_at,
|
|
1074
1157
|
assigned_to_session: parsed.assigned_to_session,
|
|
1158
|
+
parent_task_id: parsed.parent_task_id,
|
|
1075
1159
|
});
|
|
1076
1160
|
} catch {
|
|
1077
1161
|
// ignore
|
|
@@ -1107,7 +1191,8 @@ function renderAssignmentSuffix(
|
|
|
1107
1191
|
|
|
1108
1192
|
function formatTodoHeading(todo: TodoFrontMatter): string {
|
|
1109
1193
|
const tagText = todo.tags.length ? ` [${todo.tags.join(", ")}]` : "";
|
|
1110
|
-
|
|
1194
|
+
const parentTaskText = todo.parent_task_id ? ` ↳ ${todo.parent_task_id}` : "";
|
|
1195
|
+
return `${formatTodoId(todo.id)} ${getTodoTitle(todo)}${tagText}${formatAssignmentSuffix(todo)}${parentTaskText}`;
|
|
1111
1196
|
}
|
|
1112
1197
|
|
|
1113
1198
|
function buildRefinePrompt(todoId: string, title: string): string {
|
|
@@ -1248,6 +1333,7 @@ function renderTodoDetail(theme: Theme, todo: TodoRecord, expanded: boolean): st
|
|
|
1248
1333
|
theme.fg("muted", `Status: ${getTodoStatus(todo)}`),
|
|
1249
1334
|
theme.fg("muted", `Tags: ${tags}`),
|
|
1250
1335
|
theme.fg("muted", `Created: ${createdAt}`),
|
|
1336
|
+
...(todo.parent_task_id ? [theme.fg("muted", `Parent task: ${todo.parent_task_id}`)] : []),
|
|
1251
1337
|
"",
|
|
1252
1338
|
theme.fg("muted", "Body:"),
|
|
1253
1339
|
...bodyLines.map((line) => theme.fg("text", ` ${line}`)),
|
|
@@ -1497,6 +1583,16 @@ export default function todosExtension(pi: ExtensionAPI) {
|
|
|
1497
1583
|
details: { action: "create", error: "title required" },
|
|
1498
1584
|
};
|
|
1499
1585
|
}
|
|
1586
|
+
let parentTaskId: string | undefined;
|
|
1587
|
+
try {
|
|
1588
|
+
parentTaskId = await validateParentTaskId(params.parentTaskId, pi, ctx);
|
|
1589
|
+
} catch (error) {
|
|
1590
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1591
|
+
return {
|
|
1592
|
+
content: [{ type: "text", text: message }],
|
|
1593
|
+
details: { action: "create", error: message },
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1500
1596
|
await ensureTodosDir(todosDir);
|
|
1501
1597
|
const id = await generateTodoId(todosDir);
|
|
1502
1598
|
const filePath = getTodoPath(todosDir, id);
|
|
@@ -1506,6 +1602,7 @@ export default function todosExtension(pi: ExtensionAPI) {
|
|
|
1506
1602
|
tags: params.tags ?? [],
|
|
1507
1603
|
status: params.status ?? "open",
|
|
1508
1604
|
created_at: new Date().toISOString(),
|
|
1605
|
+
parent_task_id: parentTaskId,
|
|
1509
1606
|
body: params.body ?? "",
|
|
1510
1607
|
};
|
|
1511
1608
|
|
|
@@ -1559,6 +1656,9 @@ export default function todosExtension(pi: ExtensionAPI) {
|
|
|
1559
1656
|
if (params.status !== undefined) {existing.status = params.status;}
|
|
1560
1657
|
if (params.tags !== undefined) {existing.tags = params.tags;}
|
|
1561
1658
|
if (params.body !== undefined) {existing.body = params.body;}
|
|
1659
|
+
if (params.parentTaskId !== undefined) {
|
|
1660
|
+
existing.parent_task_id = await validateParentTaskId(params.parentTaskId, pi, ctx);
|
|
1661
|
+
}
|
|
1562
1662
|
if (!existing.created_at) {existing.created_at = new Date().toISOString();}
|
|
1563
1663
|
clearAssignmentIfClosed(existing);
|
|
1564
1664
|
|