@awak-app/simy-cli 0.5.33 → 0.5.35
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 +41 -0
- package/package.json +4 -3
- package/src/agent.js +144 -2
- package/src/backend-executable.js +2 -1
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/.codex-plugin/plugin.json +4 -1
- package/src/codex-plugins/simy/assets/logo.png +0 -0
- package/src/codex-plugins/simy/hooks/delivery-loop.mjs +654 -35
- package/src/codex-plugins/simy/skills/delivery-loop/SKILL.md +20 -2
- package/src/codex-work-pattern-sync.js +940 -0
- package/src/delivery-hooks/command.js +28 -7
- package/src/delivery-hooks/desktop.js +38 -4
- package/src/delivery-hooks/supervisor.js +281 -0
- package/src/desktop-host.js +62 -7
- package/src/index.js +7 -0
- package/src/local-task.js +96 -3
- package/src/orchestrator/budget.js +26 -2
- package/src/runner.js +43 -8
- package/src/session-supervision/claude-sessions.js +131 -0
- package/src/session-supervision/codex-app-server.js +290 -0
- package/src/session-supervision/index.js +140 -0
- package/src/session-supervision/original-session-target.js +20 -0
- package/src/windows-update.js +28 -2
- package/src/workflow-deliverable-upload.js +454 -0
- package/src/workflow-observation-sender.js +348 -86
package/README.md
CHANGED
|
@@ -76,6 +76,13 @@ marketplace still points to SIMY’s generated local source. Plugin versions inc
|
|
|
76
76
|
receive a fresh cache. Use a new Codex task to pick up updated skills; running
|
|
77
77
|
tasks are not restarted. Missing or disabled plugins are not enabled automatically.
|
|
78
78
|
Failed refreshes retry on the next check without blocking daemon startup.
|
|
79
|
+
The desktop Sessions page discovers existing provider conversations and lets users
|
|
80
|
+
choose monitoring or supported session supervision with a goal, acceptance
|
|
81
|
+
criteria, an autonomy policy, and finite budgets. Codex enrollment uses an exact
|
|
82
|
+
app-server session and checks writer ownership before each continuation. Claude
|
|
83
|
+
can continue through a verified live SIMY hook in its original process; sessions
|
|
84
|
+
without that hook support monitoring only, and cold takeover remains unavailable. See [session supervision](docs/session-supervision.md).
|
|
85
|
+
|
|
79
86
|
The plugin also provides an opt-in, hook-based Delivery Loop in the user's existing
|
|
80
87
|
Codex or Claude Code conversation. Install the plugin, review and enable SIMY hooks
|
|
81
88
|
with `/hooks`, then request `/simy:delivery-loop` for the task. Installing or updating
|
|
@@ -104,6 +111,40 @@ with an absolute SIMY Web origin for another deployment. Non-loopback hosts
|
|
|
104
111
|
must use HTTPS. `SIMY_WEB_ORIGIN` and the legacy `SIMY_API_ORIGIN` remain
|
|
105
112
|
available for automation, but the command-line flag takes precedence.
|
|
106
113
|
|
|
114
|
+
Work Pattern discovery checks the connected account's server-side personal
|
|
115
|
+
setting before reading local Codex or Claude Code history. An explicit opt-out
|
|
116
|
+
prevents both local inspection and upload. The daemon reads bounded user and
|
|
117
|
+
assistant conversation chunks from active and archived Codex sessions and
|
|
118
|
+
Claude Code projects, excluding delegated agents, tool output, reasoning, and
|
|
119
|
+
injected runtime context. Dated messages outside the configured lookback are
|
|
120
|
+
excluded even when their conversation continues today. Legacy transcripts with
|
|
121
|
+
no message timestamps use the file timestamp as a fallback. The local cursor stores only opaque hashes and
|
|
122
|
+
timestamps scoped to the connection, account, and device. Uploads require the
|
|
123
|
+
`user_conversation.v2` Web, Crew, and Backend contract and exact per-chunk
|
|
124
|
+
receipts before the cursor advances. Deploy those companion changes before
|
|
125
|
+
enabling this CLI version; earlier receivers cannot acknowledge v2 history.
|
|
126
|
+
|
|
127
|
+
History sync runs only in daemon mode, at startup and then at most every 15
|
|
128
|
+
minutes, and only while a Codex or Claude Code executable passes the version
|
|
129
|
+
check. The endpoint is the session's `api_base_url` (for app-dev,
|
|
130
|
+
`https://app-dev.simy.one/api/local-cli/`). The history roots are
|
|
131
|
+
`$CODEX_HOME/sessions`, `$CODEX_HOME/archived_sessions`, and
|
|
132
|
+
`$CLAUDE_CONFIG_DIR/projects`, which default to `~/.codex` and `~/.claude`. When
|
|
133
|
+
the daemon skips a sync, it logs the reason once to stderr. Reasons include no
|
|
134
|
+
daemon mode, no valid session, and no compatible provider with each provider's
|
|
135
|
+
status. To test with synthetic history only, point every root at temp
|
|
136
|
+
directories and run the daemon in the foreground so its log stays visible.
|
|
137
|
+
Stop it with Ctrl-C after the `uploaded` line:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
export SIMY_HOME="$(mktemp -d)" CODEX_HOME="$(mktemp -d)" CLAUDE_CONFIG_DIR="$(mktemp -d)"
|
|
141
|
+
# write synthetic *.jsonl files under $CODEX_HOME/sessions and $CLAUDE_CONFIG_DIR/projects/<project>/
|
|
142
|
+
SIMY_DAEMON_CHILD=1 simy --daemon --host https://app-dev.simy.one --no-auto-update --no-workflow-prompt
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`SIMY_DAEMON_CHILD=1` keeps the daemon attached to the terminal. The sync
|
|
146
|
+
cursor is written under `$SIMY_HOME/work-pattern-history-sync/`.
|
|
147
|
+
|
|
107
148
|
The CLI starts a loopback HTTP agent on a random available port, keeps a
|
|
108
149
|
48-hour, origin-scoped local session, and opens a native coding chat. The first
|
|
109
150
|
chat message creates the remote audit ledger and starts the local Agentic Loop
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awak-app/simy-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.35",
|
|
4
4
|
"description": "Local SIMY executor for non-coding Local Tasks and Agentic Loop runs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,12 +36,13 @@
|
|
|
36
36
|
"test:e2e:completion-contract": "node ./scripts/completion-contract-e2e.js",
|
|
37
37
|
"test:e2e:console:real-provider": "node ./scripts/real-provider-console-e2e.js",
|
|
38
38
|
"test:e2e:console:fullstack": "node ./scripts/fullstack-cli-smoke.js",
|
|
39
|
-
"check": "npm run check:auto-update && node --check ./src/desktop-executor.js && node --check ./src/local-task.js && node --check ./scripts/desktop-executor-e2e.js && node --check ./scripts/pre-guardrail-e2e.js && node --check ./scripts/fixtures/fake-desktop-provider.js && npm run check:syntax && npm run check:real-provider-syntax && npm test && npm run check:package",
|
|
39
|
+
"check": "npm run check:auto-update && node --check ./src/desktop-executor.js && node --check ./src/local-task.js && node --check ./scripts/desktop-executor-e2e.js && node --check ./scripts/pre-guardrail-e2e.js && node --check ./scripts/fixtures/fake-desktop-provider.js && npm run check:syntax && npm run check:session-supervision-syntax && npm run check:real-provider-syntax && npm test && npm run check:package",
|
|
40
|
+
"check:session-supervision-syntax": "node --check ./src/session-supervision/index.js && node --check ./src/session-supervision/codex-app-server.js && node --check ./src/session-supervision/claude-sessions.js && node --check ./src/session-supervision/original-session-target.js",
|
|
40
41
|
"check:auto-update": "node --check ./src/auto-update.js && node --check ./scripts/auto-update-e2e.js && npm run check:sqm",
|
|
41
42
|
"check:workflow-observation-sender": "node --check ./src/workflow-observation-sender.js",
|
|
42
43
|
"check:sqm": "node --check ./src/sqm/canonical.js && node --check ./src/sqm/validation.js && node --check ./src/sqm/reliability.js && node --check ./src/sqm/repository.js && node --check ./src/sqm/checkers.js && node --check ./src/sqm/bundle-store.js && node --check ./src/sqm/proof.js && node --check ./src/sqm/evidence-client.js && node --check ./src/sqm/session.js && node --check ./src/sqm/index.js && node --check ./src/sqm/command.js && node --check ./src/sqm/agent-skill.js && node --check ./src/sqm/workflow-onboarding.js && node --check ./src/sqm/workflow-update.js && node --check ./src/sqm/review-worker.js && node --check ./scripts/sqm-complete-loop-e2e.js && node --check ./scripts/sqm-local-review-e2e.js",
|
|
43
44
|
"check:real-provider-syntax": "node --check ./scripts/real-codex-probe.js && node --check ./scripts/real-claude-probe.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/claude-parity-runtime-e2e.js && node --check ./scripts/claude-plugin-runtime-e2e.js",
|
|
44
|
-
"check:syntax": "node --check ./src/index.js && node --check ./src/install-update.js && node --check ./src/agent.js && node --check ./src/connection-discovery.js && node --check ./src/codex-plugins/simy/hooks/connection-reminder.mjs && node --check ./src/browser.js && node --check ./src/web-api.js && node --check ./src/durable-local-task-worker.js && node --check ./src/durable-local-task-steps-contract.js && node --check ./src/bounded-local-task-subtasks-contract.js && node --check ./src/bounded-local-task-subtask-pool.js && node --check ./src/local-task-artifact-contract.js && node --check ./src/execution-capability-contract.js && node --check ./src/shutdown.js && node --check ./src/run-registry.js && node --check ./src/direct-executor.js && node --check ./src/execution-guardrail.js && node --check ./src/backend-executable.js && node --check ./src/provider-stream.js && node --check ./src/console/index.js && node --check ./src/console/app.js && node --check ./src/console/commands.js && node --check ./src/local-attachments.js && node --check ./src/repository-inventory.js && node --check ./src/session-store.js && node --check ./src/web-origin.js && node --check ./src/workspace-context.js && node --check ./src/orchestrator/index.js && node --check ./src/orchestrator/shared.js && node --check ./src/orchestrator/recovery.js && node --check ./src/orchestrator/risk.js && node --check ./src/orchestrator/contract.js && node --check ./src/orchestrator/completion-contract.js && node --check ./src/orchestrator/pr-preparation.js && node --check ./src/orchestrator/minimum-completion.js && node --check ./src/orchestrator/delivery/scripts/check-minimum-completion.mjs && node --check ./src/orchestrator/instruction.js && node --check ./src/orchestrator/problem-solving.js && node --check ./src/orchestrator/budget.js && node --check ./src/orchestrator/execution-io.js && node --check ./src/orchestrator/presentation.js && node --check ./src/orchestrator/result.js && node --check ./src/orchestrator/retry.js && node --check ./src/orchestrator/evidence.js && node --check ./src/orchestrator/independent-audit.js && node --check ./src/orchestrator/audit.js && node --check ./src/orchestrator/loop.js && node --check ./src/runner.js && node --check ./src/coding-run-store.js && node --check ./scripts/fixtures/completion-contract-fixture.js && node --check ./scripts/fixtures/fake-coding-backend.js && node --check ./scripts/e2e-terminal-evidence.js && node --check ./scripts/audit-gate-e2e.js && node --check ./scripts/completion-contract-e2e.js && node --check ./scripts/retry-circuit-e2e.js && node --check ./scripts/follow-up-charter-e2e.js && node --check ./scripts/task-routing-e2e.js && node --check ./scripts/executor-version-preflight-e2e.js && node --check ./scripts/blocked-recovery-e2e.js && node --check ./scripts/process-localization-e2e.js && node --check ./scripts/hypothesis-retries-e2e.js && node --check ./scripts/budget-enforcement-e2e.js && node --check ./scripts/local-task-default-workspace-e2e.js && node --check ./scripts/local-task-idempotency-e2e.js && node --check ./scripts/console-e2e-fixture.js && node --check ./scripts/console-e2e.js && node --check ./scripts/console-recovery-e2e-fixture.js && node --check ./scripts/console-recovery-e2e.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/fullstack-cli-smoke.js && node --check ./scripts/check-package-contents.js && node --check ./src/codex-plugins/simy/hooks/delivery-loop.mjs && node --check ./src/delivery-hooks/command.js && node --check ./src/delivery-hooks/desktop.js",
|
|
45
|
+
"check:syntax": "node --check ./src/index.js && node --check ./src/install-update.js && node --check ./src/agent.js && node --check ./src/connection-discovery.js && node --check ./src/codex-plugins/simy/hooks/connection-reminder.mjs && node --check ./src/browser.js && node --check ./src/web-api.js && node --check ./src/durable-local-task-worker.js && node --check ./src/durable-local-task-steps-contract.js && node --check ./src/bounded-local-task-subtasks-contract.js && node --check ./src/bounded-local-task-subtask-pool.js && node --check ./src/local-task-artifact-contract.js && node --check ./src/execution-capability-contract.js && node --check ./src/shutdown.js && node --check ./src/run-registry.js && node --check ./src/direct-executor.js && node --check ./src/execution-guardrail.js && node --check ./src/backend-executable.js && node --check ./src/provider-stream.js && node --check ./src/console/index.js && node --check ./src/console/app.js && node --check ./src/console/commands.js && node --check ./src/local-attachments.js && node --check ./src/repository-inventory.js && node --check ./src/session-store.js && node --check ./src/web-origin.js && node --check ./src/workspace-context.js && node --check ./src/orchestrator/index.js && node --check ./src/orchestrator/shared.js && node --check ./src/orchestrator/recovery.js && node --check ./src/orchestrator/risk.js && node --check ./src/orchestrator/contract.js && node --check ./src/orchestrator/completion-contract.js && node --check ./src/orchestrator/pr-preparation.js && node --check ./src/orchestrator/minimum-completion.js && node --check ./src/orchestrator/delivery/scripts/check-minimum-completion.mjs && node --check ./src/orchestrator/instruction.js && node --check ./src/orchestrator/problem-solving.js && node --check ./src/orchestrator/budget.js && node --check ./src/orchestrator/execution-io.js && node --check ./src/orchestrator/presentation.js && node --check ./src/orchestrator/result.js && node --check ./src/orchestrator/retry.js && node --check ./src/orchestrator/evidence.js && node --check ./src/orchestrator/independent-audit.js && node --check ./src/orchestrator/audit.js && node --check ./src/orchestrator/loop.js && node --check ./src/runner.js && node --check ./src/coding-run-store.js && node --check ./scripts/fixtures/completion-contract-fixture.js && node --check ./scripts/fixtures/fake-coding-backend.js && node --check ./scripts/e2e-terminal-evidence.js && node --check ./scripts/audit-gate-e2e.js && node --check ./scripts/completion-contract-e2e.js && node --check ./scripts/retry-circuit-e2e.js && node --check ./scripts/follow-up-charter-e2e.js && node --check ./scripts/task-routing-e2e.js && node --check ./scripts/executor-version-preflight-e2e.js && node --check ./scripts/blocked-recovery-e2e.js && node --check ./scripts/process-localization-e2e.js && node --check ./scripts/hypothesis-retries-e2e.js && node --check ./scripts/budget-enforcement-e2e.js && node --check ./scripts/local-task-default-workspace-e2e.js && node --check ./scripts/local-task-idempotency-e2e.js && node --check ./scripts/console-e2e-fixture.js && node --check ./scripts/console-e2e.js && node --check ./scripts/console-recovery-e2e-fixture.js && node --check ./scripts/console-recovery-e2e.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/fullstack-cli-smoke.js && node --check ./scripts/check-package-contents.js && node --check ./src/codex-plugins/simy/hooks/delivery-loop.mjs && node --check ./src/delivery-hooks/command.js && node --check ./src/delivery-hooks/desktop.js && node --check ./src/delivery-hooks/supervisor.js",
|
|
45
46
|
"check:package": "node ./scripts/check-package-contents.js",
|
|
46
47
|
"build:macos-installer:dev": "bash packaging/build-macos-arm64.sh --unsigned-dev",
|
|
47
48
|
"build:macos-installer": "bash packaging/build-macos-arm64.sh --production",
|
package/src/agent.js
CHANGED
|
@@ -95,7 +95,10 @@ import {
|
|
|
95
95
|
classifyExecutionRequirement,
|
|
96
96
|
EXECUTION_GUARDRAIL_POLICY_VERSION,
|
|
97
97
|
} from "./execution-guardrail.js";
|
|
98
|
-
import {
|
|
98
|
+
import {
|
|
99
|
+
normalizeWorkflowObservationBinding,
|
|
100
|
+
normalizeWorkflowStartIntent,
|
|
101
|
+
} from "./workflow-observation-sender.js";
|
|
99
102
|
import {
|
|
100
103
|
createLocalTask,
|
|
101
104
|
createLocalTaskId,
|
|
@@ -132,6 +135,7 @@ import {
|
|
|
132
135
|
createSqmLocalReviewApi,
|
|
133
136
|
createSqmLocalReviewWorker,
|
|
134
137
|
} from "./sqm/review-worker.js";
|
|
138
|
+
import { createCodexWorkPatternSync, workPatternHistoryHomes } from "./codex-work-pattern-sync.js";
|
|
135
139
|
import {
|
|
136
140
|
publishConnectionDiscovery,
|
|
137
141
|
removeConnectionDiscovery,
|
|
@@ -232,6 +236,78 @@ export async function startAgent({
|
|
|
232
236
|
};
|
|
233
237
|
let durableLocalTaskWorker = null;
|
|
234
238
|
let sqmLocalReviewWorker = null;
|
|
239
|
+
let codexWorkPatternSync = null;
|
|
240
|
+
let codexWorkPatternSyncInFlight = null;
|
|
241
|
+
|
|
242
|
+
let codexWorkPatternSkipReason = null;
|
|
243
|
+
const pollCodexWorkPatterns = () => {
|
|
244
|
+
if (shuttingDown) return;
|
|
245
|
+
const skipReason = codexWorkPatternSkipReasonFor({
|
|
246
|
+
daemon,
|
|
247
|
+
sessionValid: isSessionValid(session, Date.now(), apiOrigin),
|
|
248
|
+
capabilities: availableCapabilities,
|
|
249
|
+
});
|
|
250
|
+
// Report each distinct skip reason once so a skipped sync is never silent
|
|
251
|
+
// without repeating the same line on every heartbeat.
|
|
252
|
+
if (skipReason !== codexWorkPatternSkipReason) {
|
|
253
|
+
codexWorkPatternSkipReason = skipReason;
|
|
254
|
+
if (skipReason) reportCodexWorkPatternSyncStatus(`skipped: ${skipReason}`, quiet);
|
|
255
|
+
}
|
|
256
|
+
if (skipReason) return;
|
|
257
|
+
if (!codexWorkPatternSync) {
|
|
258
|
+
if (dependencies.codexWorkPatternSync) {
|
|
259
|
+
codexWorkPatternSync = dependencies.codexWorkPatternSync;
|
|
260
|
+
} else {
|
|
261
|
+
const homes = workPatternHistoryHomes({
|
|
262
|
+
codexHome: dependencies.codexHome,
|
|
263
|
+
claudeHome: dependencies.claudeHome,
|
|
264
|
+
});
|
|
265
|
+
reportCodexWorkPatternSyncStatus(
|
|
266
|
+
`reading history roots CODEX_HOME=${homes.codexHome} `
|
|
267
|
+
+ `(sessions/, archived_sessions/) and CLAUDE_CONFIG_DIR=${homes.claudeHome} (projects/); `
|
|
268
|
+
+ `state under ${sessionRoot}.`,
|
|
269
|
+
quiet,
|
|
270
|
+
);
|
|
271
|
+
codexWorkPatternSync = createCodexWorkPatternSync({ sessionRoot, ...homes });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
let syncPromise;
|
|
275
|
+
try {
|
|
276
|
+
syncPromise = codexWorkPatternSync.poll({
|
|
277
|
+
apiOrigin,
|
|
278
|
+
apiBaseUrl: session.api_base_url,
|
|
279
|
+
token: session.token,
|
|
280
|
+
deviceId: session.device_id,
|
|
281
|
+
accountId: session.account_id,
|
|
282
|
+
});
|
|
283
|
+
} catch (error) {
|
|
284
|
+
reportCodexWorkPatternSyncError(error, quiet);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const observed = Promise.resolve(syncPromise)
|
|
288
|
+
.then((result) => {
|
|
289
|
+
// `poll` returns undefined while throttled by the 15-minute interval.
|
|
290
|
+
if (!shuttingDown && result?.status) {
|
|
291
|
+
reportCodexWorkPatternSyncStatus(
|
|
292
|
+
`${result.status}; uploaded ${Number(result.uploaded || 0)} observation chunk(s).`,
|
|
293
|
+
quiet,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (!shuttingDown && Number(result?.skipped_oversized || 0) > 0) {
|
|
297
|
+
reportCodexWorkPatternSyncError(
|
|
298
|
+
new Error(`${result.skipped_oversized} observation(s) exceeded the gateway limit.`),
|
|
299
|
+
quiet,
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
.catch((error) => {
|
|
304
|
+
if (!shuttingDown) reportCodexWorkPatternSyncError(error, quiet);
|
|
305
|
+
});
|
|
306
|
+
codexWorkPatternSyncInFlight = observed;
|
|
307
|
+
void observed.finally(() => {
|
|
308
|
+
if (codexWorkPatternSyncInFlight === observed) codexWorkPatternSyncInFlight = null;
|
|
309
|
+
});
|
|
310
|
+
};
|
|
235
311
|
let loginUrl = null;
|
|
236
312
|
const connectionStatus = createConnectionStatusTracker({ now: dependencies.statusNow });
|
|
237
313
|
const codexStatus = createCodexStatusInspector({
|
|
@@ -463,6 +539,7 @@ export async function startAgent({
|
|
|
463
539
|
await heartbeatDevice({ apiOrigin, apiBaseUrl: session.api_base_url, token: session.token,
|
|
464
540
|
port, capabilities: refreshAvailableCapabilities(), repoInventory: repositoryInventory });
|
|
465
541
|
}
|
|
542
|
+
pollCodexWorkPatterns();
|
|
466
543
|
};
|
|
467
544
|
if (deferStartupSynchronization) {
|
|
468
545
|
void publishVerifiedProviders().catch((error) => reportHeartbeatError(error, quiet));
|
|
@@ -1074,11 +1151,19 @@ export async function startAgent({
|
|
|
1074
1151
|
throw error;
|
|
1075
1152
|
}
|
|
1076
1153
|
let workflowObservationBinding;
|
|
1154
|
+
let workflowStartIntent;
|
|
1077
1155
|
try {
|
|
1078
1156
|
workflowObservationBinding = normalizeWorkflowObservationBinding(
|
|
1079
1157
|
body.workflow_observation_binding,
|
|
1080
1158
|
{ provider: body.backend },
|
|
1081
1159
|
);
|
|
1160
|
+
workflowStartIntent = normalizeWorkflowStartIntent(
|
|
1161
|
+
body.workflow_start_intent,
|
|
1162
|
+
{ provider: body.backend },
|
|
1163
|
+
);
|
|
1164
|
+
if (workflowObservationBinding && workflowStartIntent) {
|
|
1165
|
+
throw new Error("WorkFlow binding and start intent are mutually exclusive.");
|
|
1166
|
+
}
|
|
1082
1167
|
} catch (error) {
|
|
1083
1168
|
json(res, 400, {
|
|
1084
1169
|
error: error instanceof Error ? error.message : "WorkFlow observation binding is invalid.",
|
|
@@ -1102,6 +1187,7 @@ export async function startAgent({
|
|
|
1102
1187
|
attachmentManifest: preparedAttachments,
|
|
1103
1188
|
scenarioPack,
|
|
1104
1189
|
workflowObservationBinding,
|
|
1190
|
+
workflowStartIntent,
|
|
1105
1191
|
});
|
|
1106
1192
|
hashLocalTaskIdempotencyKey(idempotencyKey);
|
|
1107
1193
|
} catch (error) {
|
|
@@ -1227,6 +1313,7 @@ export async function startAgent({
|
|
|
1227
1313
|
idempotencyKeyHash: hashLocalTaskIdempotencyKey(idempotencyKey),
|
|
1228
1314
|
requestFingerprint,
|
|
1229
1315
|
workflowObservationBinding,
|
|
1316
|
+
workflowStartIntent,
|
|
1230
1317
|
});
|
|
1231
1318
|
await persistLocalTask(task);
|
|
1232
1319
|
localTaskRegistry.create(task);
|
|
@@ -1463,11 +1550,19 @@ export async function startAgent({
|
|
|
1463
1550
|
}
|
|
1464
1551
|
const indexedRepository = await ensureRepositoryIndexed(body.repository);
|
|
1465
1552
|
let workflowObservationBinding;
|
|
1553
|
+
let workflowStartIntent;
|
|
1466
1554
|
try {
|
|
1467
1555
|
workflowObservationBinding = normalizeWorkflowObservationBinding(
|
|
1468
1556
|
body.workflow_observation_binding,
|
|
1469
1557
|
{ provider: body.backend },
|
|
1470
1558
|
);
|
|
1559
|
+
workflowStartIntent = normalizeWorkflowStartIntent(
|
|
1560
|
+
body.workflow_start_intent,
|
|
1561
|
+
{ provider: body.backend },
|
|
1562
|
+
);
|
|
1563
|
+
if (workflowObservationBinding && workflowStartIntent) {
|
|
1564
|
+
throw new Error("WorkFlow binding and start intent are mutually exclusive.");
|
|
1565
|
+
}
|
|
1471
1566
|
} catch (error) {
|
|
1472
1567
|
json(res, 400, {
|
|
1473
1568
|
error: error instanceof Error ? error.message : "WorkFlow observation binding is invalid.",
|
|
@@ -1517,6 +1612,7 @@ export async function startAgent({
|
|
|
1517
1612
|
must_not: Array.isArray(body.must_not) ? body.must_not : [],
|
|
1518
1613
|
proposal_id: typeof body.proposal_id === "string" ? body.proposal_id : null,
|
|
1519
1614
|
workflow_observation_binding: workflowObservationBinding,
|
|
1615
|
+
workflow_start_intent: workflowStartIntent,
|
|
1520
1616
|
charter_context:
|
|
1521
1617
|
body.charter_context &&
|
|
1522
1618
|
typeof body.charter_context === "object" &&
|
|
@@ -1848,6 +1944,8 @@ export async function startAgent({
|
|
|
1848
1944
|
if (codingRunMonitorTimer) clearInterval(codingRunMonitorTimer);
|
|
1849
1945
|
if (codingRunMonitorInFlight) await codingRunMonitorInFlight;
|
|
1850
1946
|
updateManager?.stop?.();
|
|
1947
|
+
await codexWorkPatternSync?.close?.();
|
|
1948
|
+
await codexWorkPatternSyncInFlight;
|
|
1851
1949
|
await sqmLocalReviewWorker?.close?.();
|
|
1852
1950
|
await durableLocalTaskWorker?.close?.();
|
|
1853
1951
|
try {
|
|
@@ -2142,6 +2240,35 @@ function reportSqmLocalReviewError(error, quiet) {
|
|
|
2142
2240
|
);
|
|
2143
2241
|
}
|
|
2144
2242
|
|
|
2243
|
+
export function codexWorkPatternSkipReasonFor({ daemon, sessionValid, capabilities }) {
|
|
2244
|
+
if (!daemon) return "history sync runs only in daemon mode (simy --daemon).";
|
|
2245
|
+
if (!sessionValid) return "no valid SIMY session for this Web origin; sign in first.";
|
|
2246
|
+
if (capabilities?.features?.codex_work_pattern_source === true) return null;
|
|
2247
|
+
const versions = capabilities?.backend_versions || {};
|
|
2248
|
+
const describe = (provider) => {
|
|
2249
|
+
const inspection = versions[provider];
|
|
2250
|
+
if (!inspection) return `${provider}=unknown`;
|
|
2251
|
+
return `${provider}=${inspection.status || "unknown"}`
|
|
2252
|
+
+ (inspection.installed_version ? ` ${inspection.installed_version}` : "")
|
|
2253
|
+
+ (inspection.minimum_version ? ` (requires ${inspection.minimum_version}+)` : "");
|
|
2254
|
+
};
|
|
2255
|
+
return "no compatible Codex or Claude Code executable was detected "
|
|
2256
|
+
+ `(${describe("codex")}, ${describe("claude")}); history roots were not read. `
|
|
2257
|
+
+ "Install or update a provider, or set SIMY_CODEX_BIN / SIMY_CLAUDE_BIN.";
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
function reportCodexWorkPatternSyncStatus(message, quiet) {
|
|
2261
|
+
if (quiet) return;
|
|
2262
|
+
console.error(`SIMY work-pattern history sync: ${message}`);
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
function reportCodexWorkPatternSyncError(error, quiet) {
|
|
2266
|
+
if (quiet) return;
|
|
2267
|
+
console.error(
|
|
2268
|
+
`SIMY work-pattern history sync: ${error instanceof Error ? error.message : String(error)}`,
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2145
2272
|
function reportStartupConnectionError(error, quiet) {
|
|
2146
2273
|
if (quiet) return;
|
|
2147
2274
|
console.error(
|
|
@@ -2257,7 +2384,12 @@ function capabilitiesFromInspections(codex, claude) {
|
|
|
2257
2384
|
durable_local_task_step_model: true,
|
|
2258
2385
|
bounded_local_task_subtasks: true,
|
|
2259
2386
|
sqm_agent_skill_management: true,
|
|
2387
|
+
// Web adds `terminal_contract` to a WorkFlow binding only for CLIs that
|
|
2388
|
+
// advertise this; older CLIs reject a fifth binding key.
|
|
2389
|
+
workflow_terminal_contract: true,
|
|
2390
|
+
workflow_deliverable_upload: true,
|
|
2260
2391
|
sqm_local_review: codex.compatible || claude.compatible,
|
|
2392
|
+
codex_work_pattern_source: codex.compatible || claude.compatible,
|
|
2261
2393
|
},
|
|
2262
2394
|
session_ttl_hours: 48,
|
|
2263
2395
|
};
|
|
@@ -2616,7 +2748,11 @@ function daemonCapabilities(inspectedCapabilities, daemon) {
|
|
|
2616
2748
|
inspectedCapabilities?.features || {},
|
|
2617
2749
|
"sqm_local_review",
|
|
2618
2750
|
);
|
|
2619
|
-
|
|
2751
|
+
const hasCodexWorkPatternSource = Object.hasOwn(
|
|
2752
|
+
inspectedCapabilities?.features || {},
|
|
2753
|
+
"codex_work_pattern_source",
|
|
2754
|
+
);
|
|
2755
|
+
return durableControlPlane || hasSqmLocalReview || hasCodexWorkPatternSource
|
|
2620
2756
|
? {
|
|
2621
2757
|
...inspectedCapabilities,
|
|
2622
2758
|
features: {
|
|
@@ -2645,6 +2781,12 @@ function daemonCapabilities(inspectedCapabilities, daemon) {
|
|
|
2645
2781
|
daemon && inspectedCapabilities?.features?.sqm_local_review === true,
|
|
2646
2782
|
}
|
|
2647
2783
|
: {}),
|
|
2784
|
+
...(hasCodexWorkPatternSource
|
|
2785
|
+
? {
|
|
2786
|
+
codex_work_pattern_source:
|
|
2787
|
+
daemon && inspectedCapabilities?.features?.codex_work_pattern_source === true,
|
|
2788
|
+
}
|
|
2789
|
+
: {}),
|
|
2648
2790
|
},
|
|
2649
2791
|
}
|
|
2650
2792
|
: inspectedCapabilities;
|
|
@@ -3,6 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
const MACOS_CODEX_BINARY = "/Applications/ChatGPT.app/Contents/Resources/codex";
|
|
6
|
+
const MACOS_CODEX_BUNDLED_BINARY = "/Applications/ChatGPT.app/Contents/Resources/codex-cli/bin/codex";
|
|
6
7
|
|
|
7
8
|
export const BACKEND_VERSION_POLICIES = Object.freeze({
|
|
8
9
|
codex: Object.freeze({
|
|
@@ -86,7 +87,7 @@ export function backendCandidates(backend, {
|
|
|
86
87
|
return [
|
|
87
88
|
environment.SIMY_CODEX_BIN,
|
|
88
89
|
"codex",
|
|
89
|
-
...(platform === "darwin" ? [MACOS_CODEX_BINARY] : []),
|
|
90
|
+
...(platform === "darwin" ? [MACOS_CODEX_BUNDLED_BINARY, MACOS_CODEX_BINARY] : []),
|
|
90
91
|
];
|
|
91
92
|
}
|
|
92
93
|
|
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.5.
|
|
16
|
+
export const CLI_VERSION = "0.5.35";
|
|
17
17
|
export const CLI_API_CONTRACT_VERSION = 10;
|
|
18
18
|
|
|
19
19
|
export function withCliContract(
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
"Run the SIMY SQM Loop for the current thread.",
|
|
30
30
|
"Review the current pull request with SIMY.",
|
|
31
31
|
"Start SIMY Delivery Loop for the current task."
|
|
32
|
-
]
|
|
32
|
+
],
|
|
33
|
+
"composerIcon": "./assets/logo.png",
|
|
34
|
+
"logo": "./assets/logo.png",
|
|
35
|
+
"logoDark": "./assets/logo.png"
|
|
33
36
|
}
|
|
34
37
|
}
|
|
Binary file
|