@emiliosp/pi-maestro 0.9.2 → 0.9.4
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
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This file summarizes meaningful changes to the codebase, including behavior, data formats, architecture, and development tools. Git tags identify version boundaries; GitHub Releases are not required. Version-only changes and routine maintenance are omitted.
|
|
4
4
|
|
|
5
|
+
## 0.9.3
|
|
6
|
+
|
|
7
|
+
1. Added a parent `pi-subagents` availability check during activation. A matching successful version 1 `ping` reply is required within 2000 ms. See [PR #35](https://github.com/emilioSp/pi-maestro/pull/35).
|
|
8
|
+
2. Failed or invalid replies, emission errors, and timeouts prevent activation. The error includes "Maestro flow requires pi-subagents installed in the Pi environment." The check makes no automatic retry.
|
|
9
|
+
3. Preserved existing activation checks, UI-only notices, and unchanged session history. The availability check starts no agent, makes no model request, and does not run when turning `Maestro` off.
|
|
10
|
+
|
|
5
11
|
## 0.9.2
|
|
6
12
|
|
|
7
13
|
1. Added code-quality review to `verifier` guidance for code affected by the approved change when applicable `AGENTS.md` directives exist. See [PR #34](https://github.com/emilioSp/pi-maestro/pull/34). All existing verification duties remain unchanged.
|
package/ROADMAP.md
CHANGED
|
@@ -74,25 +74,19 @@ All 5 `acceptance criteria` passed through independent inspection of the written
|
|
|
74
74
|
|
|
75
75
|
[Specification](.specs/20261013-185941-verify-code-quality-against-agents-md-instructions/spec.md), [verifier report](.specs/20261013-185941-verify-code-quality-against-agents-md-instructions/handoffs/verifier/V1.json), and [merged PR #34](https://github.com/emilioSp/pi-maestro/pull/34).
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## Next
|
|
80
|
-
|
|
81
|
-
## Later
|
|
82
|
-
|
|
83
|
-
These items need scope review before `specification` approval. Existing behavior must be checked before adding new code. Dependencies between these items are not yet agreed.
|
|
77
|
+
### R-06: Check subagent extensions at activation
|
|
84
78
|
|
|
85
|
-
|
|
79
|
+
Implemented in `0.9.3`. Activation requires a matching successful version 1 `ping` reply from the parent `pi-subagents` extension within 2000 ms. A failed or invalid reply, emission error, or timeout prevents activation and reports the installation requirement. The check starts no agent and makes no model request. It confirms parent extension availability, not child execution readiness.
|
|
86
80
|
|
|
87
|
-
|
|
81
|
+
All 7 `acceptance criteria` passed using controlled replies and code inspection, with no `verifier` `findings`. The saved workflow reached `candidate-ready`.
|
|
88
82
|
|
|
89
|
-
|
|
83
|
+
A later integration test requested by the `owner` directly checks the environment check's failed-reply error. This test addition is outside the completed independent verification.
|
|
90
84
|
|
|
91
|
-
|
|
85
|
+
#### Evidence
|
|
92
86
|
|
|
93
|
-
|
|
87
|
+
[Specification](.specs/20261013-194407-check-pi-subagents-availability-with-ping-at-activation/spec.md), [verifier report](.specs/20261013-194407-check-pi-subagents-availability-with-ping-at-activation/handoffs/verifier/V1.json), and [merged PR #35](https://github.com/emilioSp/pi-maestro/pull/35).
|
|
94
88
|
|
|
95
|
-
|
|
89
|
+
## Now
|
|
96
90
|
|
|
97
91
|
### R-05: Keep acceptance criterion numbering continuous
|
|
98
92
|
|
|
@@ -100,19 +94,33 @@ Package metadata and installation documentation use the new name. The package is
|
|
|
100
94
|
|
|
101
95
|
When criteria are removed during `spec` preparation or revision, renumber the remaining criteria without gaps. Numbering starts at `AC1` and continues through the final criterion.
|
|
102
96
|
|
|
97
|
+
#### Current state
|
|
98
|
+
|
|
99
|
+
Implemented approval-time numbering validation and `Maestro` guidance for numbering-only recovery using the existing GREEN FLAG. Rejected numbering leaves saved files unchanged. Independent verification is pending.
|
|
100
|
+
|
|
101
|
+
[Specification](.specs/20261013-202811-check-acceptance-criterion-numbering-before-builder-execution/spec.md).
|
|
102
|
+
|
|
103
103
|
#### Completed when
|
|
104
104
|
|
|
105
105
|
The `spec` and its current references use consistent numbering.
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
## Next
|
|
108
|
+
|
|
109
|
+
## Later
|
|
110
|
+
|
|
111
|
+
These items need scope review before `specification` approval. Existing behavior must be checked before adding new code. Dependencies between these items are not yet agreed.
|
|
112
|
+
|
|
113
|
+
### R-04: Rename the npm package
|
|
108
114
|
|
|
109
115
|
#### Objective
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
Rename `@emiliosp/pi-maestro` to `pi-maestro-sdd`. The `owner` installs the package under the new name. This item changes the package identity, not the development workflow.
|
|
118
|
+
|
|
119
|
+
Compatibility with installations under the old name must be decided in the `specification`. No `specification` is approved yet.
|
|
112
120
|
|
|
113
121
|
#### Completed when
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
Package metadata and installation documentation use the new name. The package is available under that name.
|
|
116
124
|
|
|
117
125
|
### R-07: Guide initial configuration
|
|
118
126
|
|
package/extensions/maestro.ts
CHANGED
package/package.json
CHANGED
|
@@ -3,12 +3,26 @@
|
|
|
3
3
|
* Used: When the owner activates Maestro mode.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
6
7
|
import { realpath } from 'node:fs/promises';
|
|
7
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
ExtensionAPI,
|
|
10
|
+
ExtensionContext,
|
|
11
|
+
} from '@earendil-works/pi-coding-agent';
|
|
8
12
|
import { resolveSubagentLaunchContract } from 'pi-subagents/preflight';
|
|
9
13
|
import { loadConfiguration } from '#config/loadConfiguration.ts';
|
|
10
14
|
import { AGENTS } from '#config/schema.ts';
|
|
11
15
|
|
|
16
|
+
export const SUBAGENT_PING = {
|
|
17
|
+
REQUEST_EVENT: 'subagents:rpc:v1:request',
|
|
18
|
+
REPLY_EVENT_PREFIX: 'subagents:rpc:v1:reply:',
|
|
19
|
+
VERSION: 1,
|
|
20
|
+
METHOD: 'ping',
|
|
21
|
+
TIMEOUT_MS: 2000,
|
|
22
|
+
INSTALLATION_ERROR:
|
|
23
|
+
'Maestro flow requires pi-subagents installed in the Pi environment.',
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
12
26
|
const getErrorMessage = (error: unknown): string =>
|
|
13
27
|
error instanceof Error ? error.message : String(error);
|
|
14
28
|
|
|
@@ -76,9 +90,81 @@ async function assertAgentsAvailable(projectRoot: string): Promise<void> {
|
|
|
76
90
|
}
|
|
77
91
|
}
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
93
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
94
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
95
|
+
|
|
96
|
+
const isReplyWithRequestId = (
|
|
97
|
+
reply: unknown,
|
|
98
|
+
): reply is Record<string, unknown> & { requestId: string } =>
|
|
99
|
+
isRecord(reply) && typeof reply.requestId === 'string';
|
|
100
|
+
|
|
101
|
+
type SuccessfulPingReply = {
|
|
102
|
+
version: typeof SUBAGENT_PING.VERSION;
|
|
103
|
+
requestId: string;
|
|
104
|
+
method: typeof SUBAGENT_PING.METHOD;
|
|
105
|
+
success: true;
|
|
106
|
+
data: { version: typeof SUBAGENT_PING.VERSION };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function assertSuccessfulPingReply(
|
|
110
|
+
reply: unknown,
|
|
111
|
+
): asserts reply is SuccessfulPingReply {
|
|
112
|
+
if (
|
|
113
|
+
!isReplyWithRequestId(reply) ||
|
|
114
|
+
reply.version !== SUBAGENT_PING.VERSION ||
|
|
115
|
+
reply.method !== SUBAGENT_PING.METHOD ||
|
|
116
|
+
reply.success !== true ||
|
|
117
|
+
!isRecord(reply.data) ||
|
|
118
|
+
reply.data.version !== SUBAGENT_PING.VERSION
|
|
119
|
+
) {
|
|
120
|
+
throw new Error('Unsuccessful or invalid pi-subagents ping reply.');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function assertSubagentsRespond(
|
|
125
|
+
piEventsBus: ExtensionAPI['events'],
|
|
81
126
|
): Promise<void> {
|
|
127
|
+
const requestId = randomUUID();
|
|
128
|
+
const { promise, resolve, reject } = Promise.withResolvers<unknown>();
|
|
129
|
+
|
|
130
|
+
const unsubscribe = piEventsBus.on(
|
|
131
|
+
`${SUBAGENT_PING.REPLY_EVENT_PREFIX}${requestId}`,
|
|
132
|
+
(reply) => {
|
|
133
|
+
if (isReplyWithRequestId(reply) && reply.requestId !== requestId) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
resolve(reply);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const timeout = setTimeout(
|
|
142
|
+
() => reject(new Error('Pi-subagents ping timed out after 2000 ms.')),
|
|
143
|
+
SUBAGENT_PING.TIMEOUT_MS,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
piEventsBus.emit(SUBAGENT_PING.REQUEST_EVENT, {
|
|
148
|
+
version: SUBAGENT_PING.VERSION,
|
|
149
|
+
requestId,
|
|
150
|
+
method: SUBAGENT_PING.METHOD,
|
|
151
|
+
});
|
|
152
|
+
assertSuccessfulPingReply(await promise);
|
|
153
|
+
} finally {
|
|
154
|
+
clearTimeout(timeout);
|
|
155
|
+
unsubscribe();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
type AssertEnvironmentInput = {
|
|
160
|
+
context: ExtensionContext;
|
|
161
|
+
piEventsBus: ExtensionAPI['events'];
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export async function assertEnvironment({
|
|
165
|
+
context,
|
|
166
|
+
piEventsBus,
|
|
167
|
+
}: AssertEnvironmentInput): Promise<void> {
|
|
82
168
|
const projectRoot = await getProjectRoot(context);
|
|
83
169
|
|
|
84
170
|
try {
|
|
@@ -92,4 +178,13 @@ export async function assertEnvironment(
|
|
|
92
178
|
const config = await getActivationConfiguration(projectRoot);
|
|
93
179
|
|
|
94
180
|
assertModelsAvailable({ context, config });
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
await assertSubagentsRespond(piEventsBus);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`${SUBAGENT_PING.INSTALLATION_ERROR} ${getErrorMessage(error)}`,
|
|
187
|
+
{ cause: error },
|
|
188
|
+
);
|
|
189
|
+
}
|
|
95
190
|
}
|
|
@@ -54,6 +54,14 @@ Wait for each tool result before taking the next workflow action. Do not launch
|
|
|
54
54
|
10. On approval, freeze the spec as the contract. Call maestro_mark_spec_ready with the active specId.
|
|
55
55
|
11. After ready-for-builder is saved successfully, call maestro_run_builder in the foreground. Do not request a separate start approval.
|
|
56
56
|
|
|
57
|
+
If maestro_mark_spec_ready fails with "Fix acceptance criterion ordering in spec.md." after GREEN FLAG, keep the current phase unchanged.
|
|
58
|
+
In drafting-spec, escalation-decision, or findings-decision, correct only numbering and affected references in the current spec.md.
|
|
59
|
+
Do not change criterion order or requirements.
|
|
60
|
+
For example, change headings AC1 and AC3 to AC1 and AC2, and change the affected AC3 references to AC2.
|
|
61
|
+
Retry maestro_mark_spec_ready with the active specId using the existing GREEN FLAG. Do not request another approval.
|
|
62
|
+
After the transition succeeds, call maestro_run_builder in the foreground.
|
|
63
|
+
This edit exception applies only to failed numbering validation. It does not apply after successful approval or during agent runs.
|
|
64
|
+
|
|
57
65
|
Write spec.md for the owner. Keep detail proportional to the change and state each requirement once.
|
|
58
66
|
Use the template topics as guidance. Omit empty subsections instead of filling them with Not applicable.
|
|
59
67
|
Keep behavior, scope, constraints, and approved architectural decisions in the spec. Leave routine implementation choices to the builder.
|
|
@@ -74,6 +82,7 @@ In spec.md, keep only a brief reason, essential references, and unresolved limit
|
|
|
74
82
|
### Spec edits, checks, and experiments
|
|
75
83
|
|
|
76
84
|
Edit the active spec.md and its prototypes/ directory only in drafting-spec or during owner-directed contract revisions in decision phases.
|
|
85
|
+
The numbering-only recovery procedure above also permits spec.md corrections after failed numbering validation in those phases.
|
|
77
86
|
The decision phases are escalation-decision and findings-decision. Do not edit the spec or prototypes in other phases.
|
|
78
87
|
The approved spec is frozen. Never change it during builder or verifier execution.
|
|
79
88
|
Use any available tool for these permitted edits. Do not change other workflow artifacts.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Used: When the owner approves the spec content.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
6
7
|
import type { MaestroPaths } from '#MaestroPaths.ts';
|
|
7
8
|
import { pathExists } from '#utils/path-exists.ts';
|
|
8
9
|
import { readWorkflowState } from '#workflow/state/readWorkflowState.ts';
|
|
@@ -10,6 +11,14 @@ import { WORKFLOW_EVENTS, type WorkflowState } from '#workflow/state/schema.ts';
|
|
|
10
11
|
import { writeWorkflowState } from '#workflow/state/writeWorkflowState.ts';
|
|
11
12
|
import { transitionWorkflow } from '#workflow/transitions.ts';
|
|
12
13
|
|
|
14
|
+
function assertAcceptanceCriterionOrdering(markdown: string): void {
|
|
15
|
+
const criteria = [...markdown.matchAll(/^### AC(\d+):/gm)];
|
|
16
|
+
|
|
17
|
+
if (criteria.some((match, index) => Number(match[1]) !== index + 1)) {
|
|
18
|
+
throw new Error('Fix acceptance criterion ordering in spec.md.');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
type MarkSpecReadyInput = {
|
|
14
23
|
paths: MaestroPaths;
|
|
15
24
|
specId: string;
|
|
@@ -51,6 +60,8 @@ export const markSpecReady = async ({
|
|
|
51
60
|
event: WORKFLOW_EVENTS.MARK_SPEC_READY,
|
|
52
61
|
});
|
|
53
62
|
|
|
63
|
+
assertAcceptanceCriterionOrdering(await readFile(specFilePath, 'utf8'));
|
|
64
|
+
|
|
54
65
|
await writeWorkflowState({
|
|
55
66
|
path: workflowPath,
|
|
56
67
|
state,
|