@astrosheep/keiyaku 2.9.5 → 2.9.7
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/build/.tsbuildinfo +1 -1
- package/build/agents/harness/outcome.js +20 -4
- package/build/agents/harness/projection.js +8 -7
- package/build/agents/harness/router.js +2 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +13 -1
- package/build/agents/providers/claude-agent-sdk/registration.js +2 -1
- package/build/agents/providers/codex-app-server/adapter.js +11 -10
- package/build/agents/providers/codex-app-server/registration.js +2 -1
- package/build/agents/providers/opencode-sdk/adapter.js +7 -0
- package/build/agents/providers/opencode-sdk/registration.js +2 -1
- package/build/agents/providers/pi/adapter.js +10 -0
- package/build/agents/providers/pi/registration.js +3 -1
- package/build/cli/commands/contract/bind/handler.js +10 -4
- package/build/cli/commands/contract/bind/meta.js +6 -6
- package/build/cli/commands/contract/petition/handler.js +16 -3
- package/build/cli/commands/contract/petition/meta.js +4 -4
- package/build/cli/commands/metadata.js +3 -2
- package/build/cli/commands/projection/tell/handler.js +10 -2
- package/build/cli/commands/projection/tell/meta.js +3 -3
- package/build/cli/commands/task/catalog.js +2 -0
- package/build/cli/commands/task/log/handler.js +12 -0
- package/build/cli/commands/task/log/meta.js +8 -0
- package/build/cli/completion.js +9 -2
- package/build/cli/flags.js +11 -2
- package/build/cli/index.js +10 -6
- package/build/cli/parse-flags.js +6 -0
- package/build/cli/parse-metadata.js +1 -1
- package/build/cli/render/errors.js +18 -1
- package/build/cli/render/format.js +5 -2
- package/build/cli/render/line-width.js +33 -0
- package/build/cli/render/path-prefix-compaction.js +88 -0
- package/build/cli/render/petition.js +4 -0
- package/build/cli/render/projection-activity.js +93 -20
- package/build/cli/render/shared.js +34 -12
- package/build/cli/render/success-response.js +2 -0
- package/build/cli/render/tool-presentation.js +3 -3
- package/build/cli/render/wait.js +68 -48
- package/build/cli/subagent-guard.js +3 -0
- package/build/cli/types.js +1 -1
- package/build/core/audit/candidate.js +48 -0
- package/build/core/audit/coordinates.js +180 -0
- package/build/core/audit/evidence.js +158 -0
- package/build/core/audit/facade.js +42 -0
- package/build/core/audit/readiness.js +4 -0
- package/build/core/audit/report.js +38 -0
- package/build/core/audit.js +1 -650
- package/build/core/bind.js +111 -6
- package/build/core/draft.js +1 -1
- package/build/core/projection/generation/database.js +21 -2
- package/build/core/projection/generation/model.js +24 -3
- package/build/core/projection/generation/projection-generation-continuation.js +75 -10
- package/build/core/projection/generation/projection-generation-execution.js +4 -3
- package/build/core/projection/generation/projection-generation-runner.js +96 -53
- package/build/core/projection/generation/projection-generation-runtime.js +19 -0
- package/build/core/projection/generation/store.js +9 -0
- package/build/core/projection/generation/transitions.js +105 -3
- package/build/core/projection/index.js +2 -2
- package/build/core/projection/projection-core.js +1 -1
- package/build/core/projection/projection-kill.js +31 -0
- package/build/core/projection/projection-life-protocol.js +10 -0
- package/build/core/projection/projection-wait.js +53 -15
- package/build/core/projection/projection-wake.js +35 -3
- package/build/core/projection/tell/database.js +18 -0
- package/build/core/projection/tell/model.js +1 -0
- package/build/core/projection/tell/store.js +102 -55
- package/build/core/registry.js +82 -69
- package/build/core/scope.js +9 -9
- package/build/core/task/index.js +2 -2
- package/build/core/task/query.js +65 -23
- package/build/core/task/task-contract.js +18 -0
- package/build/core/task/task-git-store.js +50 -0
- package/build/generated/version.js +2 -2
- package/package.json +1 -1
- package/skills/keiyaku-akuma/SKILL.md +10 -0
- package/skills/keiyaku-workflow/SKILL.md +82 -7
|
@@ -3,13 +3,17 @@ import { SUBAGENT_SESSION_VERSION, } from "../session.js";
|
|
|
3
3
|
import { OUTCOME_ERROR_VERSION, SubagentFailure, } from "../types.js";
|
|
4
4
|
import { isProviderTerminalError, } from "./provider-adapter.js";
|
|
5
5
|
import { renderCapturedText } from "./runtime.js";
|
|
6
|
-
export function createOutcomeState(maxCaptureChars) {
|
|
6
|
+
export function createOutcomeState(maxCaptureChars, admittedSession) {
|
|
7
7
|
return {
|
|
8
8
|
outputBuffer: new StringTailBuffer(maxCaptureChars),
|
|
9
9
|
diagnosticsBuffer: new StringTailBuffer(maxCaptureChars),
|
|
10
10
|
warnings: [],
|
|
11
|
+
...(admittedSession ? { session: admittedSession } : {}),
|
|
11
12
|
};
|
|
12
13
|
}
|
|
14
|
+
export function recordSessionAdmission(state, session) {
|
|
15
|
+
state.session = session;
|
|
16
|
+
}
|
|
13
17
|
function mintOutcome(draft) {
|
|
14
18
|
return draft;
|
|
15
19
|
}
|
|
@@ -29,7 +33,6 @@ export function processEvent(state, event) {
|
|
|
29
33
|
return;
|
|
30
34
|
case "done":
|
|
31
35
|
state.doneEvent = event;
|
|
32
|
-
state.session = event.session;
|
|
33
36
|
if (event.finalMessage !== undefined) {
|
|
34
37
|
state.finalMessageCandidate = event.finalMessage;
|
|
35
38
|
}
|
|
@@ -83,6 +86,16 @@ export function classifyFailure(shared, state, error, idleTimedOut, transportFai
|
|
|
83
86
|
warnings: [...state.warnings],
|
|
84
87
|
});
|
|
85
88
|
}
|
|
89
|
+
if (shared.explicitlyAborted && isProviderTerminalError(error) && error.fact.kind === "aborted") {
|
|
90
|
+
return mintOutcome({
|
|
91
|
+
status: "interrupted",
|
|
92
|
+
finalMessage: state.finalMessageCandidate ?? "",
|
|
93
|
+
output: renderCapturedText(state.outputBuffer),
|
|
94
|
+
diagnostics: renderCapturedText(state.diagnosticsBuffer),
|
|
95
|
+
session: state.session ?? fallbackSession(shared),
|
|
96
|
+
warnings: [...state.warnings],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
86
99
|
if (transportFailure) {
|
|
87
100
|
const message = transportFailure instanceof Error ? transportFailure.message : `${shared.terms.provider} session transport probe failed`;
|
|
88
101
|
const timeoutMs = isProviderTerminalError(transportFailure) && transportFailure.fact.kind === "failed"
|
|
@@ -173,13 +186,16 @@ export function failWithError(shared, state, error, finalMessage, diagnostics =
|
|
|
173
186
|
warnings: [...state.warnings],
|
|
174
187
|
});
|
|
175
188
|
}
|
|
176
|
-
export function completeOutcome(
|
|
189
|
+
export function completeOutcome(state, finalMessage) {
|
|
190
|
+
if (!state.session) {
|
|
191
|
+
throw new Error("Cannot complete an outcome before session admission");
|
|
192
|
+
}
|
|
177
193
|
return mintOutcome({
|
|
178
194
|
status: "completed",
|
|
179
195
|
finalMessage,
|
|
180
196
|
output: renderCapturedText(state.outputBuffer),
|
|
181
197
|
diagnostics: renderCapturedText(state.diagnosticsBuffer),
|
|
182
|
-
session,
|
|
198
|
+
session: state.session,
|
|
183
199
|
warnings: [...state.warnings],
|
|
184
200
|
});
|
|
185
201
|
}
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { FlowError } from "../../flow-error.js";
|
|
3
3
|
import { createEventChannel } from "./event-channel.js";
|
|
4
4
|
import { overflowMarkerFromDropped, prepareAgentEventForPersistence, } from "./execution-handle.js";
|
|
5
|
-
import { classifyFailure, classifySettlementFailure, completeOutcome, createOutcomeState, failFromFailEvent, failWithError, processEvent, renderOutcomeCapturedText, } from "./outcome.js";
|
|
5
|
+
import { classifyFailure, classifySettlementFailure, completeOutcome, createOutcomeState, failFromFailEvent, failWithError, processEvent, recordSessionAdmission, renderOutcomeCapturedText, } from "./outcome.js";
|
|
6
6
|
import { startLiveProjection } from "./router.js";
|
|
7
7
|
import { createAbortError } from "./runtime.js";
|
|
8
8
|
const POLICY_BUDGET_CLEANUP_GRACE_MS = 5_000;
|
|
@@ -198,7 +198,7 @@ function deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, know
|
|
|
198
198
|
processEvent(state, event);
|
|
199
199
|
}
|
|
200
200
|
async function settleProjection(shared) {
|
|
201
|
-
const state = createOutcomeState(shared.terms.maxCaptureChars);
|
|
201
|
+
const state = createOutcomeState(shared.terms.maxCaptureChars, shared.reviveTerms?.session);
|
|
202
202
|
let idleTimedOut = false;
|
|
203
203
|
let transportFailure;
|
|
204
204
|
let policyBudgetExceeded = false;
|
|
@@ -245,7 +245,6 @@ async function settleProjection(shared) {
|
|
|
245
245
|
resolvePolicyBudget();
|
|
246
246
|
}, shared.terms.executionTimeoutMs);
|
|
247
247
|
executionTimeout.unref?.();
|
|
248
|
-
refreshIdleTimeout();
|
|
249
248
|
const requestLiveAbort = () => {
|
|
250
249
|
if (shared.explicitlyAborted)
|
|
251
250
|
return;
|
|
@@ -257,7 +256,10 @@ async function settleProjection(shared) {
|
|
|
257
256
|
shared.lifecycleAbort.signal.addEventListener("abort", requestLiveAbort, { once: true });
|
|
258
257
|
const providerSettlement = (async () => {
|
|
259
258
|
try {
|
|
260
|
-
const live = await startLiveProjection(shared.terms, shared.lifecycleAbort.signal, shared.reviveTerms, refreshIdleTimeout, shared.observer)
|
|
259
|
+
const live = await startLiveProjection(shared.terms, shared.lifecycleAbort.signal, shared.reviveTerms, refreshIdleTimeout, shared.observer, (admission) => {
|
|
260
|
+
recordSessionAdmission(state, admission.session);
|
|
261
|
+
refreshIdleTimeout();
|
|
262
|
+
});
|
|
261
263
|
liveDriver = live;
|
|
262
264
|
shared.onLive(live);
|
|
263
265
|
resolveForceWaiters(shared, live);
|
|
@@ -324,8 +326,7 @@ async function settleProjection(shared) {
|
|
|
324
326
|
completionOutcome?.finalMessage ??
|
|
325
327
|
state.finalMessageCandidate ??
|
|
326
328
|
renderOutcomeCapturedText(state.outputBuffer).trim();
|
|
327
|
-
|
|
328
|
-
if (!session) {
|
|
329
|
+
if (!state.session) {
|
|
329
330
|
return failWithError(shared, state, {
|
|
330
331
|
code: "SUBAGENT_EXEC_ERROR",
|
|
331
332
|
message: `${shared.terms.provider} exec ended without a session handle`,
|
|
@@ -333,7 +334,7 @@ async function settleProjection(shared) {
|
|
|
333
334
|
exitCode: null,
|
|
334
335
|
}, finalMessage);
|
|
335
336
|
}
|
|
336
|
-
return completeOutcome(
|
|
337
|
+
return completeOutcome(state, finalMessage);
|
|
337
338
|
}
|
|
338
339
|
catch (error) {
|
|
339
340
|
if (error instanceof FlowError) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getProviderRegistration } from "../providers/registry.js";
|
|
2
|
-
export async function startLiveProjection(terms, signal, reviveTerms, onIngress, observer) {
|
|
2
|
+
export async function startLiveProjection(terms, signal, reviveTerms, onIngress, observer, onSessionAdmission) {
|
|
3
3
|
const onSyncCheckpoint = observer
|
|
4
4
|
? (control, checkpoint) => {
|
|
5
5
|
observer.onCheckpoint(control, checkpoint);
|
|
@@ -19,6 +19,7 @@ export async function startLiveProjection(terms, signal, reviveTerms, onIngress,
|
|
|
19
19
|
reviveTerms,
|
|
20
20
|
onSyncCheckpoint,
|
|
21
21
|
onDeliveryOpportunity,
|
|
22
|
+
onSessionAdmission,
|
|
22
23
|
onIngress,
|
|
23
24
|
observer,
|
|
24
25
|
});
|
|
@@ -198,6 +198,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
198
198
|
queryActive = true;
|
|
199
199
|
notifyActive();
|
|
200
200
|
let resumedSessionId = sessionId;
|
|
201
|
+
let admittedSessionId;
|
|
201
202
|
let finalMessage;
|
|
202
203
|
let latestAssistantMessageModel;
|
|
203
204
|
// Provider acceptance / pre-terminal retry evidence for no-turn classification.
|
|
@@ -207,7 +208,18 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
207
208
|
const seenToolUses = new Map();
|
|
208
209
|
for await (const event of query) {
|
|
209
210
|
builder.ingress(CLAUDE_AGENT_SDK_PROVIDER, event.type, event, claudeIngressDisposition(event.type), () => {
|
|
210
|
-
|
|
211
|
+
const providerSessionId = extractResumeToken(event);
|
|
212
|
+
resumedSessionId = providerSessionId ?? resumedSessionId;
|
|
213
|
+
if (providerSessionId && providerSessionId !== admittedSessionId) {
|
|
214
|
+
admittedSessionId = providerSessionId;
|
|
215
|
+
options.onSessionAdmission?.({
|
|
216
|
+
session: {
|
|
217
|
+
provider: CLAUDE_AGENT_SDK_PROVIDER,
|
|
218
|
+
version: SUBAGENT_SESSION_VERSION,
|
|
219
|
+
handle: { sessionId: providerSessionId },
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
211
223
|
if (isClaudeApiRetryEvent(event)) {
|
|
212
224
|
lastPreTerminalEvidenceWasRetry = true;
|
|
213
225
|
builder.emit({ type: "warning", warning: mapClaudeApiRetryWarning(event) });
|
|
@@ -179,7 +179,7 @@ export const claudeAgentSdkRegistration = {
|
|
|
179
179
|
return loader ? { ...terms, loader } : terms;
|
|
180
180
|
},
|
|
181
181
|
nativePolicyOwnership: () => null,
|
|
182
|
-
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onIngress }) => {
|
|
182
|
+
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onSessionAdmission, onIngress }) => {
|
|
183
183
|
if (terms.provider !== CLAUDE_AGENT_SDK_PROVIDER) {
|
|
184
184
|
throw new Error(`startLive expected ${CLAUDE_AGENT_SDK_PROVIDER}`);
|
|
185
185
|
}
|
|
@@ -197,6 +197,7 @@ export const claudeAgentSdkRegistration = {
|
|
|
197
197
|
systemPrompt: claudeTerms.systemPrompt,
|
|
198
198
|
onSyncCheckpoint,
|
|
199
199
|
onEvidence: claudeTerms.onEvidence,
|
|
200
|
+
onSessionAdmission,
|
|
200
201
|
onIngress,
|
|
201
202
|
initialTurn: claudeTerms.initialTurn,
|
|
202
203
|
loader: claudeTerms.loader,
|
|
@@ -304,6 +304,15 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
304
304
|
builder.emit({ type: "fail", message });
|
|
305
305
|
throw createProviderFailure(message);
|
|
306
306
|
}
|
|
307
|
+
const admittedSession = {
|
|
308
|
+
provider: "codex-app-server",
|
|
309
|
+
version: SUBAGENT_SESSION_VERSION,
|
|
310
|
+
handle: {
|
|
311
|
+
threadId: activeThreadId,
|
|
312
|
+
...(serverCodexHome ? { codexHome: serverCodexHome } : {}),
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
options.onSessionAdmission?.({ session: admittedSession });
|
|
307
316
|
if (options.onEvidence)
|
|
308
317
|
emitProviderEvidence(options.onEvidence, { type: "session", provider: CODEX_APP_SERVER_PROVIDER, threadId: activeThreadId }, builderDiagnostic);
|
|
309
318
|
// Policy A defaults, but omit when config.* already owns that surface (thread/start config wins).
|
|
@@ -351,17 +360,9 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
351
360
|
throw createProviderFailure(message);
|
|
352
361
|
}
|
|
353
362
|
// Successful turn/completed is consumption evidence; interrupt ack alone is not terminal proof.
|
|
354
|
-
const session = {
|
|
355
|
-
provider: "codex-app-server",
|
|
356
|
-
version: SUBAGENT_SESSION_VERSION,
|
|
357
|
-
handle: {
|
|
358
|
-
threadId: activeThreadId,
|
|
359
|
-
...(serverCodexHome ? { codexHome: serverCodexHome } : {}),
|
|
360
|
-
},
|
|
361
|
-
};
|
|
362
363
|
const finalMessage = turnState.lastAgentMessage;
|
|
363
|
-
builder.emit({ type: "done", finalMessage, session });
|
|
364
|
-
return { finalMessage, session };
|
|
364
|
+
builder.emit({ type: "done", finalMessage, session: admittedSession });
|
|
365
|
+
return { finalMessage, session: admittedSession };
|
|
365
366
|
}
|
|
366
367
|
finally {
|
|
367
368
|
activeTurnCompletion = undefined;
|
|
@@ -212,7 +212,7 @@ export const codexAppServerRegistration = {
|
|
|
212
212
|
webSearch: Object.freeze(webSearch),
|
|
213
213
|
});
|
|
214
214
|
},
|
|
215
|
-
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onDeliveryOpportunity, onIngress, }) => {
|
|
215
|
+
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onDeliveryOpportunity, onSessionAdmission, onIngress, }) => {
|
|
216
216
|
if (terms.provider !== CODEX_APP_SERVER_PROVIDER) {
|
|
217
217
|
throw new Error(`startLive expected ${CODEX_APP_SERVER_PROVIDER}`);
|
|
218
218
|
}
|
|
@@ -231,6 +231,7 @@ export const codexAppServerRegistration = {
|
|
|
231
231
|
onSyncCheckpoint,
|
|
232
232
|
onDeliveryOpportunity,
|
|
233
233
|
onEvidence: codexTerms.onEvidence,
|
|
234
|
+
onSessionAdmission,
|
|
234
235
|
onIngress,
|
|
235
236
|
initialTurn: codexTerms.initialTurn,
|
|
236
237
|
};
|
|
@@ -264,6 +264,13 @@ export async function startOpencode(prompt, cwd, options = {}) {
|
|
|
264
264
|
builder.emit({ type: "fail", message });
|
|
265
265
|
throw createProviderFailure(message);
|
|
266
266
|
}
|
|
267
|
+
options.onSessionAdmission?.({
|
|
268
|
+
session: {
|
|
269
|
+
provider: OPENCODE_SDK_PROVIDER,
|
|
270
|
+
version: SUBAGENT_SESSION_VERSION,
|
|
271
|
+
handle: { sessionId: activeSessionId },
|
|
272
|
+
},
|
|
273
|
+
});
|
|
267
274
|
idleMonitor = new OpencodeIdleMonitor(sdk.client.v2.session, activeSessionId, combined.signal);
|
|
268
275
|
eventController = createOpencodeEventController({
|
|
269
276
|
builder,
|
|
@@ -104,7 +104,7 @@ export const opencodeSdkRegistration = {
|
|
|
104
104
|
return loader ? { ...terms, loader } : terms;
|
|
105
105
|
},
|
|
106
106
|
nativePolicyOwnership: () => null,
|
|
107
|
-
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onDeliveryOpportunity, onIngress, }) => {
|
|
107
|
+
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onDeliveryOpportunity, onSessionAdmission, onIngress, }) => {
|
|
108
108
|
if (terms.provider !== OPENCODE_SDK_PROVIDER) {
|
|
109
109
|
throw new Error(`startLive expected ${OPENCODE_SDK_PROVIDER}`);
|
|
110
110
|
}
|
|
@@ -118,6 +118,7 @@ export const opencodeSdkRegistration = {
|
|
|
118
118
|
onSyncCheckpoint,
|
|
119
119
|
onDeliveryOpportunity,
|
|
120
120
|
onEvidence: opencodeTerms.onEvidence,
|
|
121
|
+
onSessionAdmission,
|
|
121
122
|
onIngress,
|
|
122
123
|
initialTurn: opencodeTerms.initialTurn,
|
|
123
124
|
loader: opencodeTerms.loader,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FlowError } from "../../../flow-error.js";
|
|
2
2
|
import { appendDebugLog } from "../../../telemetry/debug-log.js";
|
|
3
|
+
import { SUBAGENT_SESSION_VERSION, } from "../../session.js";
|
|
3
4
|
import { createProjectionDriver } from "../../harness/execution-handle.js";
|
|
4
5
|
import { createProviderFailure, toProviderTerminalError, } from "../../harness/provider-adapter.js";
|
|
5
6
|
import { createAbortError, emitProviderEvidence, sha256Utf8 } from "../../harness/runtime.js";
|
|
@@ -103,6 +104,15 @@ async function openPiProjectionDriver(prompt, cwd, options) {
|
|
|
103
104
|
...(resourceLoader ? { resourceLoader } : {}),
|
|
104
105
|
});
|
|
105
106
|
const session = created.session;
|
|
107
|
+
if (session.sessionFile) {
|
|
108
|
+
options.onSessionAdmission?.({
|
|
109
|
+
session: {
|
|
110
|
+
provider: PI_PROVIDER,
|
|
111
|
+
version: SUBAGENT_SESSION_VERSION,
|
|
112
|
+
handle: { sessionId: session.sessionId, sessionFile: session.sessionFile },
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
106
116
|
if (options.onEvidence)
|
|
107
117
|
emitProviderEvidence(options.onEvidence, { type: "session", provider: PI_PROVIDER, sessionId: session.sessionId, ...(session.sessionFile ? { sessionFile: session.sessionFile } : {}) }, reportEvidenceDiagnostic);
|
|
108
118
|
session.setSteeringMode("one-at-a-time");
|
|
@@ -109,7 +109,7 @@ export const piRegistration = {
|
|
|
109
109
|
return loader ? { ...terms, loader } : terms;
|
|
110
110
|
},
|
|
111
111
|
nativePolicyOwnership: () => null,
|
|
112
|
-
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onIngress }) => {
|
|
112
|
+
startLive: async ({ terms, signal, reviveTerms, onSyncCheckpoint, onSessionAdmission, onIngress }) => {
|
|
113
113
|
if (terms.provider !== PI_PROVIDER) {
|
|
114
114
|
throw new Error(`startLive expected ${PI_PROVIDER}`);
|
|
115
115
|
}
|
|
@@ -125,6 +125,7 @@ export const piRegistration = {
|
|
|
125
125
|
appendSystemPromptOverride: piTerms.appendSystemPromptOverride,
|
|
126
126
|
onSyncCheckpoint,
|
|
127
127
|
onEvidence: piTerms.onEvidence,
|
|
128
|
+
onSessionAdmission,
|
|
128
129
|
onIngress,
|
|
129
130
|
initialTurn: piTerms.initialTurn,
|
|
130
131
|
loader: piTerms.loader,
|
|
@@ -137,6 +138,7 @@ export const piRegistration = {
|
|
|
137
138
|
appendSystemPromptOverride: piTerms.appendSystemPromptOverride,
|
|
138
139
|
onSyncCheckpoint,
|
|
139
140
|
onEvidence: piTerms.onEvidence,
|
|
141
|
+
onSessionAdmission,
|
|
140
142
|
onIngress,
|
|
141
143
|
initialTurn: piTerms.initialTurn,
|
|
142
144
|
loader: piTerms.loader,
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { bindContract } from "../../../../core/bind.js";
|
|
1
|
+
import { bindContract, previewBindContract } from "../../../../core/bind.js";
|
|
2
2
|
import { defaultActorClock } from "../../../../core/outcome-base.js";
|
|
3
3
|
import { writeDraftArtifact } from "../../../draft-artifact.js";
|
|
4
|
-
import { buildBindDraftResponse,
|
|
4
|
+
import { buildBindDraftResponse, buildBindPreviewResponse, buildBindResponse } from "../../../render/shared.js";
|
|
5
5
|
import { repositoryDirectory } from "../../shared.js";
|
|
6
6
|
export const handler = async (stdin, flags, signal) => {
|
|
7
|
+
const cwd = await repositoryDirectory(flags, "bind");
|
|
7
8
|
if (flags.dryRun) {
|
|
8
|
-
|
|
9
|
+
const preview = await previewBindContract({
|
|
10
|
+
cwd, draft: stdin, ...defaultActorClock(), workspace: "worktree",
|
|
11
|
+
after: flags.after ?? [], exclusive: flags.exclusive,
|
|
12
|
+
...(flags.bindTaskIds === undefined ? {} : { taskIds: flags.bindTaskIds }),
|
|
13
|
+
signal,
|
|
14
|
+
});
|
|
15
|
+
return buildBindPreviewResponse(preview);
|
|
9
16
|
}
|
|
10
|
-
const cwd = await repositoryDirectory(flags, "bind");
|
|
11
17
|
if (flags.draftOnly) {
|
|
12
18
|
return buildBindDraftResponse(await writeDraftArtifact({ cwd, title: "bind-draft", content: stdin }));
|
|
13
19
|
}
|
|
@@ -17,10 +17,10 @@ export const meta = {
|
|
|
17
17
|
"<what the commission should accomplish>",
|
|
18
18
|
"",
|
|
19
19
|
"## Scope",
|
|
20
|
-
"
|
|
20
|
+
"~~~",
|
|
21
21
|
"<pattern>",
|
|
22
22
|
"<another-pattern>",
|
|
23
|
-
"
|
|
23
|
+
"~~~",
|
|
24
24
|
"",
|
|
25
25
|
"## Checks",
|
|
26
26
|
"- <verification>",
|
|
@@ -40,10 +40,10 @@ export const meta = {
|
|
|
40
40
|
"<what the commission should accomplish>",
|
|
41
41
|
"",
|
|
42
42
|
"## Scope",
|
|
43
|
-
"
|
|
43
|
+
"~~~",
|
|
44
44
|
"<pattern>",
|
|
45
45
|
"<another-pattern>",
|
|
46
|
-
"
|
|
46
|
+
"~~~",
|
|
47
47
|
"",
|
|
48
48
|
"## Checks",
|
|
49
49
|
"- <verification>",
|
|
@@ -52,10 +52,10 @@ export const meta = {
|
|
|
52
52
|
[
|
|
53
53
|
"keiyaku bind --task fix-flaky-pump - <<'KEIYAKU'",
|
|
54
54
|
"## Scope",
|
|
55
|
-
"
|
|
55
|
+
"~~~",
|
|
56
56
|
"<pattern>",
|
|
57
57
|
"<another-pattern>",
|
|
58
|
-
"
|
|
58
|
+
"~~~",
|
|
59
59
|
"",
|
|
60
60
|
"## Checks",
|
|
61
61
|
"- <verification>",
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
import { FlowError } from "../../../../flow-error.js";
|
|
2
2
|
import { resolveExistingContractAddress, withResolvedAddress } from "../../../../core/addressing.js";
|
|
3
3
|
import { buildPetitionClaimInput, petitionKeiyaku, previewPetition, } from "../../../../core/settlement/index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { renewKeiyaku } from "../../../../core/renew.js";
|
|
5
|
+
import { buildPetitionClaimResponse, buildPetitionPreviewResponse, renderPetitionRenewedConsequence, } from "../../../render/petition.js";
|
|
6
|
+
import { writeCliOutput } from "../../../output-stream-error-policy.js";
|
|
5
7
|
import { effectiveDirectory, repositoryDirectory } from "../../shared.js";
|
|
6
8
|
export const handler = async (stdin, flags, signal) => {
|
|
7
9
|
if (flags.json && !flags.dryRun) {
|
|
8
10
|
throw new FlowError("EMPTY_PARAM", "petition --json requires --dry-run");
|
|
9
11
|
}
|
|
12
|
+
if (flags.renewBeforePetition && flags.dryRun) {
|
|
13
|
+
throw new FlowError("EMPTY_PARAM", "petition --renew cannot be used with --dry-run");
|
|
14
|
+
}
|
|
10
15
|
const cwd = await repositoryDirectory(flags, "petition");
|
|
11
16
|
const address = await resolveExistingContractAddress(cwd, flags.contractId, flags.contractAddressSource, effectiveDirectory(flags));
|
|
12
17
|
return await withResolvedAddress(address, async () => {
|
|
13
|
-
const input = buildPetitionClaimInput({ cwd, contractId: address.binding.commissionId, stdin, signal, appendScope: flags.appendScope });
|
|
14
18
|
if (flags.dryRun) {
|
|
19
|
+
const input = buildPetitionClaimInput({ cwd, contractId: address.binding.commissionId, stdin, signal });
|
|
15
20
|
return buildPetitionPreviewResponse(await previewPetition({
|
|
16
21
|
cwd,
|
|
17
22
|
contractId: address.binding.commissionId,
|
|
18
23
|
oath: input.oath,
|
|
19
24
|
}), flags.json === true);
|
|
20
25
|
}
|
|
21
|
-
|
|
26
|
+
const renewed = flags.renewBeforePetition
|
|
27
|
+
? await renewKeiyaku({ cwd, address, appendScope: flags.appendScope })
|
|
28
|
+
: undefined;
|
|
29
|
+
if (renewed && !renewed.alreadyFresh) {
|
|
30
|
+
await writeCliOutput(process.stdout, `${renderPetitionRenewedConsequence(renewed)}\n`);
|
|
31
|
+
}
|
|
32
|
+
const input = buildPetitionClaimInput({ cwd, contractId: address.binding.commissionId, stdin, signal, appendScope: flags.appendScope });
|
|
33
|
+
const petitionInput = renewed ? { ...input, appendScope: undefined } : input;
|
|
34
|
+
return buildPetitionClaimResponse({ ...await petitionKeiyaku(petitionInput), address }, input);
|
|
22
35
|
});
|
|
23
36
|
};
|
|
@@ -2,12 +2,12 @@ export const meta = {
|
|
|
2
2
|
command: "petition",
|
|
3
3
|
summary: "Run or preview the gated settlement pipeline",
|
|
4
4
|
usage: [
|
|
5
|
-
"keiyaku petition [-C|--cwd DIR] [--repo DIR] [--contract ADDR] [--append-scope PATTERN] [- < petition.md]",
|
|
6
|
-
"keiyaku @<id> petition [-C|--cwd DIR] [--repo DIR] [--append-scope PATTERN] [- < petition.md]",
|
|
5
|
+
"keiyaku petition [-C|--cwd DIR] [--repo DIR] [--contract ADDR] [--renew] [--append-scope PATTERN] [- < petition.md]",
|
|
6
|
+
"keiyaku @<id> petition [-C|--cwd DIR] [--repo DIR] [--renew] [--append-scope PATTERN] [- < petition.md]",
|
|
7
7
|
"keiyaku @<id> petition --dry-run [--json] [- < petition.md]",
|
|
8
8
|
],
|
|
9
9
|
stdin: { mode: "document", selector: { kind: "positional", index: 0, required: false, rejectBlank: false } },
|
|
10
|
-
flags: ["cwd", "repo", "contract", "append-scope", "dry-run", "json"],
|
|
10
|
+
flags: ["cwd", "repo", "contract", "renew", "append-scope", "dry-run", "json"],
|
|
11
11
|
purpose: "Seal the current a0 or open explicit arc, queue the contract, and run verdict and claim processing; dry-run previews deterministic gates without mutation.",
|
|
12
12
|
input: [
|
|
13
13
|
"## Oath",
|
|
@@ -16,7 +16,7 @@ export const meta = {
|
|
|
16
16
|
notes: [
|
|
17
17
|
"Petition stdin is optional and read only when literal - is supplied; a missing, empty, or blank oath is rejected by the settlement gate with OATH_MISSING.",
|
|
18
18
|
"The machine checks only that the oath is present. Accepted oath text is persisted in the petition entry and hidden from the reviewer.",
|
|
19
|
-
"
|
|
19
|
+
"Use --renew to run ordinary renew before petition; renew failures stop the command before settlement.",
|
|
20
20
|
"Dry-run never runs verification or review and exits 0, 1, or 2.",
|
|
21
21
|
],
|
|
22
22
|
completionRank: 10,
|
|
@@ -23,6 +23,7 @@ import { meta as taskMeta } from "./task/task/meta.js";
|
|
|
23
23
|
import { meta as taskAddMeta } from "./task/add/meta.js";
|
|
24
24
|
import { meta as taskShowMeta } from "./task/show/meta.js";
|
|
25
25
|
import { meta as taskLsMeta } from "./task/ls/meta.js";
|
|
26
|
+
import { meta as taskLogMeta } from "./task/log/meta.js";
|
|
26
27
|
import { meta as taskStartMeta } from "./task/start/meta.js";
|
|
27
28
|
import { meta as taskStopMeta } from "./task/stop/meta.js";
|
|
28
29
|
import { meta as taskDoneMeta } from "./task/done/meta.js";
|
|
@@ -34,14 +35,14 @@ export const COMMAND_METADATA_ORDER = [
|
|
|
34
35
|
"bind", "arc", "call", "revive", "wait", "tell", "kill", "log",
|
|
35
36
|
"akuma", "akuma ls", "akuma view", "skills", "skills install", "amend", "audit",
|
|
36
37
|
"renew", "petition", "forfeit", "guide", "completion", "status", "task",
|
|
37
|
-
"task add", "task show", "task ls", "task start", "task stop", "task done",
|
|
38
|
+
"task add", "task show", "task ls", "task log", "task start", "task stop", "task done",
|
|
38
39
|
"task drop", "task update", "task doctor", "dump-env",
|
|
39
40
|
];
|
|
40
41
|
const COMMAND_METADATA = [
|
|
41
42
|
bindMeta, arcMeta, callMeta, reviveMeta, waitMeta, tellMeta, killMeta, logMeta,
|
|
42
43
|
akumaMeta, akumaLsMeta, akumaViewMeta, skillsMeta, skillsInstallMeta, amendMeta, auditMeta,
|
|
43
44
|
renewMeta, petitionMeta, forfeitMeta, guideMeta, completionMeta, statusMeta,
|
|
44
|
-
taskMeta, taskAddMeta, taskShowMeta, taskLsMeta, taskStartMeta, taskStopMeta,
|
|
45
|
+
taskMeta, taskAddMeta, taskShowMeta, taskLsMeta, taskLogMeta, taskStartMeta, taskStopMeta,
|
|
45
46
|
taskDoneMeta, taskDropMeta, taskUpdateMeta, taskDoctorMeta, dumpEnvMeta,
|
|
46
47
|
];
|
|
47
48
|
export const CLI_COMMAND_METADATA = Object.fromEntries(COMMAND_METADATA.map((meta) => [meta.command, meta]));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FlowError } from "../../../../flow-error.js";
|
|
2
|
-
import { assertTellEffortSupported, tellProjection, writeInboxTell } from "../../../../core/projection/index.js";
|
|
2
|
+
import { assertTellEffortSupported, interruptProjectionGeneration, tellProjection, writeInboxTell } from "../../../../core/projection/index.js";
|
|
3
3
|
import { waitForProjection } from "../../../../core/projection/index.js";
|
|
4
4
|
import { prependAddressReceipt } from "../../../render/address.js";
|
|
5
5
|
import { buildSilentTellResponse } from "../../../render/tell.js";
|
|
@@ -13,7 +13,15 @@ export const handler = async (body, flags, signal, positional) => runProjectionC
|
|
|
13
13
|
assertTellEffortSupported(projection.directory, flags.effort);
|
|
14
14
|
// Address admission and any effort validation precede the durable mailbox write.
|
|
15
15
|
writeInboxTell(projection.directory, body, Date.now(), { effort: flags.effort });
|
|
16
|
-
|
|
16
|
+
if (flags.interrupt) {
|
|
17
|
+
const interrupted = interruptProjectionGeneration(projection.directory);
|
|
18
|
+
if (interrupted.status === "already-closed") {
|
|
19
|
+
await tellProjection(projection.directory, projection.id, flags.effort);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await tellProjection(projection.directory, projection.id, flags.effort);
|
|
24
|
+
}
|
|
17
25
|
if (flags.timeoutMs === undefined)
|
|
18
26
|
return buildSilentTellResponse();
|
|
19
27
|
return prependAddressReceipt(buildWaitResponse(projection.id, await waitForProjection({ projectionDirectory: projection.directory, timeoutMs: flags.timeoutMs, signal }), { alias: projection.alias }), ctx.address, { projectionId: projection.id, projectionAlias: projection.alias });
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const meta = {
|
|
2
2
|
command: "tell",
|
|
3
3
|
summary: "Send intent to a projection mailbox",
|
|
4
|
-
usage: ["keiyaku tell PROJECTION [--wait DURATION] [--] <BODY|->"],
|
|
4
|
+
usage: ["keiyaku tell PROJECTION [--interrupt] [--wait DURATION] [--] <BODY|->"],
|
|
5
5
|
stdin: {
|
|
6
6
|
mode: "argument",
|
|
7
7
|
selector: { kind: "positional", index: 1, required: true, rejectBlank: true },
|
|
8
8
|
},
|
|
9
|
-
flags: ["cwd", "repo", "contract", "effort", "wait"],
|
|
10
|
-
purpose: "Write intent to the mailbox
|
|
9
|
+
flags: ["cwd", "repo", "contract", "effort", "interrupt", "wait"],
|
|
10
|
+
purpose: "Write intent to the mailbox; --interrupt terminates the active turn before successor wake.",
|
|
11
11
|
completionRank: 3,
|
|
12
12
|
};
|
|
@@ -2,6 +2,7 @@ import { meta as taskMeta } from "./task/meta.js";
|
|
|
2
2
|
import { meta as addMeta } from "./add/meta.js";
|
|
3
3
|
import { meta as showMeta } from "./show/meta.js";
|
|
4
4
|
import { meta as lsMeta } from "./ls/meta.js";
|
|
5
|
+
import { meta as logMeta } from "./log/meta.js";
|
|
5
6
|
import { meta as startMeta } from "./start/meta.js";
|
|
6
7
|
import { meta as stopMeta } from "./stop/meta.js";
|
|
7
8
|
import { meta as doneMeta } from "./done/meta.js";
|
|
@@ -13,6 +14,7 @@ export const taskCatalog = [
|
|
|
13
14
|
{ meta: addMeta, load: () => import("./add/handler.js") },
|
|
14
15
|
{ meta: showMeta, load: () => import("./show/handler.js") },
|
|
15
16
|
{ meta: lsMeta, load: () => import("./ls/handler.js") },
|
|
17
|
+
{ meta: logMeta, load: () => import("./log/handler.js") },
|
|
16
18
|
{ meta: startMeta, load: () => import("./start/handler.js") },
|
|
17
19
|
{ meta: stopMeta, load: () => import("./stop/handler.js") },
|
|
18
20
|
{ meta: doneMeta, load: () => import("./done/handler.js") },
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FlowError } from "../../../../flow-error.js";
|
|
2
|
+
import { readTaskBoard, readTaskHistory, resolveTaskReadId, } from "../../../../core/task/index.js";
|
|
3
|
+
import { textResponse } from "../../../render/shared.js";
|
|
4
|
+
import { withTaskCommandRepository } from "../shared.js";
|
|
5
|
+
export const handler = async (_stdin, flags, _signal, positional) => withTaskCommandRepository(flags, async (repository, cwd) => {
|
|
6
|
+
const board = await readTaskBoard(repository);
|
|
7
|
+
const task = board.byId.get(resolveTaskReadId(board, positional[0]));
|
|
8
|
+
if (!task)
|
|
9
|
+
throw new FlowError("INTERNAL_STATE", "resolved task disappeared from the board");
|
|
10
|
+
const rows = await readTaskHistory(cwd, task.id);
|
|
11
|
+
return textResponse(rows.map(({ timestamp, actor, subject }) => `${timestamp}\t${actor}\t${subject}`).join("\n"));
|
|
12
|
+
});
|
package/build/cli/completion.js
CHANGED
|
@@ -2,6 +2,7 @@ import { assertSettingsKnobUsable } from "../config/settings/disease.js";
|
|
|
2
2
|
import { loadKeiyakuSettings } from "../config/settings/loader.js";
|
|
3
3
|
import { loadAkumaCatalog } from "../config/akuma-loader.js";
|
|
4
4
|
import { listContractIds } from "../core/ledger.js";
|
|
5
|
+
import { TASK_FILTER_COMPLETION } from "../core/task/query.js";
|
|
5
6
|
import { allCommandMetadata, getCommandMetadata } from "./commands/metadata.js";
|
|
6
7
|
function topLevelCommands() {
|
|
7
8
|
return allCommandMetadata()
|
|
@@ -46,6 +47,9 @@ export async function renderCompletionCandidates(input) {
|
|
|
46
47
|
if (input.previous === "task") {
|
|
47
48
|
return filterPrefix(subcommandsFor("task"), word).join("\n");
|
|
48
49
|
}
|
|
50
|
+
if (input.previous === "--filter") {
|
|
51
|
+
return filterPrefix([TASK_FILTER_COMPLETION], word).join("\n");
|
|
52
|
+
}
|
|
49
53
|
return filterPrefix(topLevelCommands(), word).join("\n");
|
|
50
54
|
}
|
|
51
55
|
export function renderCompletionScript(shell = "bash") {
|
|
@@ -54,7 +58,7 @@ export function renderCompletionScript(shell = "bash") {
|
|
|
54
58
|
"#compdef keiyaku",
|
|
55
59
|
"_keiyaku() {",
|
|
56
60
|
" local -a candidates",
|
|
57
|
-
" candidates=(${(f)\"$(keiyaku completion --complete --word
|
|
61
|
+
" candidates=(${(f)\"$(keiyaku completion --complete --word=\"${words[CURRENT]}\" --previous=\"${words[CURRENT-1]}\" 2>/dev/null)\"})",
|
|
58
62
|
" compadd -- $candidates",
|
|
59
63
|
"}",
|
|
60
64
|
"_keiyaku \"$@\"",
|
|
@@ -65,7 +69,10 @@ export function renderCompletionScript(shell = "bash") {
|
|
|
65
69
|
" local cur prev",
|
|
66
70
|
" cur=\"${COMP_WORDS[COMP_CWORD]}\"",
|
|
67
71
|
" prev=\"${COMP_WORDS[COMP_CWORD-1]}\"",
|
|
68
|
-
" COMPREPLY=(
|
|
72
|
+
" COMPREPLY=()",
|
|
73
|
+
" while IFS= read -r candidate; do",
|
|
74
|
+
" COMPREPLY+=(\"$candidate\")",
|
|
75
|
+
" done < <(keiyaku completion --complete --word=\"$cur\" --previous=\"$prev\" 2>/dev/null)",
|
|
69
76
|
"}",
|
|
70
77
|
"complete -F _keiyaku_completion keiyaku",
|
|
71
78
|
].join("\n");
|
package/build/cli/flags.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ACTOR_IDENTITY } from "../keiyaku.js";
|
|
2
|
+
import { TASK_FILTER_GRAMMAR } from "../core/task/query.js";
|
|
2
3
|
export const HELP_FLAGS = new Set(["--help", "-h"]);
|
|
3
4
|
export const FLAG_SPECS = {
|
|
4
5
|
cwd: {
|
|
@@ -67,6 +68,10 @@ export const FLAG_SPECS = {
|
|
|
67
68
|
kind: "boolean",
|
|
68
69
|
description: "Return after durable launch instead of waiting for completion.",
|
|
69
70
|
},
|
|
71
|
+
interrupt: {
|
|
72
|
+
kind: "boolean",
|
|
73
|
+
description: "Interrupt the current projection turn after saving the tell.",
|
|
74
|
+
},
|
|
70
75
|
"draft-only": {
|
|
71
76
|
kind: "boolean",
|
|
72
77
|
description: "Write a draft artifact without creating a contract workspace.",
|
|
@@ -123,6 +128,10 @@ export const FLAG_SPECS = {
|
|
|
123
128
|
placeholder: "PATTERN",
|
|
124
129
|
description: "Append one ordered scope pattern to the contract before audit. May be repeated.",
|
|
125
130
|
},
|
|
131
|
+
renew: {
|
|
132
|
+
kind: "boolean",
|
|
133
|
+
description: "Renew onto the current target before petitioning.",
|
|
134
|
+
},
|
|
126
135
|
resolve: {
|
|
127
136
|
kind: "boolean",
|
|
128
137
|
description: "Open a durable Keiyaku-owned renew recovery session when the rewrite conflicts.",
|
|
@@ -178,8 +187,8 @@ export const FLAG_SPECS = {
|
|
|
178
187
|
},
|
|
179
188
|
filter: {
|
|
180
189
|
kind: "value",
|
|
181
|
-
placeholder:
|
|
182
|
-
description: "Filter structured task facts. Repeat for AND; comma
|
|
190
|
+
placeholder: TASK_FILTER_GRAMMAR,
|
|
191
|
+
description: "Filter structured task facts. Repeat --filter for AND; comma values or | terms are OR.",
|
|
183
192
|
},
|
|
184
193
|
sort: {
|
|
185
194
|
kind: "value",
|