@guanlin4924/devflow-pi 0.1.51 → 0.1.52
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/package.json
CHANGED
|
@@ -369,7 +369,7 @@ export function isRequirementDraftToolAllowed(toolName: string, input: unknown,
|
|
|
369
369
|
return normalized === "task" && taskAgents.length > 0 && taskAgents.every(agent => PLANNING_AGENTS.has(agent));
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
type InternalDevflowControlResource = "contract" | "state" | "mainflow";
|
|
372
|
+
type InternalDevflowControlResource = "contract" | "state" | "mainflow" | "requirement_graph";
|
|
373
373
|
|
|
374
374
|
/** Resolve an xdev target only when all supplied target aliases agree.
|
|
375
375
|
* A direct/eval caller can otherwise provide `path` for a real file plus an
|
|
@@ -394,6 +394,7 @@ export function internalDevflowControlResource(toolName: string, input: unknown)
|
|
|
394
394
|
if (target === "xd://devflow_contract") return "contract";
|
|
395
395
|
if (target === "xd://devflow_state") return "state";
|
|
396
396
|
if (target === "xd://devflow_mainflow") return "mainflow";
|
|
397
|
+
if (target === "xd://devflow_requirement_graph") return "requirement_graph";
|
|
397
398
|
return undefined;
|
|
398
399
|
}
|
|
399
400
|
|
|
@@ -1781,8 +1782,9 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
1781
1782
|
if (!controlPlaneSucceeded(synced)) {
|
|
1782
1783
|
throw new Error(synced.stderr || synced.stdout || "artifact registry sync after rollover prepare failed");
|
|
1783
1784
|
}
|
|
1784
|
-
|
|
1785
|
+
// The runtime can observe the request immediately; arm the switch handler first.
|
|
1785
1786
|
pendingRollover = { snapshot, preparedRevision: payload.revision, rolloverId };
|
|
1787
|
+
await enqueueControlledRolloverRequest(ctx.cwd, rolloverId, ctx.sessionManager.getSessionId());
|
|
1786
1788
|
}
|
|
1787
1789
|
|
|
1788
1790
|
function parallelBranches(snapshot: Record<string, unknown>): Array<{ workflow_step: string; track: string }> {
|
|
@@ -2850,7 +2852,7 @@ export default function devflowCore(pi: ExtensionAPI) {
|
|
|
2850
2852
|
propagation: z.enum(["one_hop", "full"]).optional(),
|
|
2851
2853
|
}).optional(),
|
|
2852
2854
|
}),
|
|
2853
|
-
approval: (args) => args.action === "propose" || args.action === "confirm" ? "write" : "read",
|
|
2855
|
+
approval: (args) => args.action === "propose" || args.action === "confirm" || (args.action === "context" && args.write === true) ? "write" : "read",
|
|
2854
2856
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
2855
2857
|
const graphWrite = params.action === "propose" || params.action === "confirm" || (params.action === "context" && params.write === true);
|
|
2856
2858
|
if (graphWrite) {
|
package/src/constants.ts
CHANGED
package/src/runtime.ts
CHANGED
|
@@ -209,7 +209,7 @@ export async function runInteractiveRuntime(project: ProjectContext, options: Ru
|
|
|
209
209
|
// authority remains STATE.rollover, which the extension verifies and claims
|
|
210
210
|
// during session_switch before it starts the next workflow turn.
|
|
211
211
|
const consumeControlledRollover = async (): Promise<void> => {
|
|
212
|
-
if (rolloverConsumptionInFlight) return;
|
|
212
|
+
if (rolloverConsumptionInFlight || interactiveSubmissionInFlight || runtime.session.isStreaming) return;
|
|
213
213
|
rolloverConsumptionInFlight = true;
|
|
214
214
|
try {
|
|
215
215
|
const requestPath = path.join(project.root, ".planning", "rollover-request.json");
|
|
@@ -238,6 +238,8 @@ export async function runInteractiveRuntime(project: ProjectContext, options: Ru
|
|
|
238
238
|
// already durable and STATE remains frozen until the target consumes it.
|
|
239
239
|
let switched = false;
|
|
240
240
|
for (let attempt = 0; attempt < 3 && !switched; attempt += 1) {
|
|
241
|
+
// newSession aborts a running turn; leave the durable request for the poller.
|
|
242
|
+
if (interactiveSubmissionInFlight || runtime.session.isStreaming) return;
|
|
241
243
|
switched = await runtime.session.newSession();
|
|
242
244
|
if (!switched && attempt < 2) await new Promise(resolve => setTimeout(resolve, 100));
|
|
243
245
|
}
|
|
@@ -259,8 +261,11 @@ export async function runInteractiveRuntime(project: ProjectContext, options: Ru
|
|
|
259
261
|
rolloverConsumptionInFlight = false;
|
|
260
262
|
mode.showWarning(`Devflow 会话轮换运行时异常,将自动重试:${String(error)}`);
|
|
261
263
|
scheduleControlledRolloverRetry();
|
|
264
|
+
} finally {
|
|
265
|
+
rolloverConsumptionInFlight = false;
|
|
262
266
|
}
|
|
263
267
|
};
|
|
268
|
+
let interactiveSubmissionInFlight = false;
|
|
264
269
|
let rolloverConsumptionInFlight = false;
|
|
265
270
|
let rolloverRetryTimer: ReturnType<typeof setTimeout> | undefined;
|
|
266
271
|
let rolloverRetryAttempt = 0;
|
|
@@ -287,7 +292,12 @@ export async function runInteractiveRuntime(project: ProjectContext, options: Ru
|
|
|
287
292
|
await consumeControlledRollover();
|
|
288
293
|
while (true) {
|
|
289
294
|
const input = await mode.getUserInput();
|
|
290
|
-
|
|
295
|
+
interactiveSubmissionInFlight = true;
|
|
296
|
+
try {
|
|
297
|
+
await omp.submitInteractiveInput(mode, runtime.session, input);
|
|
298
|
+
} finally {
|
|
299
|
+
interactiveSubmissionInFlight = false;
|
|
300
|
+
}
|
|
291
301
|
await consumeControlledRollover();
|
|
292
302
|
// The submitted turn may create a durable rollover request after the
|
|
293
303
|
// immediate check above returns. Poll once while the UI is waiting for the
|