iosm-cli 0.2.3 → 0.2.5
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 +56 -0
- package/README.md +43 -10
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-profiles.d.ts +2 -1
- package/dist/core/agent-profiles.d.ts.map +1 -1
- package/dist/core/agent-profiles.js +18 -5
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +64 -15
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-teams.d.ts.map +1 -1
- package/dist/core/agent-teams.js +90 -19
- package/dist/core/agent-teams.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +6 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +9 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/orchestration-limits.d.ts +6 -0
- package/dist/core/orchestration-limits.d.ts.map +1 -0
- package/dist/core/orchestration-limits.js +6 -0
- package/dist/core/orchestration-limits.js.map +1 -0
- package/dist/core/parallel-task-agent.d.ts +23 -1
- package/dist/core/parallel-task-agent.d.ts.map +1 -1
- package/dist/core/parallel-task-agent.js +110 -20
- package/dist/core/parallel-task-agent.js.map +1 -1
- package/dist/core/sdk.d.ts +6 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +34 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/shared-memory.d.ts +2 -2
- package/dist/core/shared-memory.d.ts.map +1 -1
- package/dist/core/shared-memory.js +220 -91
- package/dist/core/shared-memory.js.map +1 -1
- package/dist/core/singular.d.ts.map +1 -1
- package/dist/core/singular.js +3 -1
- package/dist/core/singular.js.map +1 -1
- package/dist/core/subagents.d.ts +1 -1
- package/dist/core/subagents.d.ts.map +1 -1
- package/dist/core/subagents.js +32 -10
- package/dist/core/subagents.js.map +1 -1
- package/dist/core/swarm/planner.d.ts.map +1 -1
- package/dist/core/swarm/planner.js +200 -12
- package/dist/core/swarm/planner.js.map +1 -1
- package/dist/core/swarm/scheduler.d.ts +2 -0
- package/dist/core/swarm/scheduler.d.ts.map +1 -1
- package/dist/core/swarm/scheduler.js +87 -6
- package/dist/core/swarm/scheduler.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ast-grep.d.ts.map +1 -1
- package/dist/core/tools/ast-grep.js +2 -0
- package/dist/core/tools/ast-grep.js.map +1 -1
- package/dist/core/tools/edit.d.ts +8 -4
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +18 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/index.d.ts +9 -7
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/shared-memory.d.ts.map +1 -1
- package/dist/core/tools/shared-memory.js +34 -6
- package/dist/core/tools/shared-memory.js.map +1 -1
- package/dist/core/tools/task.d.ts +10 -3
- package/dist/core/tools/task.d.ts.map +1 -1
- package/dist/core/tools/task.js +830 -184
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/todo.d.ts +10 -10
- package/dist/core/tools/todo.d.ts.map +1 -1
- package/dist/core/tools/todo.js +135 -17
- package/dist/core/tools/todo.js.map +1 -1
- package/dist/core/tools/yq.d.ts.map +1 -1
- package/dist/core/tools/yq.js +2 -0
- package/dist/core/tools/yq.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +10 -9
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +22 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +957 -75
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/cli-reference.md +8 -0
- package/docs/configuration.md +5 -1
- package/docs/interactive-mode.md +7 -1
- package/docs/orchestration-and-subagents.md +5 -0
- package/package.json +1 -1
|
@@ -15,13 +15,13 @@ export interface TodoTask {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function getTaskFilePath(cwd: string): string;
|
|
17
17
|
declare const todoWriteSchema: import("@sinclair/typebox").TObject<{
|
|
18
|
-
tasks: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
19
|
-
id: import("@sinclair/typebox").TString
|
|
20
|
-
subject: import("@sinclair/typebox").TString
|
|
18
|
+
tasks: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
19
|
+
id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
20
|
+
subject: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
21
21
|
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
22
|
-
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"in_progress">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"deleted">]
|
|
22
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"in_progress">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"deleted">]>>;
|
|
23
23
|
activeForm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
24
|
-
}>>;
|
|
24
|
+
}>>, import("@sinclair/typebox").TString]>>;
|
|
25
25
|
}>;
|
|
26
26
|
export type TodoWriteInput = Static<typeof todoWriteSchema>;
|
|
27
27
|
declare const todoReadSchema: import("@sinclair/typebox").TObject<{}>;
|
|
@@ -29,13 +29,13 @@ export type TodoReadInput = Static<typeof todoReadSchema>;
|
|
|
29
29
|
export declare function createTodoWriteTool(cwd: string): AgentTool<typeof todoWriteSchema>;
|
|
30
30
|
export declare function createTodoReadTool(cwd: string): AgentTool<typeof todoReadSchema>;
|
|
31
31
|
export declare const todoWriteTool: AgentTool<import("@sinclair/typebox").TObject<{
|
|
32
|
-
tasks: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
33
|
-
id: import("@sinclair/typebox").TString
|
|
34
|
-
subject: import("@sinclair/typebox").TString
|
|
32
|
+
tasks: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
33
|
+
id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
34
|
+
subject: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
35
35
|
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
36
|
-
status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"in_progress">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"deleted">]
|
|
36
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"pending">, import("@sinclair/typebox").TLiteral<"in_progress">, import("@sinclair/typebox").TLiteral<"completed">, import("@sinclair/typebox").TLiteral<"deleted">]>>;
|
|
37
37
|
activeForm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
38
|
-
}>>;
|
|
38
|
+
}>>, import("@sinclair/typebox").TString]>>;
|
|
39
39
|
}>, any>;
|
|
40
40
|
export declare const todoReadTool: AgentTool<import("@sinclair/typebox").TObject<{}>, any>;
|
|
41
41
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAMtD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAErE,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAMtD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAErE,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD;AAgED,QAAA,MAAM,eAAe;;;;;;;;EAmBnB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAE5D,QAAA,MAAM,cAAc,yCAAkB,CAAC;AACvC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAwH1D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,eAAe,CAAC,CAkElF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,cAAc,CAAC,CAuChF;AAGD,eAAO,MAAM,aAAa;;;;;;;;QAAqC,CAAC;AAChE,eAAO,MAAM,YAAY,yDAAoC,CAAC"}
|
package/dist/core/tools/todo.js
CHANGED
|
@@ -46,25 +46,130 @@ function countByStatus(tasks) {
|
|
|
46
46
|
// ============================================================================
|
|
47
47
|
// Schemas
|
|
48
48
|
// ============================================================================
|
|
49
|
+
const todoTaskUpdateSchema = Type.Object({
|
|
50
|
+
id: Type.Optional(Type.String({ description: "Unique task identifier (e.g. '1', 'setup-db')" })),
|
|
51
|
+
subject: Type.Optional(Type.String({
|
|
52
|
+
description: "Brief imperative title (e.g. 'Fix auth bug', 'Add tests')",
|
|
53
|
+
})),
|
|
54
|
+
description: Type.Optional(Type.String({ description: "Detailed description of what needs to be done" })),
|
|
55
|
+
status: Type.Optional(Type.Union([
|
|
56
|
+
Type.Literal("pending"),
|
|
57
|
+
Type.Literal("in_progress"),
|
|
58
|
+
Type.Literal("completed"),
|
|
59
|
+
Type.Literal("deleted"),
|
|
60
|
+
], { description: "Task status. Use 'deleted' to remove a task." })),
|
|
61
|
+
activeForm: Type.Optional(Type.String({
|
|
62
|
+
description: "Present continuous form shown while in_progress (e.g. 'Fixing auth bug')",
|
|
63
|
+
})),
|
|
64
|
+
});
|
|
49
65
|
const todoWriteSchema = Type.Object({
|
|
50
|
-
tasks: Type.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
tasks: Type.Optional(Type.Union([
|
|
67
|
+
Type.Array(todoTaskUpdateSchema, {
|
|
68
|
+
description: "Tasks to create or update. Merged with existing list by id. Missing id/subject fields are derived automatically.",
|
|
69
|
+
}),
|
|
70
|
+
Type.String({
|
|
71
|
+
description: "Markdown checklist string (for example '- [in_progress] Audit auth'). Parsed into task objects automatically.",
|
|
54
72
|
}),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Type.Literal("in_progress"),
|
|
59
|
-
Type.Literal("completed"),
|
|
60
|
-
Type.Literal("deleted"),
|
|
61
|
-
], { description: "Task status. Use 'deleted' to remove a task." }),
|
|
62
|
-
activeForm: Type.Optional(Type.String({
|
|
63
|
-
description: "Present continuous form shown while in_progress (e.g. 'Fixing auth bug')",
|
|
64
|
-
})),
|
|
65
|
-
}), { description: "Tasks to create or update. Merged with existing list by id." }),
|
|
73
|
+
], {
|
|
74
|
+
description: "Task updates as either an array of task objects or a markdown checklist string.",
|
|
75
|
+
})),
|
|
66
76
|
});
|
|
67
77
|
const todoReadSchema = Type.Object({});
|
|
78
|
+
function slugifyTaskId(text, fallback) {
|
|
79
|
+
const slug = text
|
|
80
|
+
.trim()
|
|
81
|
+
.toLowerCase()
|
|
82
|
+
.replace(/['"`]/g, "")
|
|
83
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
84
|
+
.replace(/^-+|-+$/g, "");
|
|
85
|
+
return slug || fallback;
|
|
86
|
+
}
|
|
87
|
+
function normalizeTodoStatus(raw) {
|
|
88
|
+
if (!raw)
|
|
89
|
+
return "pending";
|
|
90
|
+
const normalized = raw.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
91
|
+
if (normalized === "done" ||
|
|
92
|
+
normalized === "complete" ||
|
|
93
|
+
normalized === "completed" ||
|
|
94
|
+
normalized === "x" ||
|
|
95
|
+
normalized === "checked") {
|
|
96
|
+
return "completed";
|
|
97
|
+
}
|
|
98
|
+
if (normalized === "in_progress" ||
|
|
99
|
+
normalized === "inprogress" ||
|
|
100
|
+
normalized === "doing" ||
|
|
101
|
+
normalized === "active" ||
|
|
102
|
+
normalized === "~") {
|
|
103
|
+
return "in_progress";
|
|
104
|
+
}
|
|
105
|
+
if (normalized === "deleted" || normalized === "delete" || normalized === "removed") {
|
|
106
|
+
return "deleted";
|
|
107
|
+
}
|
|
108
|
+
return "pending";
|
|
109
|
+
}
|
|
110
|
+
function nextUniqueId(baseId, usedIds) {
|
|
111
|
+
let candidate = baseId;
|
|
112
|
+
let suffix = 2;
|
|
113
|
+
while (usedIds.has(candidate)) {
|
|
114
|
+
candidate = `${baseId}-${suffix}`;
|
|
115
|
+
suffix += 1;
|
|
116
|
+
}
|
|
117
|
+
usedIds.add(candidate);
|
|
118
|
+
return candidate;
|
|
119
|
+
}
|
|
120
|
+
function parseMarkdownTaskUpdates(markdown) {
|
|
121
|
+
const lines = markdown
|
|
122
|
+
.split(/\r?\n/g)
|
|
123
|
+
.map((line) => line.trim())
|
|
124
|
+
.filter((line) => line.length > 0);
|
|
125
|
+
const parsed = [];
|
|
126
|
+
for (const line of lines) {
|
|
127
|
+
const checklistMatch = line.match(/^(?:[-*]|\d+[.)])\s*\[([^\]]+)\]\s+(.+)$/) ?? line.match(/^\[([^\]]+)\]\s+(.+)$/);
|
|
128
|
+
if (checklistMatch) {
|
|
129
|
+
parsed.push({
|
|
130
|
+
status: normalizeTodoStatus(checklistMatch[1]),
|
|
131
|
+
subject: checklistMatch[2]?.trim(),
|
|
132
|
+
description: checklistMatch[2]?.trim(),
|
|
133
|
+
});
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const bulletMatch = line.match(/^(?:[-*]|\d+[.)])\s+(.+)$/);
|
|
137
|
+
if (bulletMatch) {
|
|
138
|
+
parsed.push({
|
|
139
|
+
status: "pending",
|
|
140
|
+
subject: bulletMatch[1]?.trim(),
|
|
141
|
+
description: bulletMatch[1]?.trim(),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
function normalizeTaskUpdates(input) {
|
|
148
|
+
if (input === undefined)
|
|
149
|
+
return [];
|
|
150
|
+
const rawTasks = typeof input === "string" ? parseMarkdownTaskUpdates(input) : input;
|
|
151
|
+
const usedDerivedIds = new Set();
|
|
152
|
+
const normalized = [];
|
|
153
|
+
for (let index = 0; index < rawTasks.length; index += 1) {
|
|
154
|
+
const item = rawTasks[index];
|
|
155
|
+
if (!item)
|
|
156
|
+
continue;
|
|
157
|
+
const subject = item.subject?.trim() || item.description?.trim() || item.id?.trim() || `Task ${index + 1}`;
|
|
158
|
+
if (!subject)
|
|
159
|
+
continue;
|
|
160
|
+
const explicitId = item.id?.trim();
|
|
161
|
+
const derivedBaseId = slugifyTaskId(subject, `task-${index + 1}`);
|
|
162
|
+
const id = explicitId || nextUniqueId(derivedBaseId, usedDerivedIds);
|
|
163
|
+
normalized.push({
|
|
164
|
+
id,
|
|
165
|
+
subject,
|
|
166
|
+
description: item.description?.trim() || undefined,
|
|
167
|
+
status: normalizeTodoStatus(item.status),
|
|
168
|
+
activeForm: item.activeForm?.trim() || undefined,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return normalized;
|
|
172
|
+
}
|
|
68
173
|
// ============================================================================
|
|
69
174
|
// Factories (capture cwd in closure — matches codebase tool pattern)
|
|
70
175
|
// ============================================================================
|
|
@@ -72,15 +177,28 @@ export function createTodoWriteTool(cwd) {
|
|
|
72
177
|
return {
|
|
73
178
|
name: "todo_write",
|
|
74
179
|
label: "todo_write",
|
|
75
|
-
description: "Create or update the session task list. Use to track progress on multi-step work. Tasks persist across turns. Mark tasks in_progress before starting, completed when done.",
|
|
180
|
+
description: "Create or update the session task list. Use to track progress on multi-step work. Tasks persist across turns. Mark tasks in_progress before starting, completed when done. Accepts either an array of task objects or a markdown checklist string.",
|
|
76
181
|
parameters: todoWriteSchema,
|
|
77
182
|
execute: async (_toolCallId, params, _signal) => {
|
|
78
183
|
const input = params;
|
|
79
184
|
const filePath = getTaskFilePath(cwd);
|
|
80
185
|
const existing = readTasks(filePath);
|
|
186
|
+
const normalizedTasks = normalizeTaskUpdates(input.tasks);
|
|
187
|
+
if (normalizedTasks.length === 0) {
|
|
188
|
+
const counts = countByStatus(existing);
|
|
189
|
+
return {
|
|
190
|
+
content: [
|
|
191
|
+
{
|
|
192
|
+
type: "text",
|
|
193
|
+
text: "No task updates provided. Pass tasks as an array or markdown checklist string.",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
details: { tasks: existing, counts },
|
|
197
|
+
};
|
|
198
|
+
}
|
|
81
199
|
// Merge: patch by id
|
|
82
200
|
const taskMap = new Map(existing.map((t) => [t.id, t]));
|
|
83
|
-
for (const incoming of
|
|
201
|
+
for (const incoming of normalizedTasks) {
|
|
84
202
|
if (incoming.status === "deleted") {
|
|
85
203
|
taskMap.delete(incoming.id);
|
|
86
204
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"todo.js","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TodoTaskStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface TodoTask {\n\tid: string;\n\tsubject: string;\n\tdescription?: string;\n\tstatus: TodoTaskStatus;\n\t/** Present continuous form shown while in_progress, e.g. \"Fixing auth bug\" */\n\tactiveForm?: string;\n}\n\n// ============================================================================\n// Path helper\n// ============================================================================\n\n/**\n * Returns the path to the session task file for a given working directory.\n * Uses a hash of the cwd so each project has its own task list.\n */\nexport function getTaskFilePath(cwd: string): string {\n\tconst hash = createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n\treturn join(homedir(), \".iosm\", \"agent\", \"tasks\", `${hash}.json`);\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction readTasks(filePath: string): TodoTask[] {\n\tif (!existsSync(filePath)) return [];\n\ttry {\n\t\tconst raw = readFileSync(filePath, \"utf8\");\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (Array.isArray(parsed)) return parsed as TodoTask[];\n\t\treturn [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction writeTasks(filePath: string, tasks: TodoTask[]): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n\twriteFileSync(filePath, JSON.stringify(tasks, null, 2), \"utf8\");\n}\n\nfunction countByStatus(tasks: TodoTask[]): Record<TodoTaskStatus, number> {\n\tconst counts: Record<TodoTaskStatus, number> = { pending: 0, in_progress: 0, completed: 0 };\n\tfor (const t of tasks) {\n\t\tif (t.status in counts) counts[t.status as TodoTaskStatus]++;\n\t}\n\treturn counts;\n}\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nconst todoWriteSchema = Type.Object({\n\ttasks: Type.Array(\n\t\tType.Object({\n\t\t\tid: Type.String({ description: \"Unique task identifier (e.g. '1', 'setup-db')\" }),\n\t\t\tsubject: Type.String({\n\t\t\t\tdescription: \"Brief imperative title (e.g. 'Fix auth bug', 'Add tests')\",\n\t\t\t}),\n\t\t\tdescription: Type.Optional(\n\t\t\t\tType.String({ description: \"Detailed description of what needs to be done\" }),\n\t\t\t),\n\t\t\tstatus: Type.Union(\n\t\t\t\t[\n\t\t\t\t\tType.Literal(\"pending\"),\n\t\t\t\t\tType.Literal(\"in_progress\"),\n\t\t\t\t\tType.Literal(\"completed\"),\n\t\t\t\t\tType.Literal(\"deleted\"),\n\t\t\t\t],\n\t\t\t\t{ description: \"Task status. Use 'deleted' to remove a task.\" },\n\t\t\t),\n\t\t\tactiveForm: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Present continuous form shown while in_progress (e.g. 'Fixing auth bug')\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"Tasks to create or update. Merged with existing list by id.\" },\n\t),\n});\n\nexport type TodoWriteInput = Static<typeof todoWriteSchema>;\n\nconst todoReadSchema = Type.Object({});\nexport type TodoReadInput = Static<typeof todoReadSchema>;\n\n// ============================================================================\n// Factories (capture cwd in closure — matches codebase tool pattern)\n// ============================================================================\n\nexport function createTodoWriteTool(cwd: string): AgentTool<typeof todoWriteSchema> {\n\treturn {\n\t\tname: \"todo_write\",\n\t\tlabel: \"todo_write\",\n\t\tdescription:\n\t\t\t\"Create or update the session task list. Use to track progress on multi-step work. Tasks persist across turns. Mark tasks in_progress before starting, completed when done.\",\n\t\tparameters: todoWriteSchema,\n\t\texecute: async (_toolCallId: string, params: unknown, _signal?: AbortSignal) => {\n\t\t\tconst input = params as TodoWriteInput;\n\t\t\tconst filePath = getTaskFilePath(cwd);\n\t\t\tconst existing = readTasks(filePath);\n\n\t\t\t// Merge: patch by id\n\t\t\tconst taskMap = new Map<string, TodoTask>(existing.map((t) => [t.id, t]));\n\n\t\t\tfor (const incoming of input.tasks) {\n\t\t\t\tif (incoming.status === \"deleted\") {\n\t\t\t\t\ttaskMap.delete(incoming.id);\n\t\t\t\t} else {\n\t\t\t\t\tconst current = taskMap.get(incoming.id);\n\t\t\t\t\ttaskMap.set(incoming.id, {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\tid: incoming.id,\n\t\t\t\t\t\tsubject: incoming.subject,\n\t\t\t\t\t\tdescription: incoming.description ?? current?.description,\n\t\t\t\t\t\tstatus: incoming.status as TodoTaskStatus,\n\t\t\t\t\t\tactiveForm: incoming.activeForm ?? current?.activeForm,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst updated = Array.from(taskMap.values());\n\t\t\twriteTasks(filePath, updated);\n\n\t\t\tconst counts = countByStatus(updated);\n\t\t\tconst parts: string[] = [];\n\t\t\tif (counts.in_progress > 0) parts.push(`${counts.in_progress} in_progress`);\n\t\t\tif (counts.pending > 0) parts.push(`${counts.pending} pending`);\n\t\t\tif (counts.completed > 0) parts.push(`${counts.completed} completed`);\n\n\t\t\tconst summary = parts.length > 0 ? parts.join(\", \") : \"no active tasks\";\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `Task list updated (${updated.length} total: ${summary})`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { tasks: updated, counts },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createTodoReadTool(cwd: string): AgentTool<typeof todoReadSchema> {\n\treturn {\n\t\tname: \"todo_read\",\n\t\tlabel: \"todo_read\",\n\t\tdescription: \"Read the current session task list. Returns all tasks with their status.\",\n\t\tparameters: todoReadSchema,\n\t\texecute: async (_toolCallId: string, _params: unknown, _signal?: AbortSignal) => {\n\t\t\tconst filePath = getTaskFilePath(cwd);\n\t\t\tconst tasks = readTasks(filePath);\n\n\t\t\tif (tasks.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: \"No tasks yet.\" }],\n\t\t\t\t\tdetails: { tasks: [] },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst statusIcon: Record<string, string> = {\n\t\t\t\tpending: \"[ ]\",\n\t\t\t\tin_progress: \"[~]\",\n\t\t\t\tcompleted: \"[x]\",\n\t\t\t};\n\n\t\t\tconst counts = countByStatus(tasks);\n\t\t\tconst header = `Tasks (${tasks.length} total: ${counts.in_progress} in_progress, ${counts.pending} pending, ${counts.completed} completed)`;\n\n\t\t\tconst lines = tasks.map((t) => {\n\t\t\t\tconst icon = statusIcon[t.status] ?? \"[ ]\";\n\t\t\t\tconst active =\n\t\t\t\t\tt.status === \"in_progress\" && t.activeForm ? ` — ${t.activeForm}` : \"\";\n\t\t\t\treturn `${icon} [${t.id}] ${t.subject}${active}`;\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: [header, ...lines].join(\"\\n\") }],\n\t\t\t\tdetails: { tasks, counts },\n\t\t\t};\n\t\t},\n\t};\n}\n\n// Pre-built instances using process.cwd() — for allTools registry\nexport const todoWriteTool = createTodoWriteTool(process.cwd());\nexport const todoReadTool = createTodoReadTool(process.cwd());\n"]}
|
|
1
|
+
{"version":3,"file":"todo.js","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TodoTaskStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface TodoTask {\n\tid: string;\n\tsubject: string;\n\tdescription?: string;\n\tstatus: TodoTaskStatus;\n\t/** Present continuous form shown while in_progress, e.g. \"Fixing auth bug\" */\n\tactiveForm?: string;\n}\n\ntype TodoTaskUpdateStatus = TodoTaskStatus | \"deleted\";\n\ninterface TodoTaskUpdateInput {\n\tid?: string;\n\tsubject?: string;\n\tdescription?: string;\n\tstatus?: TodoTaskUpdateStatus;\n\tactiveForm?: string;\n}\n\n// ============================================================================\n// Path helper\n// ============================================================================\n\n/**\n * Returns the path to the session task file for a given working directory.\n * Uses a hash of the cwd so each project has its own task list.\n */\nexport function getTaskFilePath(cwd: string): string {\n\tconst hash = createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n\treturn join(homedir(), \".iosm\", \"agent\", \"tasks\", `${hash}.json`);\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction readTasks(filePath: string): TodoTask[] {\n\tif (!existsSync(filePath)) return [];\n\ttry {\n\t\tconst raw = readFileSync(filePath, \"utf8\");\n\t\tconst parsed = JSON.parse(raw);\n\t\tif (Array.isArray(parsed)) return parsed as TodoTask[];\n\t\treturn [];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction writeTasks(filePath: string, tasks: TodoTask[]): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n\twriteFileSync(filePath, JSON.stringify(tasks, null, 2), \"utf8\");\n}\n\nfunction countByStatus(tasks: TodoTask[]): Record<TodoTaskStatus, number> {\n\tconst counts: Record<TodoTaskStatus, number> = { pending: 0, in_progress: 0, completed: 0 };\n\tfor (const t of tasks) {\n\t\tif (t.status in counts) counts[t.status as TodoTaskStatus]++;\n\t}\n\treturn counts;\n}\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nconst todoTaskUpdateSchema = Type.Object({\n\tid: Type.Optional(Type.String({ description: \"Unique task identifier (e.g. '1', 'setup-db')\" })),\n\tsubject: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Brief imperative title (e.g. 'Fix auth bug', 'Add tests')\",\n\t\t}),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({ description: \"Detailed description of what needs to be done\" }),\n\t),\n\tstatus: Type.Optional(\n\t\tType.Union(\n\t\t\t[\n\t\t\t\tType.Literal(\"pending\"),\n\t\t\t\tType.Literal(\"in_progress\"),\n\t\t\t\tType.Literal(\"completed\"),\n\t\t\t\tType.Literal(\"deleted\"),\n\t\t\t],\n\t\t\t{ description: \"Task status. Use 'deleted' to remove a task.\" },\n\t\t),\n\t),\n\tactiveForm: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Present continuous form shown while in_progress (e.g. 'Fixing auth bug')\",\n\t\t}),\n\t),\n});\n\nconst todoWriteSchema = Type.Object({\n\ttasks: Type.Optional(\n\t\tType.Union(\n\t\t\t[\n\t\t\t\tType.Array(todoTaskUpdateSchema, {\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Tasks to create or update. Merged with existing list by id. Missing id/subject fields are derived automatically.\",\n\t\t\t\t}),\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Markdown checklist string (for example '- [in_progress] Audit auth'). Parsed into task objects automatically.\",\n\t\t\t\t}),\n\t\t\t],\n\t\t\t{\n\t\t\t\tdescription:\n\t\t\t\t\t\"Task updates as either an array of task objects or a markdown checklist string.\",\n\t\t\t},\n\t\t),\n\t),\n});\n\nexport type TodoWriteInput = Static<typeof todoWriteSchema>;\n\nconst todoReadSchema = Type.Object({});\nexport type TodoReadInput = Static<typeof todoReadSchema>;\n\nfunction slugifyTaskId(text: string, fallback: string): string {\n\tconst slug = text\n\t\t.trim()\n\t\t.toLowerCase()\n\t\t.replace(/['\"`]/g, \"\")\n\t\t.replace(/[^a-z0-9]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\");\n\treturn slug || fallback;\n}\n\nfunction normalizeTodoStatus(raw: string | undefined): TodoTaskUpdateStatus {\n\tif (!raw) return \"pending\";\n\tconst normalized = raw.trim().toLowerCase().replace(/[\\s-]+/g, \"_\");\n\tif (\n\t\tnormalized === \"done\" ||\n\t\tnormalized === \"complete\" ||\n\t\tnormalized === \"completed\" ||\n\t\tnormalized === \"x\" ||\n\t\tnormalized === \"checked\"\n\t) {\n\t\treturn \"completed\";\n\t}\n\tif (\n\t\tnormalized === \"in_progress\" ||\n\t\tnormalized === \"inprogress\" ||\n\t\tnormalized === \"doing\" ||\n\t\tnormalized === \"active\" ||\n\t\tnormalized === \"~\"\n\t) {\n\t\treturn \"in_progress\";\n\t}\n\tif (normalized === \"deleted\" || normalized === \"delete\" || normalized === \"removed\") {\n\t\treturn \"deleted\";\n\t}\n\treturn \"pending\";\n}\n\nfunction nextUniqueId(baseId: string, usedIds: Set<string>): string {\n\tlet candidate = baseId;\n\tlet suffix = 2;\n\twhile (usedIds.has(candidate)) {\n\t\tcandidate = `${baseId}-${suffix}`;\n\t\tsuffix += 1;\n\t}\n\tusedIds.add(candidate);\n\treturn candidate;\n}\n\nfunction parseMarkdownTaskUpdates(markdown: string): TodoTaskUpdateInput[] {\n\tconst lines = markdown\n\t\t.split(/\\r?\\n/g)\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0);\n\tconst parsed: TodoTaskUpdateInput[] = [];\n\tfor (const line of lines) {\n\t\tconst checklistMatch =\n\t\t\tline.match(/^(?:[-*]|\\d+[.)])\\s*\\[([^\\]]+)\\]\\s+(.+)$/) ?? line.match(/^\\[([^\\]]+)\\]\\s+(.+)$/);\n\t\tif (checklistMatch) {\n\t\t\tparsed.push({\n\t\t\t\tstatus: normalizeTodoStatus(checklistMatch[1]),\n\t\t\t\tsubject: checklistMatch[2]?.trim(),\n\t\t\t\tdescription: checklistMatch[2]?.trim(),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst bulletMatch = line.match(/^(?:[-*]|\\d+[.)])\\s+(.+)$/);\n\t\tif (bulletMatch) {\n\t\t\tparsed.push({\n\t\t\t\tstatus: \"pending\",\n\t\t\t\tsubject: bulletMatch[1]?.trim(),\n\t\t\t\tdescription: bulletMatch[1]?.trim(),\n\t\t\t});\n\t\t}\n\t}\n\treturn parsed;\n}\n\nfunction normalizeTaskUpdates(input: TodoWriteInput[\"tasks\"]): Array<{\n\tid: string;\n\tsubject: string;\n\tdescription?: string;\n\tstatus: TodoTaskUpdateStatus;\n\tactiveForm?: string;\n}> {\n\tif (input === undefined) return [];\n\tconst rawTasks = typeof input === \"string\" ? parseMarkdownTaskUpdates(input) : input;\n\tconst usedDerivedIds = new Set<string>();\n\tconst normalized: Array<{\n\t\tid: string;\n\t\tsubject: string;\n\t\tdescription?: string;\n\t\tstatus: TodoTaskUpdateStatus;\n\t\tactiveForm?: string;\n\t}> = [];\n\tfor (let index = 0; index < rawTasks.length; index += 1) {\n\t\tconst item = rawTasks[index];\n\t\tif (!item) continue;\n\t\tconst subject = item.subject?.trim() || item.description?.trim() || item.id?.trim() || `Task ${index + 1}`;\n\t\tif (!subject) continue;\n\t\tconst explicitId = item.id?.trim();\n\t\tconst derivedBaseId = slugifyTaskId(subject, `task-${index + 1}`);\n\t\tconst id = explicitId || nextUniqueId(derivedBaseId, usedDerivedIds);\n\t\tnormalized.push({\n\t\t\tid,\n\t\t\tsubject,\n\t\t\tdescription: item.description?.trim() || undefined,\n\t\t\tstatus: normalizeTodoStatus(item.status),\n\t\t\tactiveForm: item.activeForm?.trim() || undefined,\n\t\t});\n\t}\n\treturn normalized;\n}\n\n// ============================================================================\n// Factories (capture cwd in closure — matches codebase tool pattern)\n// ============================================================================\n\nexport function createTodoWriteTool(cwd: string): AgentTool<typeof todoWriteSchema> {\n\treturn {\n\t\tname: \"todo_write\",\n\t\tlabel: \"todo_write\",\n\t\tdescription:\n\t\t\t\"Create or update the session task list. Use to track progress on multi-step work. Tasks persist across turns. Mark tasks in_progress before starting, completed when done. Accepts either an array of task objects or a markdown checklist string.\",\n\t\tparameters: todoWriteSchema,\n\t\texecute: async (_toolCallId: string, params: unknown, _signal?: AbortSignal) => {\n\t\t\tconst input = params as TodoWriteInput;\n\t\t\tconst filePath = getTaskFilePath(cwd);\n\t\t\tconst existing = readTasks(filePath);\n\t\t\tconst normalizedTasks = normalizeTaskUpdates(input.tasks);\n\n\t\t\tif (normalizedTasks.length === 0) {\n\t\t\t\tconst counts = countByStatus(existing);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: \"No task updates provided. Pass tasks as an array or markdown checklist string.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { tasks: existing, counts },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Merge: patch by id\n\t\t\tconst taskMap = new Map<string, TodoTask>(existing.map((t) => [t.id, t]));\n\n\t\t\tfor (const incoming of normalizedTasks) {\n\t\t\t\tif (incoming.status === \"deleted\") {\n\t\t\t\t\ttaskMap.delete(incoming.id);\n\t\t\t\t} else {\n\t\t\t\t\tconst current = taskMap.get(incoming.id);\n\t\t\t\t\ttaskMap.set(incoming.id, {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\tid: incoming.id,\n\t\t\t\t\t\tsubject: incoming.subject,\n\t\t\t\t\t\tdescription: incoming.description ?? current?.description,\n\t\t\t\t\t\tstatus: incoming.status as TodoTaskStatus,\n\t\t\t\t\t\tactiveForm: incoming.activeForm ?? current?.activeForm,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst updated = Array.from(taskMap.values());\n\t\t\twriteTasks(filePath, updated);\n\n\t\t\tconst counts = countByStatus(updated);\n\t\t\tconst parts: string[] = [];\n\t\t\tif (counts.in_progress > 0) parts.push(`${counts.in_progress} in_progress`);\n\t\t\tif (counts.pending > 0) parts.push(`${counts.pending} pending`);\n\t\t\tif (counts.completed > 0) parts.push(`${counts.completed} completed`);\n\n\t\t\tconst summary = parts.length > 0 ? parts.join(\", \") : \"no active tasks\";\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `Task list updated (${updated.length} total: ${summary})`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { tasks: updated, counts },\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport function createTodoReadTool(cwd: string): AgentTool<typeof todoReadSchema> {\n\treturn {\n\t\tname: \"todo_read\",\n\t\tlabel: \"todo_read\",\n\t\tdescription: \"Read the current session task list. Returns all tasks with their status.\",\n\t\tparameters: todoReadSchema,\n\t\texecute: async (_toolCallId: string, _params: unknown, _signal?: AbortSignal) => {\n\t\t\tconst filePath = getTaskFilePath(cwd);\n\t\t\tconst tasks = readTasks(filePath);\n\n\t\t\tif (tasks.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: \"No tasks yet.\" }],\n\t\t\t\t\tdetails: { tasks: [] },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst statusIcon: Record<string, string> = {\n\t\t\t\tpending: \"[ ]\",\n\t\t\t\tin_progress: \"[~]\",\n\t\t\t\tcompleted: \"[x]\",\n\t\t\t};\n\n\t\t\tconst counts = countByStatus(tasks);\n\t\t\tconst header = `Tasks (${tasks.length} total: ${counts.in_progress} in_progress, ${counts.pending} pending, ${counts.completed} completed)`;\n\n\t\t\tconst lines = tasks.map((t) => {\n\t\t\t\tconst icon = statusIcon[t.status] ?? \"[ ]\";\n\t\t\t\tconst active =\n\t\t\t\t\tt.status === \"in_progress\" && t.activeForm ? ` — ${t.activeForm}` : \"\";\n\t\t\t\treturn `${icon} [${t.id}] ${t.subject}${active}`;\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: [header, ...lines].join(\"\\n\") }],\n\t\t\t\tdetails: { tasks, counts },\n\t\t\t};\n\t\t},\n\t};\n}\n\n// Pre-built instances using process.cwd() — for allTools registry\nexport const todoWriteTool = createTodoWriteTool(process.cwd());\nexport const todoReadTool = createTodoReadTool(process.cwd());\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yq.d.ts","sourceRoot":"","sources":["../../../src/core/tools/yq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE3D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"yq.d.ts","sourceRoot":"","sources":["../../../src/core/tools/yq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE3D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,CAU7E;AAED,eAAO,MAAM,MAAM;;;;;QAA8B,CAAC"}
|
package/dist/core/tools/yq.js
CHANGED
|
@@ -6,6 +6,8 @@ export function createYqTool(cwd) {
|
|
|
6
6
|
description: "Run yq for YAML/JSON/TOML querying/transformation. Pass CLI arguments directly, optionally with stdin.",
|
|
7
7
|
commandCandidates: ["yq"],
|
|
8
8
|
missingInstallHint: "Install yq (brew install yq).",
|
|
9
|
+
forbiddenArgs: ["-i", "--inplace", "--in-place", "-s", "--split-exp", "--split-exp-file"],
|
|
10
|
+
forbiddenArgPrefixes: ["-i", "--inplace", "--in-place", "--split-exp=", "--split-exp-file="],
|
|
9
11
|
});
|
|
10
12
|
}
|
|
11
13
|
export const yqTool = createYqTool(process.cwd());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yq.js","sourceRoot":"","sources":["../../../src/core/tools/yq.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAI7E,MAAM,UAAU,YAAY,CAAC,GAAW;IACvC,OAAO,qBAAqB,CAAC,GAAG,EAAE;QACjC,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,wGAAwG;QACrH,iBAAiB,EAAE,CAAC,IAAI,CAAC;QACzB,kBAAkB,EAAE,+BAA+B;
|
|
1
|
+
{"version":3,"file":"yq.js","sourceRoot":"","sources":["../../../src/core/tools/yq.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAI7E,MAAM,UAAU,YAAY,CAAC,GAAW;IACvC,OAAO,qBAAqB,CAAC,GAAG,EAAE;QACjC,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,wGAAwG;QACrH,iBAAiB,EAAE,CAAC,IAAI,CAAC;QACzB,kBAAkB,EAAE,+BAA+B;QACnD,aAAa,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,kBAAkB,CAAC;QACzF,oBAAoB,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,mBAAmB,CAAC;KAC5F,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { Static } from \"@sinclair/typebox\";\nimport { createExternalCliTool, externalCliSchema } from \"./external-cli.js\";\n\nexport type YqToolInput = Static<typeof externalCliSchema>;\n\nexport function createYqTool(cwd: string): AgentTool<typeof externalCliSchema> {\n\treturn createExternalCliTool(cwd, {\n\t\tname: \"yq\",\n\t\tlabel: \"yq\",\n\t\tdescription: \"Run yq for YAML/JSON/TOML querying/transformation. Pass CLI arguments directly, optionally with stdin.\",\n\t\tcommandCandidates: [\"yq\"],\n\t\tmissingInstallHint: \"Install yq (brew install yq).\",\n\t\tforbiddenArgs: [\"-i\", \"--inplace\", \"--in-place\", \"-s\", \"--split-exp\", \"--split-exp-file\"],\n\t\tforbiddenArgPrefixes: [\"-i\", \"--inplace\", \"--in-place\", \"--split-exp=\", \"--split-exp-file=\"],\n\t});\n}\n\nexport const yqTool = createYqTool(process.cwd());\n"]}
|
|
@@ -15,7 +15,7 @@ export declare class FooterComponent implements Component {
|
|
|
15
15
|
setAutoCompactEnabled(enabled: boolean): void;
|
|
16
16
|
/**
|
|
17
17
|
* Toggle plan-mode badge in the status line.
|
|
18
|
-
* When enabled, a [
|
|
18
|
+
* When enabled, a [plan] badge is prepended before the session state badge.
|
|
19
19
|
*/
|
|
20
20
|
setPlanMode(enabled: boolean): void;
|
|
21
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAyDxF;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAM/C,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IANnB,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAM;gBAGlB,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,0BAA0B;IAG/C,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIvC;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAyDxF;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAM/C,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IANnB,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAM;gBAGlB,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,0BAA0B;IAG/C,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAInC;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIvC;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAiM/B"}
|
|
@@ -73,7 +73,7 @@ export class FooterComponent {
|
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Toggle plan-mode badge in the status line.
|
|
76
|
-
* When enabled, a [
|
|
76
|
+
* When enabled, a [plan] badge is prepended before the session state badge.
|
|
77
77
|
*/
|
|
78
78
|
setPlanMode(enabled) {
|
|
79
79
|
this.planMode = enabled;
|
|
@@ -143,20 +143,21 @@ export class FooterComponent {
|
|
|
143
143
|
pwd = `${pwd} • ${sessionName}`;
|
|
144
144
|
}
|
|
145
145
|
const statusParts = [];
|
|
146
|
-
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
if (this.planMode) {
|
|
150
|
-
statusParts.push(badge("
|
|
146
|
+
const normalizedProfile = this.activeProfile.trim().toLowerCase();
|
|
147
|
+
// Plan-mode badge stays leftmost for quick mode awareness, but avoid duplicate
|
|
148
|
+
// [plan] when active profile already renders as [plan].
|
|
149
|
+
if (this.planMode && normalizedProfile !== "plan") {
|
|
150
|
+
statusParts.push(badge("plan", "accent"));
|
|
151
151
|
}
|
|
152
152
|
// Profile badge is always shown when a profile is set, including "full".
|
|
153
|
-
if (
|
|
154
|
-
statusParts.push(badge(
|
|
153
|
+
if (normalizedProfile) {
|
|
154
|
+
statusParts.push(badge(normalizedProfile, "muted"));
|
|
155
155
|
}
|
|
156
|
+
const swarmBusy = this.footerData.getSwarmBusy?.() ?? false;
|
|
156
157
|
if (this.session.isCompacting) {
|
|
157
158
|
statusParts.push(badge("compacting", "warning"));
|
|
158
159
|
}
|
|
159
|
-
else if (this.session.isStreaming) {
|
|
160
|
+
else if (this.session.isStreaming || swarmBusy) {
|
|
160
161
|
statusParts.push(badge("working", "accent"));
|
|
161
162
|
}
|
|
162
163
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@mariozechner/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.js\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts (similar to web-ui)\n */\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nfunction badge(text: string, color: \"accent\" | \"success\" | \"warning\" | \"muted\"): string {\n\treturn theme.fg(\"dim\", \"[\") + theme.fg(color, text) + theme.fg(\"dim\", \"]\");\n}\n\n/**\n * Detect IOSM workspace and return a compact status segment.\n * Returns empty string when no IOSM workspace is found.\n */\nfunction getIosmStatus(cwd: string): string {\n\tconst iosmDir = join(cwd, \".iosm\");\n\tif (!existsSync(iosmDir)) return \"\";\n\n\t// Try to find the most recent cycle ID\n\tlet cycleId: string | undefined;\n\ttry {\n\t\tconst cyclesDir = join(iosmDir, \"cycles\");\n\t\tif (existsSync(cyclesDir)) {\n\t\t\tconst entries = readdirSync(cyclesDir).sort();\n\t\t\tif (entries.length > 0) {\n\t\t\t\tcycleId = entries[entries.length - 1];\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore read errors\n\t}\n\n\tconst label = theme.fg(\"accent\", \"iosm\");\n\tconst suffix = cycleId ? theme.fg(\"muted\", ` #${cycleId}`) : \"\";\n\treturn label + suffix;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate planMode = false;\n\tprivate activeProfile = \"\";\n\n\tconstructor(\n\t\tprivate session: AgentSession,\n\t\tprivate footerData: ReadonlyFooterDataProvider,\n\t) {}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * Toggle plan-mode badge in the status line.\n\t * When enabled, a [PLAN] badge is prepended before the session state badge.\n\t */\n\tsetPlanMode(enabled: boolean): void {\n\t\tthis.planMode = enabled;\n\t}\n\n\t/**\n\t * Set the active profile name.\n\t * When non-empty, a [profile] badge is shown in the status line so the\n\t * operator can always see the current profile, including \"full\".\n\t */\n\tsetActiveProfile(profile: string): void {\n\t\tthis.activeProfile = profile;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\t\tconst separator = theme.fg(\"dim\", \" • \");\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\ttotalInput += entry.message.usage.input;\n\t\t\t\ttotalOutput += entry.message.usage.output;\n\t\t\t\ttotalCacheRead += entry.message.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += entry.message.usage.cacheWrite;\n\t\t\t\ttotalCost += entry.message.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\tconst sessionManager = this.session.sessionManager as { getCwd?: () => string };\n\t\tconst sessionCwd = sessionManager.getCwd?.() ?? process.cwd();\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = sessionCwd;\n\t\tconst home = process.env.HOME || process.env.USERPROFILE;\n\t\tif (home && pwd.startsWith(home)) {\n\t\t\tpwd = `~${pwd.slice(home.length)}`;\n\t\t}\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\tconst statusParts = [];\n\n\t\t// Plan-mode badge: prepended first so it is always the leftmost status indicator.\n\t\t// This placement mirrors how editors surface mode indicators (e.g. INSERT, VISUAL)\n\t\t// before the file-status indicator, giving the operator immediate mode awareness.\n\t\tif (this.planMode) {\n\t\t\tstatusParts.push(badge(\"PLAN\", \"accent\"));\n\t\t}\n\n\t\t// Profile badge is always shown when a profile is set, including \"full\".\n\t\tif (this.activeProfile) {\n\t\t\tstatusParts.push(badge(this.activeProfile, \"muted\"));\n\t\t}\n\n\t\tif (this.session.isCompacting) {\n\t\t\tstatusParts.push(badge(\"compacting\", \"warning\"));\n\t\t} else if (this.session.isStreaming) {\n\t\t\tstatusParts.push(badge(\"working\", \"accent\"));\n\t\t} else {\n\t\t\tstatusParts.push(badge(\"ready\", \"success\"));\n\t\t}\n\n\t\tconst pendingMessages = this.session.pendingMessageCount ?? 0;\n\t\tif (pendingMessages > 0) {\n\t\t\tstatusParts.push(badge(`queue ${pendingMessages}`, pendingMessages > 1 ? \"warning\" : \"accent\"));\n\t\t}\n\n\t\tconst retryAttempt = this.session.retryAttempt ?? 0;\n\t\tif (retryAttempt > 0) {\n\t\t\tstatusParts.push(badge(`retry ${retryAttempt}`, \"warning\"));\n\t\t}\n\n\t\t// Build stats line\n\t\tconst usageParts = [];\n\t\tif (totalInput) usageParts.push(theme.fg(\"muted\", `↑${formatTokens(totalInput)}`));\n\t\tif (totalOutput) usageParts.push(theme.fg(\"muted\", `↓${formatTokens(totalOutput)}`));\n\t\tif (totalCacheRead) usageParts.push(theme.fg(\"muted\", `R${formatTokens(totalCacheRead)}`));\n\t\tif (totalCacheWrite) usageParts.push(theme.fg(\"muted\", `W${formatTokens(totalCacheWrite)}`));\n\n\t\t// Show cost with \"(sub)\" indicator if using OAuth subscription\n\t\tconst usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tusageParts.push(theme.fg(\"muted\", costStr));\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `ctx ?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `ctx ${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = theme.fg(\"muted\", contextPercentDisplay);\n\t\t}\n\t\tusageParts.push(contextPercentStr);\n\n\t\tlet statsLeft = [...statusParts, ...usageParts].join(separator);\n\n\t\t// Add provider/model on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model ? `${state.model.provider}/${state.model.id}` : \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = state.model ? theme.fg(\"accent\", modelName) : theme.fg(\"warning\", modelName);\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\"\n\t\t\t\t\t? `${theme.fg(\"accent\", modelName)}${theme.fg(\"muted\", \" • thinking off\")}`\n\t\t\t\t\t: `${theme.fg(\"accent\", modelName)}${theme.fg(\"muted\", ` • ${thinkingLevel}`)}`;\n\t\t}\n\n\t\tconst rightSide = rightSideWithoutProvider;\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Build pwd line, optionally with IOSM status segment appended\n\t\tconst iosmStatus = getIosmStatus(sessionCwd);\n\t\tlet pwdLine: string;\n\t\tif (iosmStatus) {\n\t\t\t// Assemble the IOSM segment (carries its own ANSI color codes)\n\t\t\tconst iosmSegment = \" [\" + iosmStatus + theme.fg(\"dim\", \"]\");\n\t\t\tconst iosmSegmentWidth = visibleWidth(iosmSegment);\n\t\t\t// Truncate pwd portion to leave room for the iosm segment\n\t\t\tconst maxPwdWidth = Math.max(0, width - iosmSegmentWidth);\n\t\t\tconst dimPwdTruncated = truncateToWidth(theme.fg(\"dim\", pwd), maxPwdWidth, theme.fg(\"dim\", \"...\"));\n\t\t\tpwdLine = dimPwdTruncated + iosmSegment;\n\t\t} else {\n\t\t\tpwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\t}\n\t\tconst lines = [pwdLine, statsLine];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@mariozechner/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.js\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts (similar to web-ui)\n */\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nfunction badge(text: string, color: \"accent\" | \"success\" | \"warning\" | \"muted\"): string {\n\treturn theme.fg(\"dim\", \"[\") + theme.fg(color, text) + theme.fg(\"dim\", \"]\");\n}\n\n/**\n * Detect IOSM workspace and return a compact status segment.\n * Returns empty string when no IOSM workspace is found.\n */\nfunction getIosmStatus(cwd: string): string {\n\tconst iosmDir = join(cwd, \".iosm\");\n\tif (!existsSync(iosmDir)) return \"\";\n\n\t// Try to find the most recent cycle ID\n\tlet cycleId: string | undefined;\n\ttry {\n\t\tconst cyclesDir = join(iosmDir, \"cycles\");\n\t\tif (existsSync(cyclesDir)) {\n\t\t\tconst entries = readdirSync(cyclesDir).sort();\n\t\t\tif (entries.length > 0) {\n\t\t\t\tcycleId = entries[entries.length - 1];\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore read errors\n\t}\n\n\tconst label = theme.fg(\"accent\", \"iosm\");\n\tconst suffix = cycleId ? theme.fg(\"muted\", ` #${cycleId}`) : \"\";\n\treturn label + suffix;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate planMode = false;\n\tprivate activeProfile = \"\";\n\n\tconstructor(\n\t\tprivate session: AgentSession,\n\t\tprivate footerData: ReadonlyFooterDataProvider,\n\t) {}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * Toggle plan-mode badge in the status line.\n\t * When enabled, a [plan] badge is prepended before the session state badge.\n\t */\n\tsetPlanMode(enabled: boolean): void {\n\t\tthis.planMode = enabled;\n\t}\n\n\t/**\n\t * Set the active profile name.\n\t * When non-empty, a [profile] badge is shown in the status line so the\n\t * operator can always see the current profile, including \"full\".\n\t */\n\tsetActiveProfile(profile: string): void {\n\t\tthis.activeProfile = profile;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\t\tconst separator = theme.fg(\"dim\", \" • \");\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\ttotalInput += entry.message.usage.input;\n\t\t\t\ttotalOutput += entry.message.usage.output;\n\t\t\t\ttotalCacheRead += entry.message.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += entry.message.usage.cacheWrite;\n\t\t\t\ttotalCost += entry.message.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\tconst sessionManager = this.session.sessionManager as { getCwd?: () => string };\n\t\tconst sessionCwd = sessionManager.getCwd?.() ?? process.cwd();\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = sessionCwd;\n\t\tconst home = process.env.HOME || process.env.USERPROFILE;\n\t\tif (home && pwd.startsWith(home)) {\n\t\t\tpwd = `~${pwd.slice(home.length)}`;\n\t\t}\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\tconst statusParts = [];\n\n\t\tconst normalizedProfile = this.activeProfile.trim().toLowerCase();\n\n\t\t// Plan-mode badge stays leftmost for quick mode awareness, but avoid duplicate\n\t\t// [plan] when active profile already renders as [plan].\n\t\tif (this.planMode && normalizedProfile !== \"plan\") {\n\t\t\tstatusParts.push(badge(\"plan\", \"accent\"));\n\t\t}\n\n\t\t// Profile badge is always shown when a profile is set, including \"full\".\n\t\tif (normalizedProfile) {\n\t\t\tstatusParts.push(badge(normalizedProfile, \"muted\"));\n\t\t}\n\n\t\tconst swarmBusy = this.footerData.getSwarmBusy?.() ?? false;\n\t\tif (this.session.isCompacting) {\n\t\t\tstatusParts.push(badge(\"compacting\", \"warning\"));\n\t\t} else if (this.session.isStreaming || swarmBusy) {\n\t\t\tstatusParts.push(badge(\"working\", \"accent\"));\n\t\t} else {\n\t\t\tstatusParts.push(badge(\"ready\", \"success\"));\n\t\t}\n\n\t\tconst pendingMessages = this.session.pendingMessageCount ?? 0;\n\t\tif (pendingMessages > 0) {\n\t\t\tstatusParts.push(badge(`queue ${pendingMessages}`, pendingMessages > 1 ? \"warning\" : \"accent\"));\n\t\t}\n\n\t\tconst retryAttempt = this.session.retryAttempt ?? 0;\n\t\tif (retryAttempt > 0) {\n\t\t\tstatusParts.push(badge(`retry ${retryAttempt}`, \"warning\"));\n\t\t}\n\n\t\t// Build stats line\n\t\tconst usageParts = [];\n\t\tif (totalInput) usageParts.push(theme.fg(\"muted\", `↑${formatTokens(totalInput)}`));\n\t\tif (totalOutput) usageParts.push(theme.fg(\"muted\", `↓${formatTokens(totalOutput)}`));\n\t\tif (totalCacheRead) usageParts.push(theme.fg(\"muted\", `R${formatTokens(totalCacheRead)}`));\n\t\tif (totalCacheWrite) usageParts.push(theme.fg(\"muted\", `W${formatTokens(totalCacheWrite)}`));\n\n\t\t// Show cost with \"(sub)\" indicator if using OAuth subscription\n\t\tconst usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tusageParts.push(theme.fg(\"muted\", costStr));\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `ctx ?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `ctx ${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = theme.fg(\"muted\", contextPercentDisplay);\n\t\t}\n\t\tusageParts.push(contextPercentStr);\n\n\t\tlet statsLeft = [...statusParts, ...usageParts].join(separator);\n\n\t\t// Add provider/model on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model ? `${state.model.provider}/${state.model.id}` : \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = state.model ? theme.fg(\"accent\", modelName) : theme.fg(\"warning\", modelName);\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\"\n\t\t\t\t\t? `${theme.fg(\"accent\", modelName)}${theme.fg(\"muted\", \" • thinking off\")}`\n\t\t\t\t\t: `${theme.fg(\"accent\", modelName)}${theme.fg(\"muted\", ` • ${thinkingLevel}`)}`;\n\t\t}\n\n\t\tconst rightSide = rightSideWithoutProvider;\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Build pwd line, optionally with IOSM status segment appended\n\t\tconst iosmStatus = getIosmStatus(sessionCwd);\n\t\tlet pwdLine: string;\n\t\tif (iosmStatus) {\n\t\t\t// Assemble the IOSM segment (carries its own ANSI color codes)\n\t\t\tconst iosmSegment = \" [\" + iosmStatus + theme.fg(\"dim\", \"]\");\n\t\t\tconst iosmSegmentWidth = visibleWidth(iosmSegment);\n\t\t\t// Truncate pwd portion to leave room for the iosm segment\n\t\t\tconst maxPwdWidth = Math.max(0, width - iosmSegmentWidth);\n\t\t\tconst dimPwdTruncated = truncateToWidth(theme.fg(\"dim\", pwd), maxPwdWidth, theme.fg(\"dim\", \"...\"));\n\t\t\tpwdLine = dimPwdTruncated + iosmSegment;\n\t\t} else {\n\t\t\tpwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\t}\n\t\tconst lines = [pwdLine, statsLine];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
import type { ImageContent } from "@mariozechner/pi-ai";
|
|
6
6
|
import { type AgentSession } from "../../core/agent-session.js";
|
|
7
7
|
import { type McpRuntime } from "../../core/mcp/index.js";
|
|
8
|
+
export declare function resolveStreamingSubmissionMode(input: {
|
|
9
|
+
configuredMode: "steer" | "followUp" | "meta";
|
|
10
|
+
activeProfileName: string;
|
|
11
|
+
activeSubagentCount: number;
|
|
12
|
+
activeAssistantOrchestrationContext: boolean;
|
|
13
|
+
}): "steer" | "followUp" | "meta";
|
|
8
14
|
/**
|
|
9
15
|
* Options for InteractiveMode initialization.
|
|
10
16
|
*/
|
|
@@ -60,6 +66,8 @@ export declare class InteractiveMode {
|
|
|
60
66
|
private singularService;
|
|
61
67
|
private singularLastEffectiveContract;
|
|
62
68
|
private swarmActiveRunId;
|
|
69
|
+
private swarmStopRequested;
|
|
70
|
+
private swarmAbortController;
|
|
63
71
|
private lastSigintTime;
|
|
64
72
|
private lastEscapeTime;
|
|
65
73
|
private changelogMarkdown;
|
|
@@ -67,6 +75,8 @@ export declare class InteractiveMode {
|
|
|
67
75
|
private lastStatusText;
|
|
68
76
|
private streamingComponent;
|
|
69
77
|
private streamingMessage;
|
|
78
|
+
private currentTurnSawAssistantMessage;
|
|
79
|
+
private currentTurnSawTaskToolCall;
|
|
70
80
|
private pendingTools;
|
|
71
81
|
private subagentComponents;
|
|
72
82
|
private subagentElapsedTimer;
|
|
@@ -270,6 +280,11 @@ export declare class InteractiveMode {
|
|
|
270
280
|
private handleClipboardImagePaste;
|
|
271
281
|
private setupEditorSubmitHandler;
|
|
272
282
|
private updateRunningSubagentDisplay;
|
|
283
|
+
private getSwarmSubagentKey;
|
|
284
|
+
private ensureSwarmSubagentDisplay;
|
|
285
|
+
private updateSwarmSubagentProgress;
|
|
286
|
+
private finalizeSwarmSubagentDisplay;
|
|
287
|
+
private finalizeSwarmRunSubagentDisplays;
|
|
273
288
|
private ensureSubagentElapsedTimer;
|
|
274
289
|
private clearSubagentElapsedTimer;
|
|
275
290
|
private stopSubagentElapsedTimerIfIdle;
|
|
@@ -285,6 +300,8 @@ export declare class InteractiveMode {
|
|
|
285
300
|
* we update the previous status line instead of appending new ones to avoid log spam.
|
|
286
301
|
*/
|
|
287
302
|
private showStatus;
|
|
303
|
+
private showMetaModeInterruptionHint;
|
|
304
|
+
private showMetaModeProfileHint;
|
|
288
305
|
private showProgressLine;
|
|
289
306
|
private setWorkingMessage;
|
|
290
307
|
private addMessageToChat;
|
|
@@ -471,6 +488,8 @@ export declare class InteractiveMode {
|
|
|
471
488
|
private parseIosmAutomationSlashCommand;
|
|
472
489
|
private getSwarmHelpText;
|
|
473
490
|
private buildSwarmRecommendationFromOrchestrate;
|
|
491
|
+
private resolveOrchestrateDefaultAssignmentProfile;
|
|
492
|
+
private deriveOrchestrateDelegateParallelHint;
|
|
474
493
|
private isEffectiveContractReady;
|
|
475
494
|
private parseContractListInput;
|
|
476
495
|
private buildAutoDraftContractFromTask;
|
|
@@ -484,6 +503,9 @@ export declare class InteractiveMode {
|
|
|
484
503
|
private resolveSwarmTaskProfile;
|
|
485
504
|
private estimateSwarmTaskCostUsd;
|
|
486
505
|
private deriveSwarmTaskDelegateParallelHint;
|
|
506
|
+
private ensureSwarmModelReady;
|
|
507
|
+
private resolveSwarmMaxParallel;
|
|
508
|
+
private resolveSwarmDispatchTimeoutMs;
|
|
487
509
|
private parseSwarmSpawnCandidates;
|
|
488
510
|
private loadSingularAnalysisByRunId;
|
|
489
511
|
private dispatchSwarmTaskWithAgent;
|