@awak-app/simy-cli 0.7.16 → 0.7.17
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/README.md +180 -26
- package/package.json +3 -2
- package/src/agent.js +128 -7
- package/src/bounded-local-task-subtask-pool.js +32 -6
- package/src/bounded-local-task-subtasks-contract.js +1 -1
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/.codex-plugin/plugin.json +2 -2
- package/src/codex-plugins/simy/hooks/README.md +8 -3
- package/src/codex-plugins/simy/hooks/delivery-loop.mjs +261 -67
- package/src/codex-plugins/simy/hooks/hooks.json +1 -1
- package/src/codex-plugins/simy/hooks/loop-kernel/conformance.json +136 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/index.mjs +42 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/outcome-review.mjs +31 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/pin.json +6 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/policy.json +141 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/task-pool.mjs +34 -0
- package/src/codex-plugins/simy/hooks/loop-kernel/work-frontier.mjs +132 -0
- package/src/codex-plugins/simy/hooks/loop-kernel.mjs +6 -0
- package/src/codex-plugins/simy/hooks/outcome-progress.mjs +15 -3
- package/src/codex-plugins/simy/hooks/purpose-completion-contract.mjs +10 -0
- package/src/codex-plugins/simy/hooks/purpose-evidence.mjs +8 -6
- package/src/codex-plugins/simy/hooks/result-cycle.mjs +32 -6
- package/src/codex-plugins/simy/hooks/work-frontier.mjs +2 -0
- package/src/codex-plugins/simy/skills/diagnose/SKILL.md +10 -4
- package/src/coding-run-recovery.js +4 -2
- package/src/delivery-hooks/claude-workflow.md +10 -7
- package/src/delivery-hooks/command.js +45 -10
- package/src/delivery-hooks/consult.js +60 -0
- package/src/delivery-hooks/diagnosis.js +2 -2
- package/src/delivery-hooks/legacy-hook-routing.js +46 -8
- package/src/delivery-hooks/local-runtime.js +50 -1
- package/src/delivery-hooks/local-supervisor.js +1 -1
- package/src/delivery-hooks/repair-continuation.js +80 -0
- package/src/delivery-hooks/repair.js +164 -0
- package/src/delivery-hooks/supervisor-service.js +3 -1
- package/src/delivery-hooks/supervisor.js +88 -12
- package/src/desktop-access.js +2 -1
- package/src/desktop-host.js +35 -2
- package/src/durable-local-task-worker.js +372 -58
- package/src/execution-capability-contract.js +15 -1
- package/src/index.js +3 -3
- package/src/local-photos-read.swift +33 -0
- package/src/local-photos.js +47 -0
- package/src/local-task-attachment-store.js +31 -0
- package/src/local-task-destination.js +174 -0
- package/src/local-task.js +119 -7
- package/src/native-delegation-contract.js +68 -0
- package/src/native-provider-identity.js +60 -0
- package/src/orchestrator/budget.js +22 -11
- package/src/orchestrator/independent-audit.js +9 -18
- package/src/orchestrator/loop.js +27 -59
- package/src/orchestrator/recovery.js +32 -2
- package/src/provider-delegation.js +336 -0
- package/src/runner.js +2 -1
- package/src/session-supervision/artifact-observer.js +138 -0
- package/src/session-supervision/codex-app-server.js +19 -5
- package/src/session-supervision/completion-artifacts.js +44 -0
- package/src/session-supervision/consistency-auditor.js +8 -11
- package/src/session-supervision/continuation-analysis.js +46 -28
- package/src/session-supervision/final-response-recovery.js +5 -3
- package/src/session-supervision/index.js +22 -5
- package/src/session-supervision/purpose-recovery.js +12 -3
- package/src/session-supervision/purpose-verification.js +9 -57
- package/src/session-supervision/recovery-frontier.js +55 -0
- package/src/session-supervision/stop-notifications.js +8 -8
- package/src/sqm/agent-skill.js +1 -1
- package/src/sqm/checkers.js +12 -6
- package/src/sqm/claude-plugin-update.js +22 -8
- package/src/sqm/claude-plugin.js +4 -0
- package/src/sqm/local-tests.js +2 -2
- package/src/sqm/plugin-cache.js +67 -0
- package/src/sqm/proof.js +25 -0
- package/src/sqm/report.js +1 -0
- package/src/sqm/workflow-onboarding.js +3 -39
- package/src/sqm/workflow-update.js +17 -6
- package/src/team-status-fence-store.js +32 -0
- package/src/team-threads.js +457 -0
|
@@ -58,6 +58,7 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
58
58
|
prepareWorkspace = prepareLocalTaskWorkspace,
|
|
59
59
|
leaseSeconds = DEFAULT_LEASE_SECONDS,
|
|
60
60
|
heartbeatIntervalMs = DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
61
|
+
now = Date.now,
|
|
61
62
|
setIntervalImpl = setInterval,
|
|
62
63
|
clearIntervalImpl = clearInterval,
|
|
63
64
|
onError = () => {},
|
|
@@ -111,10 +112,12 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
111
112
|
let completionConfirmed = false;
|
|
112
113
|
let completionState = null;
|
|
113
114
|
let providerStarted = false;
|
|
115
|
+
let knownLeaseExpiry = Number.NaN;
|
|
114
116
|
const startedAt = Date.now();
|
|
115
117
|
try {
|
|
116
118
|
normalized = normalizeDurableLocalTaskSubtaskClaim(claim, {
|
|
117
119
|
parentAuthority: parent,
|
|
120
|
+
nowMs: now(),
|
|
118
121
|
leaseSeconds,
|
|
119
122
|
});
|
|
120
123
|
if (normalized.disposition !== "execute") {
|
|
@@ -129,6 +132,12 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
129
132
|
}
|
|
130
133
|
batchId ??= normalized.batch.batch_id;
|
|
131
134
|
|
|
135
|
+
knownLeaseExpiry = normalized.attempt.leaseExpiresAtMs;
|
|
136
|
+
const checkLease = async () => {
|
|
137
|
+
if (!controller.signal.aborted && !completionConfirmed && now() >= knownLeaseExpiry) await cancel("lease_lost");
|
|
138
|
+
return !controller.signal.aborted;
|
|
139
|
+
};
|
|
140
|
+
|
|
132
141
|
const execution = boundedLocalTaskSubtaskExecution(normalized, parent);
|
|
133
142
|
const runtime = await materializeSubtaskRuntime({
|
|
134
143
|
normalized,
|
|
@@ -140,7 +149,7 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
140
149
|
downloadSource: sourceDownloader,
|
|
141
150
|
signal: controller.signal,
|
|
142
151
|
});
|
|
143
|
-
if (
|
|
152
|
+
if (!await checkLease()) return;
|
|
144
153
|
|
|
145
154
|
const fence = durableLocalTaskSubtaskFence(normalized, parent);
|
|
146
155
|
let boundaryConfirmed = false;
|
|
@@ -161,7 +170,7 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
161
170
|
}).catch(onError);
|
|
162
171
|
return;
|
|
163
172
|
}
|
|
164
|
-
if (boundaryConfirmed !== true ||
|
|
173
|
+
if (boundaryConfirmed !== true || !await checkLease()) {
|
|
165
174
|
await api.abandon_local_task_subtask_attempt_v2({
|
|
166
175
|
...fence,
|
|
167
176
|
p_reason_code: controller.signal.aborted
|
|
@@ -174,6 +183,8 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
174
183
|
|
|
175
184
|
const heartbeat = async () => {
|
|
176
185
|
if (controller.signal.aborted || completionConfirmed) return;
|
|
186
|
+
const renewalStartedAt = now();
|
|
187
|
+
if (!await checkLease()) return;
|
|
177
188
|
try {
|
|
178
189
|
const response =
|
|
179
190
|
await api.heartbeat_local_task_subtask_attempt_v2({
|
|
@@ -190,6 +201,7 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
190
201
|
) {
|
|
191
202
|
return;
|
|
192
203
|
}
|
|
204
|
+
if (!await checkLease()) return;
|
|
193
205
|
if (
|
|
194
206
|
response?.ok !== true ||
|
|
195
207
|
response.cancel_requested === true ||
|
|
@@ -198,6 +210,8 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
198
210
|
normalized.parent.cancel_generation)
|
|
199
211
|
) {
|
|
200
212
|
await cancel("server_cancelled");
|
|
213
|
+
} else {
|
|
214
|
+
knownLeaseExpiry = renewalStartedAt + leaseSeconds * 1_000;
|
|
201
215
|
}
|
|
202
216
|
} catch (error) {
|
|
203
217
|
if (completionConfirmed && isKnownSubtaskFenceError(error)) return;
|
|
@@ -214,9 +228,11 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
214
228
|
}
|
|
215
229
|
};
|
|
216
230
|
heartbeatTimer = setIntervalImpl(() => {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
heartbeatInFlight =
|
|
231
|
+
void checkLease().then((valid) => {
|
|
232
|
+
if (!valid || heartbeatInFlight || completionConfirmed) return;
|
|
233
|
+
heartbeatInFlight = heartbeat().finally(() => {
|
|
234
|
+
heartbeatInFlight = null;
|
|
235
|
+
});
|
|
220
236
|
});
|
|
221
237
|
}, heartbeatIntervalMs);
|
|
222
238
|
|
|
@@ -245,6 +261,13 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
245
261
|
),
|
|
246
262
|
);
|
|
247
263
|
}
|
|
264
|
+
// Lease loss after the paid boundary cannot establish a cancelled result.
|
|
265
|
+
// Preserve a known result, but leave interrupted work for server resolution.
|
|
266
|
+
if (providerStarted && controller.signal.reason === "lease_lost" &&
|
|
267
|
+
rawResult?.status === "cancelled") {
|
|
268
|
+
rawResult = { ...rawResult, status: "unknown",
|
|
269
|
+
failure_code: "local_task_subtask_provider_result_unknown" };
|
|
270
|
+
}
|
|
248
271
|
const result = normalizeDurableLocalTaskSubtaskResult(
|
|
249
272
|
normalizeRunResult(rawResult, startedAt),
|
|
250
273
|
{ normalizedClaim: normalized },
|
|
@@ -305,12 +328,15 @@ export function createBoundedLocalTaskSubtaskPool({
|
|
|
305
328
|
}
|
|
306
329
|
} finally {
|
|
307
330
|
if (heartbeatTimer) clearIntervalImpl(heartbeatTimer);
|
|
308
|
-
|
|
331
|
+
// Pending renewal has its own fenced completion handler; it must not
|
|
332
|
+
// hold a finished/cancelled slot open after its timer is cleared.
|
|
309
333
|
}
|
|
310
334
|
};
|
|
311
335
|
|
|
312
336
|
const scheduler = async () => {
|
|
313
337
|
if (!initialized) {
|
|
338
|
+
// Initialization only acknowledges the canonical plan. Backend keeps
|
|
339
|
+
// existing attempts/reservations intact; claim reconciles old generations.
|
|
314
340
|
const initializedBatch =
|
|
315
341
|
await api.initialize_local_task_subtask_batch_v2({
|
|
316
342
|
p_turn_id: parent.turnId,
|
|
@@ -1043,7 +1043,7 @@ function uploadedAttachmentRefs(value, name) {
|
|
|
1043
1043
|
return refs;
|
|
1044
1044
|
}
|
|
1045
1045
|
|
|
1046
|
-
function normalizeParentUploadedRef(item, name) {
|
|
1046
|
+
export function normalizeParentUploadedRef(item, name = "uploaded source") {
|
|
1047
1047
|
record(item, name);
|
|
1048
1048
|
const allowed = new Set([
|
|
1049
1049
|
"schema_version",
|
package/src/cli-contract.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./durable-local-task-steps-contract.js";
|
|
14
14
|
import { buildExecutionCapabilityContract } from "./execution-capability-contract.js";
|
|
15
15
|
|
|
16
|
-
export const CLI_VERSION = "0.7.
|
|
16
|
+
export const CLI_VERSION = "0.7.17";
|
|
17
17
|
export const CLI_API_CONTRACT_VERSION = 10;
|
|
18
18
|
|
|
19
19
|
export function narrativeImageCapabilityMetadata() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simy",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"description": "SIMY quality and PR review
|
|
4
|
+
"description": "SIMY quality and PR review, with automatic checkpoint tracking through enabled provider hooks.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Specialist Doctors Inc.",
|
|
7
7
|
"url": "https://github.com/SpecialistDoctors-Inc"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"interface": {
|
|
18
18
|
"displayName": "SIMY",
|
|
19
19
|
"shortDescription": "Quality and PR review.",
|
|
20
|
-
"longDescription": "Run explicitly requested quality checks and PR reviews.
|
|
20
|
+
"longDescription": "Run explicitly requested quality checks and PR reviews. Enabled hooks automatically track eligible conversations from user prompts through checkpoints. Stops, permission waits and opt-outs are preserved. The local Delivery skill remains retired; independently managed work uses the CLI Agentic Loop.",
|
|
21
21
|
"developerName": "Specialist Doctors Inc.",
|
|
22
22
|
"category": "Developer Tools",
|
|
23
23
|
"capabilities": [
|
|
@@ -18,9 +18,14 @@ scans ports or reads stored session tokens.
|
|
|
18
18
|
|
|
19
19
|
## Delivery Loop hooks
|
|
20
20
|
|
|
21
|
-
`delivery-loop.mjs` is
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
`delivery-loop.mjs` is shared by the Codex and Claude distributions. The CLI
|
|
22
|
+
prepares missing plugin sources automatically and maintains enabled plugin caches.
|
|
23
|
+
SessionStart supplies identity without starting work. A nonempty UserPromptSubmit
|
|
24
|
+
starts standard Delivery Loop by default for eligible connected conversations,
|
|
25
|
+
including when SessionStart was missed. No per-project enable command is needed.
|
|
26
|
+
`simy delivery auto off --provider codex|claude` saves a project override; updates
|
|
27
|
+
preserve it. Existing loops, explicit stops, session opt-outs and revoked provider
|
|
28
|
+
consent remain authoritative. No hook grants provider trust. Stop checks that
|
|
24
29
|
session's checkpoint and returns bounded next-step instructions. Approval/input
|
|
25
30
|
blocks, interruption, completion, failures and missing progress stop automatic continuation.
|
|
26
31
|
Provider errors/exits are surfaced to SIMY's desktop; a dead provider is not
|