@awak-app/simy-cli 0.2.3 → 0.4.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # SIMY CLI
2
2
 
3
- Local execution agent for SIMY Agentic Loop runs.
3
+ Local execution agent for SIMY Local Tasks and Agentic Loop runs.
4
4
 
5
5
  For normal use, install SIMY globally and keep its background agent running:
6
6
 
@@ -44,6 +44,95 @@ the Provider command boundary, and permits exactly one Provider invocation. It
44
44
  does not create an Agentic Loop ledger, audit session, or retry lifecycle for
45
45
  that task.
46
46
 
47
+ ## Local Tasks
48
+
49
+ CLI API contract v9 promotes non-coding work to a first-class **Local Task**
50
+ runtime. A Local Task is separate from Agentic Loop: it runs one bounded Codex
51
+ or Claude Code session without Git branches, pull requests, audits, or automatic
52
+ Provider retries. Knowledge-work deliverables use an isolated task sandbox by
53
+ default, so they do not require a repository.
54
+
55
+ `POST /v1/local-tasks/start` accepts JSON or the same verified multipart
56
+ attachment envelope used by Agentic Loop and requires a stable
57
+ `Idempotency-Key`. Repeating the same request returns the original task; using
58
+ the same key for different content returns
59
+ `LOCAL_TASK_IDEMPOTENCY_CONFLICT`. `GET /v1/local-tasks/reconcile` with the same
60
+ header recovers a task when the original response was lost. Only the key hash is
61
+ persisted. Task state, verified inputs, and the event log stay under
62
+ `~/.simy/tasks/<task-id>/`. Tasks that do not need a Git
63
+ repository run in `~/simy/<task-id>/`, with generated files in its `outputs/`
64
+ directory. The public snapshot exposes this user-facing workspace as
65
+ `workspace_display_path` without exposing internal state paths. Set
66
+ `SIMY_LOCAL_TASK_WORKSPACE_ROOT` to override the default workspace root.
67
+
68
+ Local Tasks provide:
69
+
70
+ - `GET /v1/local-tasks/<id>` for the current structured snapshot;
71
+ - `GET /v1/local-tasks/reconcile` for request-key reconciliation;
72
+ - `GET /v1/local-tasks/<id>/stream` for live Server-Sent Events;
73
+ - `POST /v1/local-tasks/<id>/control` with `{"action":"stop"}`;
74
+ - `GET /v1/local-tasks/<id>/artifacts/<artifact-id>` for a verified output;
75
+ - one Provider invocation, a configurable Provider-token safety budget, and a
76
+ bounded runtime timeout;
77
+ - restart-safe terminal persistence. An interrupted active task fails closed
78
+ after CLI restart and is never replayed automatically.
79
+
80
+ Interactive Pipelines can use the same daemon worker for a `local_task` node.
81
+ The CLI still invokes the selected Provider exactly once. Before the node is
82
+ reported as successful, every output file is re-verified, uploaded through a
83
+ task-bound short-lived URL, and committed only after SIMY rechecks its byte
84
+ size and SHA-256 digest. Ordinary My AI Local Tasks keep their existing local
85
+ verified-download behavior. Scheduled or unattended Pipeline runs are not
86
+ allowed to select a desktop implicitly.
87
+
88
+ Web and Backend may opt into `durable_local_task_steps` for a versioned
89
+ multi-step Local Task. The daemon then claims and executes one closed-schema
90
+ step at a time (maximum eight), with an independent Provider invocation
91
+ boundary per step and aggregate step, token, and runtime budgets. The task
92
+ workspace is stable for the turn while each lease attempt has its own local
93
+ record. A step that crossed its Provider boundary is never replayed
94
+ automatically.
95
+
96
+ Plan initialization uses a two-phase claim. Web stores an authoritative
97
+ `execution_spec.controlled_plan`; the CLI validates that its Provider,
98
+ operation, permission, repository, approval target, and aggregate budgets
99
+ cannot exceed the enclosing execution spec, then submits the exact plan for
100
+ Backend persistence. The CLI never asks a Provider to infer or expand a plan.
101
+ Older one-shot requests receive a deterministic one-step compatibility plan.
102
+
103
+ Human approval and unknown Provider results are distinct non-executable
104
+ dispositions. Neither holds a Provider process, heartbeat lease, or update
105
+ work reservation. Only bounded summaries and verified artifact references from
106
+ completed steps may enter the next step's context. Unknown plan fields,
107
+ unscoped approvals, unsafe paths, and Provider-supplied risk metadata fail
108
+ closed. The original `local_task_execution.v1` one-shot path remains available
109
+ unchanged for clients that do not negotiate this feature.
110
+
111
+ Contract 10 additionally advertises `bounded_local_task_subtasks`. Backend
112
+ admits at most two Provider children at once from a closed `parallel_reads`
113
+ plan with 2-4 source-bound candidates. When Crew declines or times out, the
114
+ same v2 contract can admit one `serial_uploaded` read-only child for 2-4
115
+ uploaded sources; this fallback never routes those uploads through the v1 CLI
116
+ staging materializer. The CLI never prefetches beyond an available execution slot:
117
+ each child starts only after a fenced server claim and an explicitly confirmed
118
+ invocation boundary. Children inherit the parent Provider and model, run in
119
+ separate read-only task sandboxes, receive only verified immutable SIMY uploads,
120
+ and cannot use mutation tools or nested delegation. Downloaded bytes are checked
121
+ against the claimed size and SHA-256 digest, then exposed through a mode `0400`
122
+ file without revealing the storage URI to the Provider.
123
+
124
+ Cancellation uses one pool-wide abort signal and prevents new claims. Unknown
125
+ invocation or final-status boundaries are never replayed automatically. Sibling
126
+ fan-in summaries remain explicitly untrusted data, and all lease, generation,
127
+ budget, usage, and elapsed-time bigint fields cross the JSON boundary as
128
+ canonical decimal strings. The contract 9 `durable_local_task_steps` path
129
+ remains serial and unchanged.
130
+
131
+ External side effects such as sending messages, submitting forms, uploading, or
132
+ purchasing are outside this MVP. The router rejects them instead of silently
133
+ granting broad permissions. The legacy `/v1/direct-execution/*` contract remains
134
+ available for older Web clients.
135
+
47
136
  ## CLI updates
48
137
 
49
138
  The CLI checks the npm registry at startup and once per hour while it is
@@ -114,6 +203,61 @@ limit. SIMY Web can edit that suggestion and call
114
203
  `provider_token_budget`. The CLI persists the higher limit and resumes the same
115
204
  run. SIMY token consumption remains a separate platform billing record.
116
205
 
206
+ ## SQM local checks
207
+
208
+ SQM deliberately has two identity-bound stages:
209
+
210
+ 1. `simy sqm min-check` quickly inspects committed changes, the working tree,
211
+ untracked files, and deletions. It runs only deterministic low-cost rules,
212
+ reports preliminary findings, and writes the applicable state, transition,
213
+ stress, and scenario plan. A passing min-check is not a complete validation.
214
+ 2. `simy sqm check` verifies that repository, base, HEAD, working-tree digest,
215
+ and signed bundle still match the min-check. It then evaluates applicable
216
+ state transitions, invariants, stress/strength expectations, and scenarios,
217
+ writes `proof.json`, and signs that proof with the local device identity.
218
+
219
+ Normal runs do not require a separate sync command: the CLI
220
+ uses a verified local cache and revalidates it with TTL and ETag semantics.
221
+ The Agentic Loop runs min-check after each code modification and the full check
222
+ before PR readiness. Findings and the redacted signed-proof summary are recorded
223
+ in its audit; source text is never uploaded.
224
+
225
+ Configure the bundle service with `SIMY_SQM_BUNDLE_URL`. Authentication uses
226
+ the current SIMY session in the coding loop, or `SIMY_SQM_TOKEN`/
227
+ `SIMY_ACCESS_TOKEN` for the diagnostic command. On the first authenticated
228
+ HTTPS request, the CLI receives the bundle verification key from the SIMY
229
+ gateway, verifies the signed bundle, and pins that key to the endpoint,
230
+ account, organization, and repository cache identity for offline use. Explicit
231
+ trust anchors can instead be configured as a JSON key-ID map in
232
+ `SIMY_SQM_PUBLIC_KEYS_JSON`, or as one `SIMY_SQM_KEY_ID` plus
233
+ `SIMY_SQM_PUBLIC_KEY`. Public keys may be PEM, base64 SPKI, or a base64 raw
234
+ 32-byte Ed25519 key. Optional settings are:
235
+
236
+ - `SIMY_SQM_CACHE_DIR`: verified bundle cache location.
237
+ - `SIMY_SQM_CACHE_TTL_MS`: revalidation TTL, defaulting to five minutes.
238
+ - `SIMY_SQM_ACCOUNT_ID` and `SIMY_SQM_ORGANIZATION_ID`: tenant identity for
239
+ diagnostic checks. Coding-loop checks receive tenant identity from the
240
+ authenticated session. Cache entries are isolated by endpoint, account,
241
+ organization, and repository, and the organization is verified against the
242
+ signed bundle. `SIMY_SQM_ORGANIZATION_ID` is required for standalone
243
+ diagnostic checks; without a tenant identity SQM fails closed in shadow mode.
244
+
245
+ Use either phase with `--offline` to prohibit network access and `--refresh` to force
246
+ ETag revalidation, `--base <branch>` to select a base branch, and `--json` for
247
+ machine-readable results. Full check additionally accepts `--min-result`,
248
+ `--proof`, `--signed-evidence`, and `--no-upload`. The min result and full proof
249
+ share one pinned signed bundle and one exact repository identity, so a code
250
+ change cannot silently reuse an old preflight. If Cloud is unavailable, the CLI clearly warns and
251
+ uses the last unexpired signature-verified bundle only after a network failure
252
+ or Cloud 5xx response. Authentication, authorization, compatibility,
253
+ signature, schema, tenant, and expiry failures never execute stale knowledge.
254
+ With no verified cache it skips SQM
255
+ in shadow mode. Bundles contain only the fixed declarative checker vocabulary;
256
+ the CLI never executes shell, JavaScript, Python, WASM, or another remotely
257
+ supplied implementation. A module's matcher array has explicit **AND semantics**:
258
+ every matcher must match before any check in that module runs; it is not an OR
259
+ list.
260
+
117
261
  ## Interactive console
118
262
 
119
263
  Running `simy` in a terminal opens the Agentic Loop chat. It discovers the
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@awak-app/simy-cli",
3
- "version": "0.2.3",
4
- "description": "Local SIMY Agentic Loop executor for Codex and Claude Code.",
3
+ "version": "0.4.0",
4
+ "description": "Local SIMY executor for non-coding Local Tasks and Agentic Loop runs.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "simy": "src/index.js"
@@ -14,6 +14,10 @@
14
14
  "start": "node ./src/index.js",
15
15
  "test": "node --test",
16
16
  "test:e2e:console": "node ./scripts/console-e2e.js",
17
+ "test:e2e:sqm-complete-loop": "node ./scripts/sqm-complete-loop-e2e.js",
18
+ "test:e2e:console:narrow": "CLI_E2E_COLUMNS=78 CLI_E2E_ROWS=40 node ./scripts/console-e2e.js",
19
+ "test:e2e:console:no-color": "CLI_E2E_NO_COLOR=1 node ./scripts/console-e2e.js",
20
+ "test:e2e:console:recovery": "node ./scripts/console-recovery-e2e.js",
17
21
  "test:e2e:auto-update": "node ./scripts/auto-update-e2e.js",
18
22
  "test:e2e:audit-gate": "node ./scripts/audit-gate-e2e.js",
19
23
  "test:e2e:retry-circuit": "node ./scripts/retry-circuit-e2e.js",
@@ -26,13 +30,16 @@
26
30
  "test:e2e:budgets": "node ./scripts/budget-enforcement-e2e.js",
27
31
  "test:e2e:desktop-executor": "node ./scripts/desktop-executor-e2e.js",
28
32
  "test:e2e:pre-guardrail": "node ./scripts/pre-guardrail-e2e.js",
33
+ "test:e2e:local-task-default-workspace": "node ./scripts/local-task-default-workspace-e2e.js",
34
+ "test:e2e:local-task-idempotency": "node ./scripts/local-task-idempotency-e2e.js",
29
35
  "test:e2e:completion-contract": "node ./scripts/completion-contract-e2e.js",
30
36
  "test:e2e:console:real-provider": "node ./scripts/real-provider-console-e2e.js",
31
37
  "test:e2e:console:fullstack": "node ./scripts/fullstack-cli-smoke.js",
32
- "check": "npm run check:auto-update && node --check ./src/desktop-executor.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",
33
- "check:auto-update": "node --check ./src/auto-update.js && node --check ./scripts/auto-update-e2e.js",
38
+ "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:auto-update": "node --check ./src/auto-update.js && node --check ./scripts/auto-update-e2e.js && npm run check:sqm",
40
+ "check:sqm": "node --check ./src/sqm/canonical.js && node --check ./src/sqm/validation.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 ./scripts/sqm-complete-loop-e2e.js",
34
41
  "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",
35
- "check:syntax": "node --check ./src/index.js && node --check ./src/agent.js && node --check ./src/browser.js && node --check ./src/web-api.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/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 ./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/console-e2e-fixture.js && node --check ./scripts/console-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",
42
+ "check:syntax": "node --check ./src/index.js && node --check ./src/agent.js && 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/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 ./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",
36
43
  "check:package": "node ./scripts/check-package-contents.js"
37
44
  },
38
45
  "engines": {
@@ -52,6 +59,8 @@
52
59
  },
53
60
  "dependencies": {
54
61
  "ink": "^6.8.0",
62
+ "pdf-lib": "^1.17.1",
63
+ "pngjs": "^7.0.0",
55
64
  "react": "^19.2.0"
56
65
  },
57
66
  "devDependencies": {