maestro-agent-sdk 0.1.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/LICENSE +21 -0
- package/NOTICE +24 -0
- package/README.md +133 -0
- package/dist/agents/contracts.d.ts +49 -0
- package/dist/agents/contracts.d.ts.map +1 -0
- package/dist/agents/contracts.js +2 -0
- package/dist/agents/contracts.js.map +1 -0
- package/dist/agents/rollout/shared.d.ts +24 -0
- package/dist/agents/rollout/shared.d.ts.map +1 -0
- package/dist/agents/rollout/shared.js +105 -0
- package/dist/agents/rollout/shared.js.map +1 -0
- package/dist/core/agent.d.ts +71 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +22 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/loop.d.ts +26 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +317 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +79 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +176 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/pool-cache.d.ts +103 -0
- package/dist/mcp/pool-cache.d.ts.map +1 -0
- package/dist/mcp/pool-cache.js +249 -0
- package/dist/mcp/pool-cache.js.map +1 -0
- package/dist/mcp/pool.d.ts +65 -0
- package/dist/mcp/pool.d.ts.map +1 -0
- package/dist/mcp/pool.js +86 -0
- package/dist/mcp/pool.js.map +1 -0
- package/dist/media/file-events.d.ts +8 -0
- package/dist/media/file-events.d.ts.map +1 -0
- package/dist/media/file-events.js +15 -0
- package/dist/media/file-events.js.map +1 -0
- package/dist/memory/active-task-template.d.ts +34 -0
- package/dist/memory/active-task-template.d.ts.map +1 -0
- package/dist/memory/active-task-template.js +63 -0
- package/dist/memory/active-task-template.js.map +1 -0
- package/dist/memory/compressor.d.ts +87 -0
- package/dist/memory/compressor.d.ts.map +1 -0
- package/dist/memory/compressor.js +164 -0
- package/dist/memory/compressor.js.map +1 -0
- package/dist/memory/hash.d.ts +17 -0
- package/dist/memory/hash.d.ts.map +1 -0
- package/dist/memory/hash.js +20 -0
- package/dist/memory/hash.js.map +1 -0
- package/dist/memory/prune.d.ts +117 -0
- package/dist/memory/prune.d.ts.map +1 -0
- package/dist/memory/prune.js +416 -0
- package/dist/memory/prune.js.map +1 -0
- package/dist/memory/reminder.d.ts +57 -0
- package/dist/memory/reminder.d.ts.map +1 -0
- package/dist/memory/reminder.js +57 -0
- package/dist/memory/reminder.js.map +1 -0
- package/dist/memory/scrubber.d.ts +28 -0
- package/dist/memory/scrubber.d.ts.map +1 -0
- package/dist/memory/scrubber.js +147 -0
- package/dist/memory/scrubber.js.map +1 -0
- package/dist/memory/token-estimate.d.ts +10 -0
- package/dist/memory/token-estimate.d.ts.map +1 -0
- package/dist/memory/token-estimate.js +69 -0
- package/dist/memory/token-estimate.js.map +1 -0
- package/dist/platform/config.d.ts +12 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/config.js +54 -0
- package/dist/platform/config.js.map +1 -0
- package/dist/platform/jsonl.d.ts +15 -0
- package/dist/platform/jsonl.d.ts.map +1 -0
- package/dist/platform/jsonl.js +80 -0
- package/dist/platform/jsonl.js.map +1 -0
- package/dist/platform/lifecycle.d.ts +22 -0
- package/dist/platform/lifecycle.d.ts.map +1 -0
- package/dist/platform/lifecycle.js +60 -0
- package/dist/platform/lifecycle.js.map +1 -0
- package/dist/platform/logger.d.ts +26 -0
- package/dist/platform/logger.d.ts.map +1 -0
- package/dist/platform/logger.js +41 -0
- package/dist/platform/logger.js.map +1 -0
- package/dist/platform/mcp-config.d.ts +15 -0
- package/dist/platform/mcp-config.d.ts.map +1 -0
- package/dist/platform/mcp-config.js +8 -0
- package/dist/platform/mcp-config.js.map +1 -0
- package/dist/provider.d.ts +81 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +444 -0
- package/dist/provider.js.map +1 -0
- package/dist/providers/anthropic.d.ts +132 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +518 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +140 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/deepseek.d.ts +118 -0
- package/dist/providers/deepseek.d.ts.map +1 -0
- package/dist/providers/deepseek.js +467 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +94 -0
- package/dist/registry.js.map +1 -0
- package/dist/session-store.d.ts +133 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +277 -0
- package/dist/session-store.js.map +1 -0
- package/dist/skills/curator.d.ts +104 -0
- package/dist/skills/curator.d.ts.map +1 -0
- package/dist/skills/curator.js +162 -0
- package/dist/skills/curator.js.map +1 -0
- package/dist/skills/index-builder.d.ts +42 -0
- package/dist/skills/index-builder.d.ts.map +1 -0
- package/dist/skills/index-builder.js +94 -0
- package/dist/skills/index-builder.js.map +1 -0
- package/dist/skills/loader.d.ts +107 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +286 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/preprocess.d.ts +45 -0
- package/dist/skills/preprocess.d.ts.map +1 -0
- package/dist/skills/preprocess.js +126 -0
- package/dist/skills/preprocess.js.map +1 -0
- package/dist/skills/usage.d.ts +75 -0
- package/dist/skills/usage.d.ts.map +1 -0
- package/dist/skills/usage.js +147 -0
- package/dist/skills/usage.js.map +1 -0
- package/dist/state/todos.d.ts +95 -0
- package/dist/state/todos.d.ts.map +1 -0
- package/dist/state/todos.js +198 -0
- package/dist/state/todos.js.map +1 -0
- package/dist/storage/conversations.d.ts +28 -0
- package/dist/storage/conversations.d.ts.map +1 -0
- package/dist/storage/conversations.js +8 -0
- package/dist/storage/conversations.js.map +1 -0
- package/dist/sub-agent/runner.d.ts +78 -0
- package/dist/sub-agent/runner.d.ts.map +1 -0
- package/dist/sub-agent/runner.js +215 -0
- package/dist/sub-agent/runner.js.map +1 -0
- package/dist/tools/builtin/agent.d.ts +33 -0
- package/dist/tools/builtin/agent.d.ts.map +1 -0
- package/dist/tools/builtin/agent.js +76 -0
- package/dist/tools/builtin/agent.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +11 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +91 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +21 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +238 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +17 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +139 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/sandbox.d.ts +16 -0
- package/dist/tools/builtin/sandbox.d.ts.map +1 -0
- package/dist/tools/builtin/sandbox.js +58 -0
- package/dist/tools/builtin/sandbox.js.map +1 -0
- package/dist/tools/builtin/skill_view.d.ts +37 -0
- package/dist/tools/builtin/skill_view.d.ts.map +1 -0
- package/dist/tools/builtin/skill_view.js +82 -0
- package/dist/tools/builtin/skill_view.js.map +1 -0
- package/dist/tools/builtin/todo_write.d.ts +29 -0
- package/dist/tools/builtin/todo_write.d.ts.map +1 -0
- package/dist/tools/builtin/todo_write.js +96 -0
- package/dist/tools/builtin/todo_write.js.map +1 -0
- package/dist/tools/builtin/web_fetch.d.ts +10 -0
- package/dist/tools/builtin/web_fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web_fetch.js +150 -0
- package/dist/tools/builtin/web_fetch.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +35 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +70 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/file-state.d.ts +99 -0
- package/dist/tools/file-state.d.ts.map +1 -0
- package/dist/tools/file-state.js +133 -0
- package/dist/tools/file-state.js.map +1 -0
- package/dist/tools/hooks/sandbox-fs.d.ts +25 -0
- package/dist/tools/hooks/sandbox-fs.d.ts.map +1 -0
- package/dist/tools/hooks/sandbox-fs.js +48 -0
- package/dist/tools/hooks/sandbox-fs.js.map +1 -0
- package/dist/tools/registry.d.ts +102 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +93 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { DATA_DIR } from "../platform/config.js";
|
|
4
|
+
import { logger } from "../platform/logger.js";
|
|
5
|
+
const SCHEMA_VERSION = 1;
|
|
6
|
+
/** Default sidecar path. Overridable via `MAESTRO_SKILL_USAGE_PATH` for tests
|
|
7
|
+
* and operators that prefer a different on-disk location. */
|
|
8
|
+
export function defaultUsagePath() {
|
|
9
|
+
return (process.env.MAESTRO_SKILL_USAGE_PATH ??
|
|
10
|
+
join(DATA_DIR, "agents", "maestro", "skills", "usage.json"));
|
|
11
|
+
}
|
|
12
|
+
/** Mutex queue — each enqueued action awaits the previous one. */
|
|
13
|
+
const queuesByPath = new Map();
|
|
14
|
+
// Write-through cache: every `bump` is serialized through `enqueue`, so the
|
|
15
|
+
// in-process cache is the authoritative state between writes. Eliminates the
|
|
16
|
+
// per-turn readFileSync that curator + skill_view used to incur for every
|
|
17
|
+
// `loadUsage` call. Tests reset via `__resetForTests`.
|
|
18
|
+
const usageCacheByPath = new Map();
|
|
19
|
+
function enqueue(path, fn) {
|
|
20
|
+
const prev = queuesByPath.get(path) ?? Promise.resolve();
|
|
21
|
+
let resolver;
|
|
22
|
+
let rejecter;
|
|
23
|
+
const result = new Promise((res, rej) => {
|
|
24
|
+
resolver = res;
|
|
25
|
+
rejecter = rej;
|
|
26
|
+
});
|
|
27
|
+
const next = prev.then(async () => {
|
|
28
|
+
try {
|
|
29
|
+
const v = await fn();
|
|
30
|
+
resolver(v);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
rejecter(err);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
queuesByPath.set(path, next);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function emptyFile() {
|
|
40
|
+
return { schemaVersion: SCHEMA_VERSION, skills: {} };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read the usage file synchronously. Returns an empty (in-memory) file on
|
|
44
|
+
* ENOENT / parse failure — callers that need to disambiguate can call
|
|
45
|
+
* `existsSync(defaultUsagePath())` themselves. Logged at debug so a missing
|
|
46
|
+
* file is not noise on every read.
|
|
47
|
+
*/
|
|
48
|
+
export function loadUsage(path = defaultUsagePath()) {
|
|
49
|
+
const cached = usageCacheByPath.get(path);
|
|
50
|
+
if (cached)
|
|
51
|
+
return cached;
|
|
52
|
+
const fresh = readUsageFromDisk(path);
|
|
53
|
+
usageCacheByPath.set(path, fresh);
|
|
54
|
+
return fresh;
|
|
55
|
+
}
|
|
56
|
+
function readUsageFromDisk(path) {
|
|
57
|
+
if (!existsSync(path))
|
|
58
|
+
return emptyFile();
|
|
59
|
+
let raw;
|
|
60
|
+
try {
|
|
61
|
+
raw = readFileSync(path, "utf8");
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
logger.debug({ err, path }, "skill usage: read failed, returning empty");
|
|
65
|
+
return emptyFile();
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
if (parsed.schemaVersion !== SCHEMA_VERSION || typeof parsed.skills !== "object") {
|
|
70
|
+
logger.warn({ path, schemaVersion: parsed.schemaVersion }, "skill usage: schema mismatch — resetting");
|
|
71
|
+
return emptyFile();
|
|
72
|
+
}
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
logger.warn({ err, path }, "skill usage: JSON parse failed — resetting");
|
|
77
|
+
return emptyFile();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Get counters for a single skill. Never returns undefined — synthesizes
|
|
81
|
+
* zeroed counters for unseen skills so callers can compute deltas without
|
|
82
|
+
* null-checks. */
|
|
83
|
+
export function getCounters(name, path = defaultUsagePath()) {
|
|
84
|
+
const file = loadUsage(path);
|
|
85
|
+
return file.skills[name] ?? zeroedCounters();
|
|
86
|
+
}
|
|
87
|
+
function zeroedCounters() {
|
|
88
|
+
const ts = new Date().toISOString();
|
|
89
|
+
return {
|
|
90
|
+
viewCount: 0,
|
|
91
|
+
useCount: 0,
|
|
92
|
+
patchCount: 0,
|
|
93
|
+
lastTouchedTs: ts,
|
|
94
|
+
firstSeenTs: ts,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** Atomic write: tmp → rename. Survives a process kill mid-write because
|
|
98
|
+
* the destination either has the old bytes or the new bytes, never half. */
|
|
99
|
+
function writeAtomic(path, contents) {
|
|
100
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
101
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
102
|
+
writeFileSync(tmp, JSON.stringify(contents, null, 2));
|
|
103
|
+
renameSync(tmp, path);
|
|
104
|
+
}
|
|
105
|
+
/** Internal: increment one counter by one for `name`, persisting. */
|
|
106
|
+
async function bump(name, key, path = defaultUsagePath()) {
|
|
107
|
+
if (!name) {
|
|
108
|
+
throw new Error("skill usage bump: empty name");
|
|
109
|
+
}
|
|
110
|
+
return enqueue(path, () => {
|
|
111
|
+
const file = loadUsage(path);
|
|
112
|
+
const ts = new Date().toISOString();
|
|
113
|
+
const existing = file.skills[name];
|
|
114
|
+
const next = existing
|
|
115
|
+
? { ...existing, [key]: existing[key] + 1, lastTouchedTs: ts }
|
|
116
|
+
: { ...zeroedCounters(), firstSeenTs: ts, [key]: 1, lastTouchedTs: ts };
|
|
117
|
+
file.skills[name] = next;
|
|
118
|
+
writeAtomic(path, file);
|
|
119
|
+
// `file` is the cached reference — mutation above already updated the
|
|
120
|
+
// cache. Reassert here in case `loadUsage` had returned a fresh disk read
|
|
121
|
+
// (cold cache miss) so a subsequent loadUsage call gets the post-write
|
|
122
|
+
// state without going through disk again.
|
|
123
|
+
usageCacheByPath.set(path, file);
|
|
124
|
+
return next;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Bump `viewCount` for `name`. Called from `skill_view` after a successful body load. */
|
|
128
|
+
export function bumpView(name, path) {
|
|
129
|
+
return bump(name, "viewCount", path);
|
|
130
|
+
}
|
|
131
|
+
/** Bump `useCount` for `name`. Reserved for future call-site instrumentation. */
|
|
132
|
+
export function bumpUse(name, path) {
|
|
133
|
+
return bump(name, "useCount", path);
|
|
134
|
+
}
|
|
135
|
+
/** Bump `patchCount` for `name`. Reserved for the future `skill_edit` builtin. */
|
|
136
|
+
export function bumpPatch(name, path) {
|
|
137
|
+
return bump(name, "patchCount", path);
|
|
138
|
+
}
|
|
139
|
+
/** Test-only: drop the in-memory mutex queue + write-through cache. Disk
|
|
140
|
+
* file is NOT erased — tests that need filesystem isolation should point
|
|
141
|
+
* `MAESTRO_SKILL_USAGE_PATH` at a tmp file via `process.env` and remove it
|
|
142
|
+
* themselves. */
|
|
143
|
+
export function __resetForTests() {
|
|
144
|
+
queuesByPath.clear();
|
|
145
|
+
usageCacheByPath.clear();
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/skills/usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session todo list backing TodoWrite.
|
|
3
|
+
*
|
|
4
|
+
* The model gets a single `todo_write` tool to upsert / mutate the list. There
|
|
5
|
+
* is no `todo_list` tool — read-side surfaces via the per-turn system
|
|
6
|
+
* reminder, which keeps the model from juggling two near-identical tools
|
|
7
|
+
* (and saves a per-turn round-trip for what is fundamentally a snapshot view).
|
|
8
|
+
*
|
|
9
|
+
* Persistence: one JSON file at `~/.maestro/sessions/<sid>.todos.json` — a
|
|
10
|
+
* snapshot of the current list, atomically written. Not JSONL: `todo_write`
|
|
11
|
+
* semantically OVERWRITES the list each call, so an append-only stream
|
|
12
|
+
* would accumulate dead entries the loader has to filter. A single JSON
|
|
13
|
+
* snapshot matches the actual semantics and is cheaper to read.
|
|
14
|
+
*
|
|
15
|
+
* Lifecycle:
|
|
16
|
+
* - `getTodoStore(sid)` lazy-creates the store and hydrates from disk if
|
|
17
|
+
* a prior turn wrote one.
|
|
18
|
+
* - `dropTodoStore(sid)` is called from `deleteMaestroSession` and
|
|
19
|
+
* `cleanupStaleMaestroSessions` (same pattern as `file-state.ts`) so the
|
|
20
|
+
* module-level map can't outlive its sessions.
|
|
21
|
+
*
|
|
22
|
+
* Invariants enforced at upsert time:
|
|
23
|
+
* - At most one entry is `in_progress`. Setting a second one to
|
|
24
|
+
* `in_progress` flips any prior one to `pending` and warns the caller
|
|
25
|
+
* via the tool result. Mirrors Claude Code's TodoWrite contract.
|
|
26
|
+
* - IDs are auto-assigned (`task-1`, `task-2`, …) when omitted. Short IDs
|
|
27
|
+
* so the model can refer back to them in prose without bloat.
|
|
28
|
+
*/
|
|
29
|
+
export type TodoStatus = "pending" | "in_progress" | "completed";
|
|
30
|
+
export interface TodoEntry {
|
|
31
|
+
id: string;
|
|
32
|
+
content: string;
|
|
33
|
+
status: TodoStatus;
|
|
34
|
+
/** Optional present-continuous form for spinner/status display
|
|
35
|
+
* ("Reading config" vs the imperative "Read config"). */
|
|
36
|
+
activeForm?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface TodoUpsert {
|
|
39
|
+
id?: string;
|
|
40
|
+
content: string;
|
|
41
|
+
status: TodoStatus;
|
|
42
|
+
activeForm?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface UpsertResult {
|
|
45
|
+
todos: TodoEntry[];
|
|
46
|
+
/** Set when the upsert had to flip a prior in_progress to pending to
|
|
47
|
+
* enforce the 1-in-progress invariant. The tool surfaces this in its
|
|
48
|
+
* result so the model knows the previously-active item was bumped. */
|
|
49
|
+
demotedId?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare class TodoStore {
|
|
52
|
+
private readonly path;
|
|
53
|
+
private todos;
|
|
54
|
+
private nextCounter;
|
|
55
|
+
constructor(path: string);
|
|
56
|
+
/** Read the current list. Caller must not mutate. */
|
|
57
|
+
list(): readonly TodoEntry[];
|
|
58
|
+
/** True when the list is empty (no in-flight or pending work). */
|
|
59
|
+
isEmpty(): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Replace / upsert the entire list. Entries with an `id` that matches an
|
|
62
|
+
* existing one update that entry; entries without an id (or with an id
|
|
63
|
+
* not in the current list) become new entries with an auto-assigned id.
|
|
64
|
+
*
|
|
65
|
+
* The shape mirrors Claude Code's TodoWrite: the model passes a complete
|
|
66
|
+
* snapshot of "what I want the list to look like now," and we reconcile.
|
|
67
|
+
* That means an existing id NOT included in the incoming snapshot is
|
|
68
|
+
* dropped — TodoWrite is a snapshot replace, not a partial update.
|
|
69
|
+
*
|
|
70
|
+
* Returns `{todos, demotedId?}` so the tool can tell the model exactly
|
|
71
|
+
* what landed (incl. any in-progress demotion).
|
|
72
|
+
*/
|
|
73
|
+
upsert(incoming: TodoUpsert[]): UpsertResult;
|
|
74
|
+
/** Drop the on-disk file. Called by deleteMaestroSession via dropTodoStore. */
|
|
75
|
+
unlinkFile(): void;
|
|
76
|
+
/** Test-only: snapshot the path the store is backed by. */
|
|
77
|
+
__path(): string;
|
|
78
|
+
private nextId;
|
|
79
|
+
private hydrate;
|
|
80
|
+
/** Recover the counter from existing IDs when the file lacked the field
|
|
81
|
+
* (defensive — recent hydrate writes always include it). */
|
|
82
|
+
private deriveCounter;
|
|
83
|
+
private persist;
|
|
84
|
+
}
|
|
85
|
+
/** Resolve the absolute todos-file path for a session. Mirrors
|
|
86
|
+
* `maestroSessionPath` but with `.todos.json` instead of `.jsonl`. */
|
|
87
|
+
export declare function todosPathFor(sessionId: string): string;
|
|
88
|
+
export declare function getTodoStore(sessionId: string): TodoStore;
|
|
89
|
+
/** Drop a session's store + unlink its on-disk file. */
|
|
90
|
+
export declare function dropTodoStore(sessionId: string): void;
|
|
91
|
+
/** Test-only. Reset every store. */
|
|
92
|
+
export declare function __resetAllStores(): void;
|
|
93
|
+
/** Test-only. Count of currently-tracked sessions. */
|
|
94
|
+
export declare function __storeCount(): number;
|
|
95
|
+
//# sourceMappingURL=todos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todos.d.ts","sourceRoot":"","sources":["../../src/state/todos.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAEjE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB;8DAC0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB;;2EAEuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,SAAS;IAIR,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,WAAW,CAAK;gBAEK,IAAI,EAAE,MAAM;IAIzC,qDAAqD;IACrD,IAAI,IAAI,SAAS,SAAS,EAAE;IAI5B,kEAAkE;IAClE,OAAO,IAAI,OAAO;IAIlB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,YAAY;IAwC5C,+EAA+E;IAC/E,UAAU,IAAI,IAAI;IAUlB,2DAA2D;IAC3D,MAAM,IAAI,MAAM;IAMhB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,OAAO;IAgBf;iEAC6D;IAC7D,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,OAAO;CAQhB;AAqBD;uEACuE;AACvE,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD;AAeD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAOzD;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED,oCAAoC;AACpC,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,sDAAsD;AACtD,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { logger } from "../platform/logger.js";
|
|
5
|
+
/** Mirror of `maestroSessionsDir()` from session-store.ts — inlined here to
|
|
6
|
+
* avoid a circular import (session-store.ts needs to call
|
|
7
|
+
* `dropTodoStore` for cleanup). Two single-line copies are cheaper than
|
|
8
|
+
* extracting a shared util file for one path. */
|
|
9
|
+
function sessionsDir() {
|
|
10
|
+
return join(homedir(), ".maestro", "sessions");
|
|
11
|
+
}
|
|
12
|
+
export class TodoStore {
|
|
13
|
+
path;
|
|
14
|
+
todos = [];
|
|
15
|
+
nextCounter = 1;
|
|
16
|
+
constructor(path) {
|
|
17
|
+
this.path = path;
|
|
18
|
+
this.hydrate();
|
|
19
|
+
}
|
|
20
|
+
/** Read the current list. Caller must not mutate. */
|
|
21
|
+
list() {
|
|
22
|
+
return this.todos;
|
|
23
|
+
}
|
|
24
|
+
/** True when the list is empty (no in-flight or pending work). */
|
|
25
|
+
isEmpty() {
|
|
26
|
+
return this.todos.length === 0;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Replace / upsert the entire list. Entries with an `id` that matches an
|
|
30
|
+
* existing one update that entry; entries without an id (or with an id
|
|
31
|
+
* not in the current list) become new entries with an auto-assigned id.
|
|
32
|
+
*
|
|
33
|
+
* The shape mirrors Claude Code's TodoWrite: the model passes a complete
|
|
34
|
+
* snapshot of "what I want the list to look like now," and we reconcile.
|
|
35
|
+
* That means an existing id NOT included in the incoming snapshot is
|
|
36
|
+
* dropped — TodoWrite is a snapshot replace, not a partial update.
|
|
37
|
+
*
|
|
38
|
+
* Returns `{todos, demotedId?}` so the tool can tell the model exactly
|
|
39
|
+
* what landed (incl. any in-progress demotion).
|
|
40
|
+
*/
|
|
41
|
+
upsert(incoming) {
|
|
42
|
+
const out = [];
|
|
43
|
+
let demotedId;
|
|
44
|
+
// First pass: build the new list, assigning IDs to entries that need
|
|
45
|
+
// them. We do this BEFORE the 1-in-progress sweep so the auto-IDs are
|
|
46
|
+
// available for the warning message.
|
|
47
|
+
for (const item of incoming) {
|
|
48
|
+
const id = item.id?.trim() || this.nextId();
|
|
49
|
+
out.push({
|
|
50
|
+
id,
|
|
51
|
+
content: item.content,
|
|
52
|
+
status: item.status,
|
|
53
|
+
...(item.activeForm ? { activeForm: item.activeForm } : {}),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// Second pass: enforce 1-in-progress. Walk in incoming order; the LAST
|
|
57
|
+
// in_progress wins (mirrors how a model batch-updates and the final
|
|
58
|
+
// entry expresses current intent). Earlier in_progress entries are
|
|
59
|
+
// flipped to pending and surfaced via `demotedId`.
|
|
60
|
+
let lastInProgressIdx = -1;
|
|
61
|
+
for (let i = 0; i < out.length; i++) {
|
|
62
|
+
if (out[i].status === "in_progress")
|
|
63
|
+
lastInProgressIdx = i;
|
|
64
|
+
}
|
|
65
|
+
if (lastInProgressIdx >= 0) {
|
|
66
|
+
for (let i = 0; i < out.length; i++) {
|
|
67
|
+
if (i === lastInProgressIdx)
|
|
68
|
+
continue;
|
|
69
|
+
if (out[i].status === "in_progress") {
|
|
70
|
+
out[i] = { ...out[i], status: "pending" };
|
|
71
|
+
demotedId = out[i].id;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.todos = out;
|
|
76
|
+
this.persist();
|
|
77
|
+
return demotedId !== undefined ? { todos: out, demotedId } : { todos: out };
|
|
78
|
+
}
|
|
79
|
+
/** Drop the on-disk file. Called by deleteMaestroSession via dropTodoStore. */
|
|
80
|
+
unlinkFile() {
|
|
81
|
+
try {
|
|
82
|
+
unlinkSync(this.path);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
if (e?.code !== "ENOENT") {
|
|
86
|
+
logger.warn({ err: e, path: this.path }, "TodoStore.unlinkFile failed");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Test-only: snapshot the path the store is backed by. */
|
|
91
|
+
__path() {
|
|
92
|
+
return this.path;
|
|
93
|
+
}
|
|
94
|
+
// --- internals ---------------------------------------------------------
|
|
95
|
+
nextId() {
|
|
96
|
+
const id = `task-${this.nextCounter}`;
|
|
97
|
+
this.nextCounter++;
|
|
98
|
+
return id;
|
|
99
|
+
}
|
|
100
|
+
hydrate() {
|
|
101
|
+
if (!existsSync(this.path))
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
const raw = readFileSync(this.path, "utf8");
|
|
105
|
+
const parsed = JSON.parse(raw);
|
|
106
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.todos)) {
|
|
107
|
+
logger.warn({ path: this.path }, "TodoStore.hydrate: unsupported schema, ignoring");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.todos = parsed.todos.filter(isWellFormedEntry);
|
|
111
|
+
this.nextCounter = Math.max(1, parsed.nextCounter ?? this.deriveCounter());
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
logger.warn({ err: e, path: this.path }, "TodoStore.hydrate: parse failed, starting empty");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Recover the counter from existing IDs when the file lacked the field
|
|
118
|
+
* (defensive — recent hydrate writes always include it). */
|
|
119
|
+
deriveCounter() {
|
|
120
|
+
let max = 0;
|
|
121
|
+
for (const t of this.todos) {
|
|
122
|
+
const m = /^task-(\d+)$/.exec(t.id);
|
|
123
|
+
if (m)
|
|
124
|
+
max = Math.max(max, Number.parseInt(m[1], 10));
|
|
125
|
+
}
|
|
126
|
+
return max + 1;
|
|
127
|
+
}
|
|
128
|
+
persist() {
|
|
129
|
+
const file = {
|
|
130
|
+
version: 1,
|
|
131
|
+
nextCounter: this.nextCounter,
|
|
132
|
+
todos: this.todos,
|
|
133
|
+
};
|
|
134
|
+
writeAtomic(this.path, file);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Atomic write: tmp → rename. Same pattern as skills/usage.ts. */
|
|
138
|
+
function writeAtomic(path, contents) {
|
|
139
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
140
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
141
|
+
writeFileSync(tmp, JSON.stringify(contents, null, 2));
|
|
142
|
+
renameSync(tmp, path);
|
|
143
|
+
}
|
|
144
|
+
function isWellFormedEntry(v) {
|
|
145
|
+
if (!v || typeof v !== "object")
|
|
146
|
+
return false;
|
|
147
|
+
const o = v;
|
|
148
|
+
if (typeof o.id !== "string" || typeof o.content !== "string")
|
|
149
|
+
return false;
|
|
150
|
+
if (o.status !== "pending" && o.status !== "in_progress" && o.status !== "completed") {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if (o.activeForm !== undefined && typeof o.activeForm !== "string")
|
|
154
|
+
return false;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
/** Resolve the absolute todos-file path for a session. Mirrors
|
|
158
|
+
* `maestroSessionPath` but with `.todos.json` instead of `.jsonl`. */
|
|
159
|
+
export function todosPathFor(sessionId) {
|
|
160
|
+
return join(sessionsDir(), `${sessionId}.todos.json`);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Module-level registry — same pattern as `file-state.ts`.
|
|
164
|
+
*
|
|
165
|
+
* The maestroProvider rebuilds tools each turn but the sessionId persists
|
|
166
|
+
* across turns. A registry-local store would re-hydrate every turn (cheap
|
|
167
|
+
* but wasteful); a module-level cache keeps the in-memory list hot.
|
|
168
|
+
*
|
|
169
|
+
* Cleanup is wired into `deleteMaestroSession` and
|
|
170
|
+
* `cleanupStaleMaestroSessions` (see session-store.ts) so the map can't
|
|
171
|
+
* outlive its sessions.
|
|
172
|
+
*/
|
|
173
|
+
const stores = new Map();
|
|
174
|
+
export function getTodoStore(sessionId) {
|
|
175
|
+
let s = stores.get(sessionId);
|
|
176
|
+
if (!s) {
|
|
177
|
+
s = new TodoStore(todosPathFor(sessionId));
|
|
178
|
+
stores.set(sessionId, s);
|
|
179
|
+
}
|
|
180
|
+
return s;
|
|
181
|
+
}
|
|
182
|
+
/** Drop a session's store + unlink its on-disk file. */
|
|
183
|
+
export function dropTodoStore(sessionId) {
|
|
184
|
+
const s = stores.get(sessionId);
|
|
185
|
+
if (s) {
|
|
186
|
+
s.unlinkFile();
|
|
187
|
+
stores.delete(sessionId);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Test-only. Reset every store. */
|
|
191
|
+
export function __resetAllStores() {
|
|
192
|
+
stores.clear();
|
|
193
|
+
}
|
|
194
|
+
/** Test-only. Count of currently-tracked sessions. */
|
|
195
|
+
export function __storeCount() {
|
|
196
|
+
return stores.size;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=todos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todos.js","sourceRoot":"","sources":["../../src/state/todos.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C;;;kDAGkD;AAClD,SAAS,WAAW;IAClB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC;AAgED,MAAM,OAAO,SAAS;IAIS;IAHrB,KAAK,GAAgB,EAAE,CAAC;IACxB,WAAW,GAAG,CAAC,CAAC;IAExB,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAED,qDAAqD;IACrD,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,kEAAkE;IAClE,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,QAAsB;QAC3B,MAAM,GAAG,GAAgB,EAAE,CAAC;QAC5B,IAAI,SAA6B,CAAC;QAElC,qEAAqE;QACrE,sEAAsE;QACtE,qCAAqC;QACrC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5C,GAAG,CAAC,IAAI,CAAC;gBACP,EAAE;gBACF,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,uEAAuE;QACvE,oEAAoE;QACpE,mEAAmE;QACnE,mDAAmD;QACnD,IAAI,iBAAiB,GAAG,CAAC,CAAC,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa;gBAAE,iBAAiB,GAAG,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,iBAAiB,IAAI,CAAC,EAAE,CAAC;YAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpC,IAAI,CAAC,KAAK,iBAAiB;oBAAE,SAAS;gBACtC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;oBACpC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;oBAC1C,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;QACjB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC9E,CAAC;IAED,+EAA+E;IAC/E,UAAU;QACR,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAK,CAA2B,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpD,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,6BAA6B,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,0EAA0E;IAElE,MAAM;QACZ,MAAM,EAAE,GAAG,QAAQ,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;YACpD,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,iDAAiD,CAAC,CAAC;gBACpF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;YACpD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,iDAAiD,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED;iEAC6D;IACrD,aAAa;QACnB,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC;gBAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,GAAG,GAAG,CAAC,CAAC;IACjB,CAAC;IAEO,OAAO;QACb,MAAM,IAAI,GAAa;YACrB,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;QACF,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,mEAAmE;AACnE,SAAS,WAAW,CAAC,IAAY,EAAE,QAAkB;IACnD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACvD,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAU;IACnC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5E,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACrF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;uEACuE;AACvE,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,SAAS,aAAa,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE5C,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,IAAI,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC;QACN,CAAC,CAAC,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,gBAAgB;IAC9B,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AgentKind, UnifiedEvent } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-agnostic conversation entry.
|
|
4
|
+
*
|
|
5
|
+
* The SDK does **not** persist conversations itself — that's the host's job.
|
|
6
|
+
* This interface is exposed so hosts can hand the SDK a back-fill of past
|
|
7
|
+
* turns (`registry.forkSession` rehydrates from this shape) and so SDK
|
|
8
|
+
* code that needs to encode/decode rollout entries shares a single type.
|
|
9
|
+
*/
|
|
10
|
+
export interface ConversationEntry {
|
|
11
|
+
/** ISO timestamp the event was recorded. */
|
|
12
|
+
ts: string;
|
|
13
|
+
/** Agent that produced this event, frozen at write time. */
|
|
14
|
+
agent: AgentKind;
|
|
15
|
+
/** Normalized event payload. */
|
|
16
|
+
event: UnifiedEvent;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Host-supplied callback that returns the conversation log for a session.
|
|
20
|
+
*
|
|
21
|
+
* The SDK calls this from `registry.forkSession()` when synthesizing a maestro
|
|
22
|
+
* rollout from cross-agent history. Hosts that don't need cross-agent
|
|
23
|
+
* bridging can leave the default (returns `[]`) in place.
|
|
24
|
+
*/
|
|
25
|
+
export type ConversationReader = (userId: number | string, topicName: string, groupId?: number) => ConversationEntry[];
|
|
26
|
+
export declare function setConversationReader(reader: ConversationReader): void;
|
|
27
|
+
export declare function readConversation(userId: number | string, topicName: string, groupId?: number): ConversationEntry[];
|
|
28
|
+
//# sourceMappingURL=conversations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../src/storage/conversations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,SAAS,CAAC;IACjB,gCAAgC;IAChC,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,KACb,iBAAiB,EAAE,CAAC;AAIzB,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAEtE;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,iBAAiB,EAAE,CAErB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/storage/conversations.ts"],"names":[],"mappings":"AAgCA,IAAI,OAAO,GAAuB,GAAG,EAAE,CAAC,EAAE,CAAC;AAE3C,MAAM,UAAU,qBAAqB,CAAC,MAA0B;IAC9D,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAuB,EACvB,SAAiB,EACjB,OAAgB;IAEhB,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { loadSkillsCached, type SkillEntry } from "../skills/loader.js";
|
|
2
|
+
import type { EffortLevel, TokenUsage } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Sub-agent runner — spawns a fresh maestro loop for a delegated task.
|
|
5
|
+
*
|
|
6
|
+
* Architecture decisions (advisor-reviewed):
|
|
7
|
+
* - **No MCP in v1.** Sub-agents are scoped roles, not parent-lite. If
|
|
8
|
+
* MCP-rich exploration is needed, the user spawns a new topic.
|
|
9
|
+
* - **Inherit parent model + effort.** Uses `providerForModel()` to
|
|
10
|
+
* select the correct provider (Anthropic / DeepSeek) based on parent
|
|
11
|
+
* model. No override knob — keeps the model from picking a smaller
|
|
12
|
+
* model "to save cost" and missing things.
|
|
13
|
+
* - **Separate file-state tracker per sub-session.** Sharing the parent's
|
|
14
|
+
* would break the Read-before-Edit invariant in both directions.
|
|
15
|
+
* - **Inherit parent's systemPrompt + overlay.** Parent persona is the
|
|
16
|
+
* base; the sub-agent prompt adds the "you are a sub-agent" role.
|
|
17
|
+
* - **Hard JSONL cleanup on RETURN (success/failure).** NOT on abort —
|
|
18
|
+
* a parent abort mid-sub-call leaves the JSONL for postmortem and
|
|
19
|
+
* the 30-day TTL sweep eventually clears it.
|
|
20
|
+
* - **Silent by default.** Parent's event stream only carries the Agent
|
|
21
|
+
* tool's `tool_use` + final text. The sub-agent's text_deltas /
|
|
22
|
+
* tool_uses are NOT forwarded to telegram.
|
|
23
|
+
* - **depth=1 cap.** Sub-agents do NOT get the Agent tool — implicit
|
|
24
|
+
* because runSubAgent doesn't register one in the child registry.
|
|
25
|
+
* No recursion. Grandchildren require the parent to re-delegate.
|
|
26
|
+
*/
|
|
27
|
+
export type SubagentType = "general" | "explore";
|
|
28
|
+
export interface RunSubAgentOptions {
|
|
29
|
+
subagentType: SubagentType;
|
|
30
|
+
/** Self-contained task brief. The sub-agent sees only this as the user
|
|
31
|
+
* message. */
|
|
32
|
+
prompt: string;
|
|
33
|
+
/** Parent's resolved maestro sessionId. Used only for logging — the
|
|
34
|
+
* sub-agent has its own freshly-minted session id. */
|
|
35
|
+
parentSessionId: string;
|
|
36
|
+
/** Parent's augmented systemPrompt (caller-prompt + skills index).
|
|
37
|
+
* Used as the base layer of the sub-agent's prompt. */
|
|
38
|
+
parentSystemPrompt: string;
|
|
39
|
+
/** Parent's resolved model id (full, alias already expanded). */
|
|
40
|
+
parentModel: string;
|
|
41
|
+
/** Parent's effort level. Passed through to the provider (Anthropic:
|
|
42
|
+
* thinking budget; DeepSeek: reasoning_effort). */
|
|
43
|
+
parentEffort?: EffortLevel;
|
|
44
|
+
/** Parent's abort signal. When the parent aborts, the sub-agent's
|
|
45
|
+
* in-flight provider call cancels too. */
|
|
46
|
+
parentAbortSignal?: AbortSignal;
|
|
47
|
+
/** Pre-loaded skill catalog. Same set the parent sees. */
|
|
48
|
+
skills: SkillEntry[];
|
|
49
|
+
}
|
|
50
|
+
export interface RunSubAgentResult {
|
|
51
|
+
/** The sub-agent's final assistant text. This becomes the Agent tool's
|
|
52
|
+
* return value to the parent model. */
|
|
53
|
+
text: string;
|
|
54
|
+
/** Accumulated usage across every API call the sub-agent made. */
|
|
55
|
+
usage: TokenUsage;
|
|
56
|
+
/** The sub-agent's own session id. Surfaced for diagnostics + so the
|
|
57
|
+
* Agent tool can include it in the result text for traceability. */
|
|
58
|
+
subSessionId: string;
|
|
59
|
+
/** True when the parent's abort signal fired mid-execution. */
|
|
60
|
+
aborted: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Run a sub-agent to completion. Returns its final text + accumulated
|
|
64
|
+
* usage; the caller (Agent tool) decides how to surface that to the
|
|
65
|
+
* parent model.
|
|
66
|
+
*
|
|
67
|
+
* Cleanup contract (load-bearing):
|
|
68
|
+
* - Clean drain or thrown error → `deleteMaestroSession(subSessionId)`
|
|
69
|
+
* in the finally block. Frees the JSONL + file-state tracker + (any)
|
|
70
|
+
* todo store for this sub-session.
|
|
71
|
+
* - Abort → leave JSONL on disk. The 30-day TTL sweep will eventually
|
|
72
|
+
* clear it; meanwhile it's available for postmortem.
|
|
73
|
+
*/
|
|
74
|
+
export declare function runSubAgent(opts: RunSubAgentOptions): Promise<RunSubAgentResult>;
|
|
75
|
+
/** Convenience re-export for test setup — lets tests prime the loaded
|
|
76
|
+
* catalog without re-fetching from disk. */
|
|
77
|
+
export { loadSkillsCached };
|
|
78
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/sub-agent/runner.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAWpE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,YAAY,CAAC;IAC3B;mBACe;IACf,MAAM,EAAE,MAAM,CAAC;IACf;2DACuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB;4DACwD;IACxD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB;yDACqD;IACrD,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B;+CAC2C;IAC3C,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAChC,0DAA0D;IAC1D,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC;4CACwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,UAAU,CAAC;IAClB;yEACqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;CAClB;AAyED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA+GtF;AAgBD;6CAC6C;AAC7C,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|