@agent-plan/core 0.4.1 → 0.4.2

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.
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Agent Plan API v1 — the contract for programs outside Agent Plan.
3
+ *
4
+ * The stored schemas (schema.ts) are internal and change freely. The views in
5
+ * this file are what outside programs are promised: every field is picked by
6
+ * name, so a stored-schema change can never leak into the contract. Adding a
7
+ * field keeps `API_V1_VERSION`; removing or renaming one, or changing what it
8
+ * means, needs a new version (see docs/api-v1.md).
9
+ *
10
+ * Harness-agnostic: no server, Pi or MCP imports. The HTTP routes, the change
11
+ * events and any other adapter build on these same mappers.
12
+ */
13
+ import type { AcceptedDecision, Feature, Idea, Phase, Project, Task } from "./schema.js";
14
+ export declare const API_V1_VERSION = "1";
15
+ export interface ApiV1Envelope<T> {
16
+ apiVersion: typeof API_V1_VERSION;
17
+ data: T;
18
+ }
19
+ export interface ApiV1ErrorEnvelope {
20
+ apiVersion: typeof API_V1_VERSION;
21
+ error: {
22
+ code: string;
23
+ message: string;
24
+ };
25
+ }
26
+ export declare function apiV1Envelope<T>(data: T): ApiV1Envelope<T>;
27
+ export declare function apiV1Error(code: string, message: string): ApiV1ErrorEnvelope;
28
+ export type ApiV1EntityKind = "project" | "feature" | "phase" | "task" | "decision" | "handoff" | "idea";
29
+ export interface ApiV1Project {
30
+ name: string;
31
+ description: string;
32
+ goal: string;
33
+ guidelines: string;
34
+ guidelinesUpdatedAt: string;
35
+ scope: string[];
36
+ outOfScope: string[];
37
+ technologies: string[];
38
+ tools: string[];
39
+ contentLanguage: string;
40
+ chatLanguage: string;
41
+ }
42
+ export interface ApiV1Feature {
43
+ id: string;
44
+ ref: string;
45
+ shortId: string;
46
+ number: number;
47
+ name: string;
48
+ description: string;
49
+ status: string;
50
+ priority: number;
51
+ startDate: string;
52
+ endDate: string;
53
+ workDone: string;
54
+ workRemaining: string;
55
+ phaseRefs: string[];
56
+ dependsOn: string[];
57
+ createdAt: string;
58
+ updatedAt: string;
59
+ }
60
+ export interface ApiV1Phase {
61
+ id: string;
62
+ ref: string;
63
+ shortId: string;
64
+ number: number;
65
+ featureRef: string | null;
66
+ title: string;
67
+ summary: string;
68
+ description: string;
69
+ status: string;
70
+ priority: number;
71
+ goals: string[];
72
+ dependsOn: string[];
73
+ taskRefs: string[];
74
+ hasHandoff: boolean;
75
+ createdAt: string;
76
+ updatedAt: string;
77
+ }
78
+ export interface ApiV1ChecklistItem {
79
+ id: string;
80
+ number: number;
81
+ title: string;
82
+ checked: boolean;
83
+ }
84
+ export interface ApiV1TaskPause {
85
+ reason: string;
86
+ resumeLocation: string;
87
+ pausedAt: string;
88
+ }
89
+ export interface ApiV1Task {
90
+ id: string;
91
+ ref: string;
92
+ shortId: string;
93
+ number: number;
94
+ phaseRef: string;
95
+ featureRef: string | null;
96
+ title: string;
97
+ description: string;
98
+ status: string;
99
+ priority: number;
100
+ checklist: ApiV1ChecklistItem[];
101
+ dependsOn: string[];
102
+ pause: ApiV1TaskPause | null;
103
+ startedAt: string;
104
+ completedAt: string;
105
+ createdAt: string;
106
+ updatedAt: string;
107
+ }
108
+ export type ApiV1DecisionOwnerKind = "project" | "feature" | "phase" | "task";
109
+ export interface ApiV1AcceptedDecision {
110
+ id: string;
111
+ ref: string;
112
+ title: string;
113
+ decision: string;
114
+ rationale: string;
115
+ implementationNotes: string;
116
+ acceptedAt: string;
117
+ owner: {
118
+ kind: ApiV1DecisionOwnerKind;
119
+ ref: string | null;
120
+ };
121
+ }
122
+ export interface ApiV1Handoff {
123
+ phaseRef: string;
124
+ content: string;
125
+ updatedAt: string;
126
+ resumeReady: boolean;
127
+ resumeReadyAt: string;
128
+ }
129
+ export interface ApiV1Idea {
130
+ id: string;
131
+ ref: string;
132
+ shortId: string;
133
+ number: number;
134
+ title: string;
135
+ description: string;
136
+ promotion: {
137
+ targetType: string;
138
+ targetRef: string;
139
+ promotedAt: string;
140
+ } | null;
141
+ createdAt: string;
142
+ updatedAt: string;
143
+ }
144
+ /** Refs for every entity that other entities point at, built once per model. */
145
+ export interface ApiV1RefContext {
146
+ featureRefById: ReadonlyMap<string, string>;
147
+ phaseRefById: ReadonlyMap<string, string>;
148
+ taskRefById: ReadonlyMap<string, string>;
149
+ }
150
+ export interface ApiV1Source {
151
+ project: Project;
152
+ features: readonly Feature[];
153
+ phases: readonly Phase[];
154
+ ideas: readonly Idea[];
155
+ }
156
+ export interface ApiV1Model {
157
+ project: ApiV1Project;
158
+ features: ApiV1Feature[];
159
+ phases: ApiV1Phase[];
160
+ tasks: ApiV1Task[];
161
+ decisions: ApiV1AcceptedDecision[];
162
+ handoffs: ApiV1Handoff[];
163
+ ideas: ApiV1Idea[];
164
+ }
165
+ export declare function formatTaskRef(phaseRef: string, taskNumber: number): string;
166
+ export declare function buildApiV1RefContext(features: readonly Feature[], phases: readonly Phase[]): ApiV1RefContext;
167
+ export declare function toApiV1Project(project: Project): ApiV1Project;
168
+ export declare function toApiV1Feature(feature: Feature, context: ApiV1RefContext): ApiV1Feature;
169
+ export declare function toApiV1Phase(phase: Phase, context: ApiV1RefContext): ApiV1Phase;
170
+ export declare function toApiV1Task(task: Task, phase: Phase, context: ApiV1RefContext): ApiV1Task;
171
+ export declare function toApiV1Decision(decision: AcceptedDecision, owner: {
172
+ kind: ApiV1DecisionOwnerKind;
173
+ ref: string | null;
174
+ }): ApiV1AcceptedDecision;
175
+ /** The active handoff of a phase, or null when it has none (or the phase is finished). */
176
+ export declare function toApiV1Handoff(phase: Phase, context: ApiV1RefContext): ApiV1Handoff | null;
177
+ export declare function toApiV1Idea(idea: Idea): ApiV1Idea;
178
+ /** Every view of a loaded planner, with all cross-references turned into human refs. */
179
+ export declare function buildApiV1Model(source: ApiV1Source): ApiV1Model;
180
+ /** One entry per entity, with its parents, for change detection and indexes. */
181
+ export interface ApiV1EntityEntry {
182
+ kind: ApiV1EntityKind;
183
+ /** Unique within its kind. Decisions repeat ids across owners, so theirs includes the owner. */
184
+ key: string;
185
+ id: string;
186
+ ref: string;
187
+ parents: {
188
+ featureRef?: string;
189
+ phaseRef?: string;
190
+ };
191
+ view: unknown;
192
+ }
193
+ export declare function listApiV1Entities(model: ApiV1Model): ApiV1EntityEntry[];
194
+ //# sourceMappingURL=api-v1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-v1.d.ts","sourceRoot":"","sources":["../src/api-v1.ts"],"names":[],"mappings":"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"}
package/dist/api-v1.js ADDED
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Agent Plan API v1 — the contract for programs outside Agent Plan.
3
+ *
4
+ * The stored schemas (schema.ts) are internal and change freely. The views in
5
+ * this file are what outside programs are promised: every field is picked by
6
+ * name, so a stored-schema change can never leak into the contract. Adding a
7
+ * field keeps `API_V1_VERSION`; removing or renaming one, or changing what it
8
+ * means, needs a new version (see docs/api-v1.md).
9
+ *
10
+ * Harness-agnostic: no server, Pi or MCP imports. The HTTP routes, the change
11
+ * events and any other adapter build on these same mappers.
12
+ */
13
+ import { formatFeatureRef, formatIdeaRef, formatPhaseRef, formatThreeDigitNumber } from "./naming.js";
14
+ export const API_V1_VERSION = "1";
15
+ export function apiV1Envelope(data) {
16
+ return { apiVersion: API_V1_VERSION, data };
17
+ }
18
+ export function apiV1Error(code, message) {
19
+ return { apiVersion: API_V1_VERSION, error: { code, message } };
20
+ }
21
+ /** A phase in one of these statuses has no active handoff (it is archived). */
22
+ const TERMINAL_PHASE_STATUSES = new Set(["done", "canceled", "rejected"]);
23
+ export function formatTaskRef(phaseRef, taskNumber) {
24
+ return `${phaseRef}/T${formatThreeDigitNumber(taskNumber)}`;
25
+ }
26
+ export function buildApiV1RefContext(features, phases) {
27
+ const featureNumberById = new Map(features.map((feature) => [feature.id, feature.number]));
28
+ const featureRefById = new Map(features.map((feature) => [feature.id, formatFeatureRef(feature.number)]));
29
+ const phaseRefById = new Map();
30
+ const taskRefById = new Map();
31
+ for (const phase of phases) {
32
+ const featureNumber = phase.featureId ? featureNumberById.get(phase.featureId) : undefined;
33
+ const phaseRef = formatPhaseRef(phase.number, featureNumber);
34
+ phaseRefById.set(phase.id, phaseRef);
35
+ for (const task of phase.tasks)
36
+ taskRefById.set(task.id, formatTaskRef(phaseRef, task.number));
37
+ }
38
+ return { featureRefById, phaseRefById, taskRefById };
39
+ }
40
+ /** A dependency that no longer resolves keeps its stored id rather than vanishing. */
41
+ function refsOf(ids, refById) {
42
+ return ids.map((id) => refById.get(id) ?? id);
43
+ }
44
+ export function toApiV1Project(project) {
45
+ return {
46
+ name: project.name,
47
+ description: project.description,
48
+ goal: project.goal,
49
+ guidelines: project.projectGuidelines.content,
50
+ guidelinesUpdatedAt: project.projectGuidelines.updatedAt,
51
+ scope: [...project.scope],
52
+ outOfScope: [...project.outOfScope],
53
+ technologies: [...project.technologies],
54
+ tools: [...project.tools],
55
+ contentLanguage: project.contentLanguage,
56
+ chatLanguage: project.chatLanguage,
57
+ };
58
+ }
59
+ export function toApiV1Feature(feature, context) {
60
+ return {
61
+ id: feature.id,
62
+ ref: formatFeatureRef(feature.number),
63
+ shortId: feature.shortId,
64
+ number: feature.number,
65
+ name: feature.name,
66
+ description: feature.description,
67
+ status: feature.status,
68
+ priority: feature.priority,
69
+ startDate: feature.startDate,
70
+ endDate: feature.endDate,
71
+ workDone: feature.workDone,
72
+ workRemaining: feature.workRemaining,
73
+ phaseRefs: refsOf(feature.phaseIds, context.phaseRefById),
74
+ dependsOn: refsOf(feature.dependsOn, context.featureRefById),
75
+ createdAt: feature.createdAt,
76
+ updatedAt: feature.updatedAt,
77
+ };
78
+ }
79
+ export function toApiV1Phase(phase, context) {
80
+ return {
81
+ id: phase.id,
82
+ ref: context.phaseRefById.get(phase.id) ?? formatPhaseRef(phase.number),
83
+ shortId: phase.shortId,
84
+ number: phase.number,
85
+ featureRef: phase.featureId ? context.featureRefById.get(phase.featureId) ?? null : null,
86
+ title: phase.title,
87
+ summary: phase.summary,
88
+ description: phase.description,
89
+ status: phase.status,
90
+ priority: phase.priority,
91
+ goals: [...phase.goals],
92
+ dependsOn: refsOf(phase.dependsOn, context.phaseRefById),
93
+ taskRefs: phase.tasks.map((task) => context.taskRefById.get(task.id) ?? task.id),
94
+ hasHandoff: hasActiveHandoff(phase),
95
+ createdAt: phase.createdAt,
96
+ updatedAt: phase.updatedAt,
97
+ };
98
+ }
99
+ export function toApiV1Task(task, phase, context) {
100
+ return {
101
+ id: task.id,
102
+ ref: context.taskRefById.get(task.id) ?? formatTaskRef(formatPhaseRef(phase.number), task.number),
103
+ shortId: task.shortId,
104
+ number: task.number,
105
+ phaseRef: context.phaseRefById.get(phase.id) ?? formatPhaseRef(phase.number),
106
+ featureRef: phase.featureId ? context.featureRefById.get(phase.featureId) ?? null : null,
107
+ title: task.title,
108
+ description: task.description,
109
+ status: task.status,
110
+ priority: task.priority,
111
+ checklist: task.checklist.map((item) => {
112
+ // The schema transform always expands string items into objects.
113
+ const entry = typeof item === "string" ? { id: item, number: 0, title: item, checked: false } : item;
114
+ return { id: entry.id, number: entry.number, title: entry.title, checked: entry.checked };
115
+ }),
116
+ dependsOn: refsOf(task.dependsOn, context.taskRefById),
117
+ pause: task.pauseSnapshot
118
+ ? { reason: task.pauseSnapshot.reason, resumeLocation: task.pauseSnapshot.resumeLocation, pausedAt: task.pauseSnapshot.pausedAt }
119
+ : null,
120
+ startedAt: task.startedAt,
121
+ completedAt: task.completedAt,
122
+ createdAt: task.createdAt,
123
+ updatedAt: task.updatedAt,
124
+ };
125
+ }
126
+ export function toApiV1Decision(decision, owner) {
127
+ return {
128
+ id: decision.id,
129
+ ref: `${owner.ref ?? "project"}#${decision.id}`,
130
+ title: decision.title,
131
+ decision: decision.decision,
132
+ rationale: decision.rationale,
133
+ implementationNotes: decision.implementationNotes,
134
+ acceptedAt: decision.acceptedAt,
135
+ owner: { kind: owner.kind, ref: owner.ref },
136
+ };
137
+ }
138
+ function hasActiveHandoff(phase) {
139
+ return phase.handoff.length > 0 && !TERMINAL_PHASE_STATUSES.has(phase.status);
140
+ }
141
+ /** The active handoff of a phase, or null when it has none (or the phase is finished). */
142
+ export function toApiV1Handoff(phase, context) {
143
+ if (!hasActiveHandoff(phase))
144
+ return null;
145
+ const resumeReadyAt = phase.handoffAudit?.resumeReadyAt ?? "";
146
+ return {
147
+ phaseRef: context.phaseRefById.get(phase.id) ?? formatPhaseRef(phase.number),
148
+ content: phase.handoff,
149
+ updatedAt: phase.handoffUpdatedAt || phase.updatedAt,
150
+ resumeReady: resumeReadyAt !== "",
151
+ resumeReadyAt,
152
+ };
153
+ }
154
+ export function toApiV1Idea(idea) {
155
+ return {
156
+ id: idea.id,
157
+ ref: formatIdeaRef(idea.number),
158
+ shortId: idea.shortId,
159
+ number: idea.number,
160
+ title: idea.title,
161
+ description: idea.description,
162
+ promotion: idea.promotion
163
+ ? { targetType: idea.promotion.targetType, targetRef: idea.promotion.targetRef, promotedAt: idea.promotion.promotedAt }
164
+ : null,
165
+ createdAt: idea.createdAt,
166
+ updatedAt: idea.updatedAt,
167
+ };
168
+ }
169
+ /** Every view of a loaded planner, with all cross-references turned into human refs. */
170
+ export function buildApiV1Model(source) {
171
+ const context = buildApiV1RefContext(source.features, source.phases);
172
+ const decisions = source.project.acceptedDecisions.map((decision) => toApiV1Decision(decision, { kind: "project", ref: null }));
173
+ for (const feature of source.features) {
174
+ const owner = { kind: "feature", ref: formatFeatureRef(feature.number) };
175
+ for (const decision of feature.acceptedDecisions)
176
+ decisions.push(toApiV1Decision(decision, owner));
177
+ }
178
+ const tasks = [];
179
+ const handoffs = [];
180
+ for (const phase of source.phases) {
181
+ const phaseRef = context.phaseRefById.get(phase.id) ?? formatPhaseRef(phase.number);
182
+ for (const decision of phase.acceptedDecisions)
183
+ decisions.push(toApiV1Decision(decision, { kind: "phase", ref: phaseRef }));
184
+ const handoff = toApiV1Handoff(phase, context);
185
+ if (handoff)
186
+ handoffs.push(handoff);
187
+ for (const task of phase.tasks) {
188
+ tasks.push(toApiV1Task(task, phase, context));
189
+ const taskRef = context.taskRefById.get(task.id) ?? task.id;
190
+ for (const decision of task.acceptedDecisions)
191
+ decisions.push(toApiV1Decision(decision, { kind: "task", ref: taskRef }));
192
+ }
193
+ }
194
+ return {
195
+ project: toApiV1Project(source.project),
196
+ features: source.features.map((feature) => toApiV1Feature(feature, context)),
197
+ phases: source.phases.map((phase) => toApiV1Phase(phase, context)),
198
+ tasks,
199
+ decisions,
200
+ handoffs,
201
+ ideas: source.ideas.map(toApiV1Idea),
202
+ };
203
+ }
204
+ export function listApiV1Entities(model) {
205
+ const entries = [
206
+ { kind: "project", key: "project", id: "project", ref: "project", parents: {}, view: model.project },
207
+ ];
208
+ for (const feature of model.features) {
209
+ entries.push({ kind: "feature", key: feature.id, id: feature.id, ref: feature.ref, parents: {}, view: feature });
210
+ }
211
+ for (const phase of model.phases) {
212
+ entries.push({ kind: "phase", key: phase.id, id: phase.id, ref: phase.ref, parents: phase.featureRef ? { featureRef: phase.featureRef } : {}, view: phase });
213
+ }
214
+ for (const task of model.tasks) {
215
+ entries.push({
216
+ kind: "task", key: task.id, id: task.id, ref: task.ref,
217
+ parents: { ...(task.featureRef ? { featureRef: task.featureRef } : {}), phaseRef: task.phaseRef },
218
+ view: task,
219
+ });
220
+ }
221
+ for (const decision of model.decisions) {
222
+ entries.push({ kind: "decision", key: decision.ref, id: decision.id, ref: decision.ref, parents: {}, view: decision });
223
+ }
224
+ for (const handoff of model.handoffs) {
225
+ entries.push({ kind: "handoff", key: handoff.phaseRef, id: handoff.phaseRef, ref: handoff.phaseRef, parents: { phaseRef: handoff.phaseRef }, view: handoff });
226
+ }
227
+ for (const idea of model.ideas) {
228
+ entries.push({ kind: "idea", key: idea.id, id: idea.id, ref: idea.ref, parents: {}, view: idea });
229
+ }
230
+ return entries;
231
+ }
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Every adapter (MCP, Pi, and any future harness) calls the same builders
5
5
  * here instead of assembling its own text/structuredContent pair. Each
6
- * builder returns exactly one copy of every piece of information: the
7
- * human-readable channel (`text`) and the machine-readable channel
8
- * (`structured`) never both carry the same field. Which channel is
6
+ * builder returns one canonical structured shape plus human-readable text.
7
+ * Most large fields still live in only one channel, but the handoff body is
8
+ * deliberately duplicated in `structured.content` for hosts that expose only
9
+ * structuredContent to the agent. Which channel is
9
10
  * canonical for a given piece of content is decided per field below, based
10
11
  * on what a structuredContent-only host needs in order to act (see the
11
12
  * per-field comments) rather than by a single blanket rule — see AGENTS.md
@@ -74,13 +75,11 @@ export type HandoffShowReplyInput = {
74
75
  * empty, archived, and active branches through one shared shape so no
75
76
  * surface keeps its own construction.
76
77
  *
77
- * Placement: the resume capsule body is prose meant to be read, and every
78
- * existing consumer reads it from `text` (never from `structured`), so
79
- * `text` is its one home; `structured` carries only `fullLength`/
80
- * `truncated` flags plus the identifiers, hash, and verification flags a
81
- * structuredContent-only host needs to drive the candidate-then-verify
82
- * contract (call verify with the right hash) without needing the prose
83
- * itself.
78
+ * Placement: the resume capsule body is prose that must be read by the
79
+ * agent before verify/resume. It is intentionally present in both `text` and
80
+ * `structured.content`; some hosts surface only structuredContent, and a
81
+ * phase ref plus hash is not enough to resume safely. `fullLength` and
82
+ * `truncated` describe the bounded body in both channels.
84
83
  */
85
84
  export declare function buildHandoffShowReply(input: HandoffShowReplyInput): HandoffReply;
86
85
  /** Single source of truth for the prepare-reply evidence-contract sentence,
@@ -1 +1 @@
1
- {"version":3,"file":"handoff-reply.d.ts","sourceRoot":"","sources":["../src/handoff-reply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAA6B,KAAK,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,GAAE,SAAS,GAAG,aAAyB,GAAG,aAAa,CAMrI;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;oBAMoB;AACpB,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAKjF;AA8CD;6CAC6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAmCD,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC/C,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC/C,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEN;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAsEhF;AAED;wDACwD;AACxD,eAAO,MAAM,iCAAiC,0IAC2F,CAAC;AAE1I,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,wBAAwB,GAAG,YAAY,CAkFtF"}
1
+ {"version":3,"file":"handoff-reply.d.ts","sourceRoot":"","sources":["../src/handoff-reply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,wBAAwB,EAA6B,KAAK,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,GAAE,SAAS,GAAG,aAAyB,GAAG,aAAa,CAMrI;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;oBAMoB;AACpB,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAKjF;AA8CD;6CAC6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAmCD,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC/C,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC/C,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEN;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAwEhF;AAED;wDACwD;AACxD,eAAO,MAAM,iCAAiC,0IAC2F,CAAC;AAE1I,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,wBAAwB,GAAG,YAAY,CAkFtF"}
@@ -105,13 +105,11 @@ function handoffAuditForTransport(audit) {
105
105
  * empty, archived, and active branches through one shared shape so no
106
106
  * surface keeps its own construction.
107
107
  *
108
- * Placement: the resume capsule body is prose meant to be read, and every
109
- * existing consumer reads it from `text` (never from `structured`), so
110
- * `text` is its one home; `structured` carries only `fullLength`/
111
- * `truncated` flags plus the identifiers, hash, and verification flags a
112
- * structuredContent-only host needs to drive the candidate-then-verify
113
- * contract (call verify with the right hash) without needing the prose
114
- * itself.
108
+ * Placement: the resume capsule body is prose that must be read by the
109
+ * agent before verify/resume. It is intentionally present in both `text` and
110
+ * `structured.content`; some hosts surface only structuredContent, and a
111
+ * phase ref plus hash is not enough to resume safely. `fullLength` and
112
+ * `truncated` describe the bounded body in both channels.
115
113
  */
116
114
  export function buildHandoffShowReply(input) {
117
115
  if (input.kind === "empty") {
@@ -148,6 +146,7 @@ export function buildHandoffShowReply(input) {
148
146
  archiveFile: input.archiveFile,
149
147
  fullLength: bounded.fullLength,
150
148
  truncated: bounded.truncated,
149
+ content: bounded.content,
151
150
  supportingDocuments,
152
151
  empty: false,
153
152
  resumeReady: false,
@@ -174,6 +173,7 @@ export function buildHandoffShowReply(input) {
174
173
  phaseWorkMap: workMapForTransport(phaseWorkMap, false),
175
174
  fullLength: bounded.fullLength,
176
175
  truncated: bounded.truncated,
176
+ content: bounded.content,
177
177
  contentHash,
178
178
  persistenceVerified,
179
179
  resumeReady,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./naming.js";
2
+ export * from "./api-v1.js";
3
+ export * from "./session-focus.js";
2
4
  export * from "./refs.js";
3
5
  export * from "./render-utils.js";
4
6
  export * from "./pagination.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,kCAAkC,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,KAAK,2BAA2B,EAAE,KAAK,2BAA2B,EAAE,KAAK,6BAA6B,EAAE,KAAK,8BAA8B,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3hB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,kCAAkC,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,KAAK,2BAA2B,EAAE,KAAK,2BAA2B,EAAE,KAAK,6BAA6B,EAAE,KAAK,8BAA8B,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3hB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./naming.js";
2
+ export * from "./api-v1.js";
3
+ export * from "./session-focus.js";
2
4
  export * from "./refs.js";
3
5
  export * from "./render-utils.js";
4
6
  export * from "./pagination.js";
@@ -256,6 +256,7 @@ export declare class PlanStore {
256
256
  private generatedDir;
257
257
  private codebasePath;
258
258
  private resumePath;
259
+ private resumeSessionsPath;
259
260
  private activityPath;
260
261
  private projectContextReadsPath;
261
262
  private localRoot;
@@ -303,7 +304,8 @@ export declare class PlanStore {
303
304
  /** Read-only manifest load. Upgrading legacy `.local` state is explicit
304
305
  * maintenance (`repair`), never an incidental side effect of opening a plan. */
305
306
  loadManifest(): Promise<Manifest>;
306
- loadProject(): Promise<Project>;
307
+ /** With a session id, `workDeviations` holds only that session's side tasks (plus unowned legacy ones); without, all of them. */
308
+ loadProject(sessionId?: string): Promise<Project>;
307
309
  /**
308
310
  * Reserve immutable human identifiers without touching tracked `project.json`.
309
311
  * Worktrees in the same clone share `.git/agent-plan/allocations`, guarded by
@@ -331,8 +333,17 @@ export declare class PlanStore {
331
333
  loadFeatures(): Promise<FeaturesDocument>;
332
334
  loadCodebaseProfile(): Promise<CodebaseProfile | null>;
333
335
  saveCodebaseProfile(profile: CodebaseProfile): Promise<void>;
334
- loadResume(): Promise<ResumeFocus | null>;
335
- saveResume(resume: ResumeFocus): Promise<void>;
336
+ /** The project-level resume focus (the one a sessionless caller sees). */
337
+ private loadProjectResume;
338
+ private loadResumeSessions;
339
+ /** Read-modify-write of the per-session entries under the planner's write lock. */
340
+ private updateResumeSessions;
341
+ /**
342
+ * The resume focus. With a session id, that session's own entry; a session that has
343
+ * none yet inherits the project-level focus for reading. Without one, the project-level focus.
344
+ */
345
+ loadResume(sessionId?: string): Promise<ResumeFocus | null>;
346
+ saveResume(resume: ResumeFocus, sessionId?: string): Promise<void>;
336
347
  /**
337
348
  * Authorize a temporary guard bypass so edit/write tools may proceed even
338
349
  * when no task is in-progress. Harness-agnostic: stored in resume.json so
@@ -347,7 +358,7 @@ export declare class PlanStore {
347
358
  loadActivityLog(): Promise<ActivityLog>;
348
359
  appendActivity(type: string, ref: string, summary: string): Promise<ActivityEntry>;
349
360
  /** Derive an up-to-date resume focus from the current workspace state. */
350
- refreshResume(notes?: string, lastSessionSummary?: string): Promise<ResumeFocus>;
361
+ refreshResume(notes?: string, lastSessionSummary?: string, sessionId?: string): Promise<ResumeFocus>;
351
362
  loadRequirements(): Promise<RequirementsDocument>;
352
363
  loadIdeas(): Promise<IdeasDocument>;
353
364
  linkedRequirementsForPhase(phaseId: string): Promise<Requirement[]>;
@@ -460,8 +471,12 @@ export declare class PlanStore {
460
471
  /** Apply and verify the legacy project-context migration. Callers must invoke
461
472
  * this only from an explicit preparation or compatibility-recovery flow. */
462
473
  migrateLegacyProjectContext(): Promise<LegacyProjectContextMigrationResult>;
474
+ /** Every session's side tasks. Selection needs them all: recommendNextTask hides other sessions' on its own. */
475
+ listAllWorkDeviations(): Promise<WorkDeviation[]>;
463
476
  /** Persist an explicitly approved work deviation without coupling it to a harness. */
464
- addWorkDeviation(deviation: WorkDeviation): Promise<Project>;
477
+ addWorkDeviation(deviation: Omit<WorkDeviation, "ownerSession"> & {
478
+ ownerSession?: string;
479
+ }, sessionId?: string): Promise<Project>;
465
480
  /** Advance a deviation while retaining its complete audit and return stack. */
466
481
  setWorkDeviationState(id: string, state: "active" | "resume-required" | "resolved" | "resumed" | "canceled", timestamp?: string): Promise<Project>;
467
482
  updateFeatures(updater: (f: FeaturesDocument) => FeaturesDocument): Promise<FeaturesDocument>;