@awak-app/simy-cli 0.5.7 → 0.5.10
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 +54 -1
- package/package.json +7 -3
- package/src/agent.js +71 -10
- package/src/auto-update.js +312 -35
- package/src/browser.js +24 -7
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/SKILL.md +188 -12
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md +130 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/change-boundary-matrix.md +20 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/cross-repository-control.md +76 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/delivery-levels.md +76 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/local-sqm-evidence.md +34 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md +15 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs +191 -0
- package/src/console/app.js +21 -2
- package/src/console/commands.js +3 -0
- package/src/desktop-host.js +220 -0
- package/src/desktop-process-lock.js +231 -0
- package/src/desktop-status.js +263 -0
- package/src/direct-executor.js +6 -0
- package/src/index.js +38 -12
- package/src/install-update.js +494 -0
- package/src/sqm/agent-skill.js +61 -75
- package/src/sqm/command.js +3 -0
- package/src/sqm/local-evidence.js +28 -0
- package/src/sqm/workflow-onboarding.js +1 -1
- package/src/sqm/workflow-update.js +3 -2
package/README.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
Local execution agent for SIMY Local Tasks and Agentic Loop runs.
|
|
4
4
|
|
|
5
|
+
## Apple Silicon Mac app
|
|
6
|
+
|
|
7
|
+
The macOS installer includes a native status window and menu bar app. Open
|
|
8
|
+
SIMY CLI from Applications and choose **Sign in**. The window shows SIMY login,
|
|
9
|
+
the connected Web address and last successful heartbeat, Codex installation and
|
|
10
|
+
login status, tasks, and updates separately. A Codex login check does not prove
|
|
11
|
+
that a task can execute successfully; permissions and service availability are
|
|
12
|
+
checked when work starts.
|
|
13
|
+
|
|
14
|
+
Closing the window keeps the agent running. Open the app again or choose
|
|
15
|
+
**Show SIMY CLI** from its menu bar icon to return. **Quit SIMY CLI** asks before
|
|
16
|
+
interrupting active tasks. The normal `simy` command remains available.
|
|
17
|
+
|
|
18
|
+
Signed patch/minor updates wait for idle and verify the new runtime before
|
|
19
|
+
handoff; failed startup restores the previous installed version. After a runtime
|
|
20
|
+
update, quit and reopen the app to load an updated native interface. The status
|
|
21
|
+
window reports App and runtime versions separately while they differ.
|
|
22
|
+
|
|
23
|
+
For development, `npm run build:macos-installer:dev` creates an unsigned app/DMG;
|
|
24
|
+
production builds require Developer ID signing and notarization. Never publish
|
|
25
|
+
unsigned development artifacts through the stable update manifest.
|
|
26
|
+
|
|
5
27
|
For normal use, install SIMY globally and keep its background agent running:
|
|
6
28
|
|
|
7
29
|
```bash
|
|
@@ -11,9 +33,12 @@ simy --daemon
|
|
|
11
33
|
|
|
12
34
|
When an interactive `simy --daemon` starts without managed SIMY workflows,
|
|
13
35
|
the CLI asks once before installing the Codex plugin
|
|
14
|
-
marketplace
|
|
36
|
+
marketplace and Codex/Claude opt-in SQM skills. Existing unrelated plugins
|
|
15
37
|
and hooks are preserved. Use `--install-workflows` for explicit non-interactive
|
|
16
38
|
installation or `--no-workflow-prompt` to start the daemon without asking.
|
|
39
|
+
|
|
40
|
+
SQM checks apply when you explicitly select `@simy`, invoke the SQM skill, or ask to use SQM for the current task. Ordinary PR creation and `git push` do not opt in. Upgrading and restarting the daemon migrates the legacy global PR gate and shipped personal skills; unrelated hooks are preserved. Start a new coding session to reload skill instructions.
|
|
41
|
+
|
|
17
42
|
After installation, restart Codex and find and install **SIMY** in **Plugins**
|
|
18
43
|
before using `@simy` in a new task.
|
|
19
44
|
|
|
@@ -370,6 +395,13 @@ processes, and exercises HIL plus lifecycle controls. It regenerates the
|
|
|
370
395
|
screenshots, terminal frames, raw transcript, and SHA-256 manifest under
|
|
371
396
|
`docs/pr-evidence/cli-agentic-loop-console/`.
|
|
372
397
|
|
|
398
|
+
## Delivery Loop design proposals
|
|
399
|
+
|
|
400
|
+
The [minimum completion plan](docs/delivery-minimum-completion/README.md) describes
|
|
401
|
+
proposed checks for omitted requirements, inactive controls, unsaved results, and
|
|
402
|
+
broken integrations at every delivery level, with workflow, sequence, and state
|
|
403
|
+
diagrams. This is a design proposal, not a shipped completion guarantee.
|
|
404
|
+
|
|
373
405
|
## Publishing
|
|
374
406
|
|
|
375
407
|
Publishing is handled by GitHub Actions in `.github/workflows/publish.yml`.
|
|
@@ -391,3 +423,24 @@ original snapshot. A scope revision change requires a fresh minimum check.
|
|
|
391
423
|
Deploy this CLI and the web capability proxy before enabling the backend scope
|
|
392
424
|
requirement. Older clients receive an explicit upgrade error, never an expanded
|
|
393
425
|
organization-wide bundle.
|
|
426
|
+
|
|
427
|
+
### Submit repaired local delivery evidence to SQM
|
|
428
|
+
|
|
429
|
+
The bundled Delivery Loop maintains an external acceptance checklist with separate
|
|
430
|
+
user-journey and technical-invariant results. It refreshes the table after each
|
|
431
|
+
evaluated action and marks evidence pending when the code or runtime context
|
|
432
|
+
changes. The [acceptance evidence guide](src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md)
|
|
433
|
+
documents the offline validator shipped inside the skill. Its result establishes
|
|
434
|
+
record completeness and artifact integrity, not overall delivery or deployment.
|
|
435
|
+
At the start of each new run, the loop recommends and confirms one of five
|
|
436
|
+
[delivery levels](src/codex-plugins/simy/skills/agentic-delivery-loop/references/delivery-levels.md)
|
|
437
|
+
in chat. Risk-based ceilings keep sensitive or consequential changes on the
|
|
438
|
+
required safety level; the selection adjusts verification depth but grants no
|
|
439
|
+
additional authority.
|
|
440
|
+
|
|
441
|
+
`simy sqm submit-evidence --file delivery.json --host https://app-dev.simy.one`
|
|
442
|
+
submits an explicit bounded summary through your existing organization-bound device
|
|
443
|
+
session. `--dry-run` previews the exact document without uploading it. See the
|
|
444
|
+
[local evidence contract](src/codex-plugins/simy/skills/agentic-delivery-loop/references/local-sqm-evidence.md).
|
|
445
|
+
The receipt identifies the source digest and analysis job; it is not a declaration
|
|
446
|
+
that an incident or blocking rule has been published.
|
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.10",
|
|
4
4
|
"description": "Local SIMY executor for non-coding Local Tasks and Agentic Loop runs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,8 +40,12 @@
|
|
|
40
40
|
"check:auto-update": "node --check ./src/auto-update.js && node --check ./scripts/auto-update-e2e.js && npm run check:sqm",
|
|
41
41
|
"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",
|
|
42
42
|
"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",
|
|
43
|
-
"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",
|
|
44
|
-
"check:package": "node ./scripts/check-package-contents.js"
|
|
43
|
+
"check:syntax": "node --check ./src/index.js && node --check ./src/install-update.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",
|
|
44
|
+
"check:package": "node ./scripts/check-package-contents.js",
|
|
45
|
+
"build:macos-installer:dev": "bash packaging/build-macos-arm64.sh --unsigned-dev",
|
|
46
|
+
"build:macos-installer": "bash packaging/build-macos-arm64.sh --production",
|
|
47
|
+
"test:macos-installer": "node --test packaging/test-macos-packaging.mjs",
|
|
48
|
+
"build:macos-installer:production": "bash packaging/build-macos-arm64.sh --production"
|
|
45
49
|
},
|
|
46
50
|
"engines": {
|
|
47
51
|
"node": ">=20"
|
package/src/agent.js
CHANGED
|
@@ -48,6 +48,12 @@ import {
|
|
|
48
48
|
inspectDesktopExecutor,
|
|
49
49
|
normalizeDesktopExecutionTarget,
|
|
50
50
|
} from "./desktop-executor.js";
|
|
51
|
+
import {
|
|
52
|
+
createCodexStatusInspector,
|
|
53
|
+
createConnectionStatusTracker,
|
|
54
|
+
desktopAuthStatus,
|
|
55
|
+
desktopTaskStatus,
|
|
56
|
+
} from "./desktop-status.js";
|
|
51
57
|
import { recoveryContractForPreflight } from "./orchestrator/recovery.js";
|
|
52
58
|
import {
|
|
53
59
|
DEFAULT_RETRY_BUDGET,
|
|
@@ -237,6 +243,25 @@ export async function startAgent({
|
|
|
237
243
|
let heartbeatInFlight = null;
|
|
238
244
|
let durableLocalTaskWorker = null;
|
|
239
245
|
let sqmLocalReviewWorker = null;
|
|
246
|
+
let loginUrl = null;
|
|
247
|
+
const connectionStatus = createConnectionStatusTracker({ now: dependencies.statusNow });
|
|
248
|
+
const codexStatus = createCodexStatusInspector({
|
|
249
|
+
inspect: dependencies.inspectCodexStatus,
|
|
250
|
+
now: dependencies.statusNowMs,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const requestDesktopLogin = () => {
|
|
254
|
+
if (isSessionValid(session, Date.now(), apiOrigin)) return null;
|
|
255
|
+
if (!loginUrl) {
|
|
256
|
+
loginUrl = new URL("/local-cli/connect", apiOrigin);
|
|
257
|
+
loginUrl.searchParams.set("port", String(port));
|
|
258
|
+
loginUrl.searchParams.set("nonce", authNonce);
|
|
259
|
+
loginUrl.searchParams.set("cli_version", CLI_VERSION);
|
|
260
|
+
loginUrl.searchParams.set("api_contract_version", String(CLI_API_CONTRACT_VERSION));
|
|
261
|
+
if (installMode) loginUrl.searchParams.set("install_mode", installMode);
|
|
262
|
+
}
|
|
263
|
+
return loginUrl.toString();
|
|
264
|
+
};
|
|
240
265
|
|
|
241
266
|
const restoreRemoteRuns = async () => {
|
|
242
267
|
if (!isSessionValid(session, Date.now(), apiOrigin) || !session?.device_id) return;
|
|
@@ -268,6 +293,8 @@ export async function startAgent({
|
|
|
268
293
|
const heartbeat = () => {
|
|
269
294
|
if (!isSessionValid(session, Date.now(), apiOrigin)) return Promise.resolve(false);
|
|
270
295
|
if (heartbeatInFlight) return heartbeatInFlight;
|
|
296
|
+
connectionStatus.attempt();
|
|
297
|
+
let deviceHeartbeatSucceeded = false;
|
|
271
298
|
heartbeatInFlight = Promise.resolve()
|
|
272
299
|
.then(() =>
|
|
273
300
|
heartbeatDevice({
|
|
@@ -280,12 +307,26 @@ export async function startAgent({
|
|
|
280
307
|
}),
|
|
281
308
|
)
|
|
282
309
|
.then(async () => {
|
|
310
|
+
deviceHeartbeatSucceeded = true;
|
|
311
|
+
connectionStatus.success();
|
|
283
312
|
const sqmResult = sqmLocalReviewWorker
|
|
284
313
|
? await sqmLocalReviewWorker.poll()
|
|
285
314
|
: null;
|
|
286
315
|
if (!sqmResult && durableLocalTaskWorker) await durableLocalTaskWorker.poll();
|
|
287
316
|
return true;
|
|
288
317
|
})
|
|
318
|
+
.catch((error) => {
|
|
319
|
+
if (!deviceHeartbeatSucceeded) {
|
|
320
|
+
const state = connectionStatus.failure(error);
|
|
321
|
+
if (state === "unauthorized") {
|
|
322
|
+
session = null;
|
|
323
|
+
loginUrl = null;
|
|
324
|
+
refreshAvailableCapabilities();
|
|
325
|
+
requestDesktopLogin();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
throw error;
|
|
329
|
+
})
|
|
289
330
|
.finally(() => {
|
|
290
331
|
heartbeatInFlight = null;
|
|
291
332
|
});
|
|
@@ -498,7 +539,7 @@ export async function startAgent({
|
|
|
498
539
|
const body = await readJson(req);
|
|
499
540
|
if (body.confirmed !== true) {
|
|
500
541
|
json(res, 400, {
|
|
501
|
-
error: "Explicit confirmation is required before installing the SIMY plugin
|
|
542
|
+
error: "Explicit confirmation is required before installing the SIMY plugin and opt-in agent skills.",
|
|
502
543
|
});
|
|
503
544
|
return;
|
|
504
545
|
}
|
|
@@ -1530,14 +1571,8 @@ export async function startAgent({
|
|
|
1530
1571
|
console.log(`SIMY Web host: ${apiOrigin}`);
|
|
1531
1572
|
}
|
|
1532
1573
|
|
|
1533
|
-
let loginUrl = null;
|
|
1534
1574
|
if (!isSessionValid(session, Date.now(), apiOrigin)) {
|
|
1535
|
-
|
|
1536
|
-
loginUrl.searchParams.set("port", String(port));
|
|
1537
|
-
loginUrl.searchParams.set("nonce", authNonce);
|
|
1538
|
-
loginUrl.searchParams.set("cli_version", CLI_VERSION);
|
|
1539
|
-
loginUrl.searchParams.set("api_contract_version", String(CLI_API_CONTRACT_VERSION));
|
|
1540
|
-
if (installMode) loginUrl.searchParams.set("install_mode", installMode);
|
|
1575
|
+
requestDesktopLogin();
|
|
1541
1576
|
if (!quiet) {
|
|
1542
1577
|
console.log(`Sign in to SIMY: ${loginUrl.toString()}`);
|
|
1543
1578
|
console.log(`Session file: ${sessionPath(apiOrigin, sessionRoot)}`);
|
|
@@ -1571,6 +1606,21 @@ export async function startAgent({
|
|
|
1571
1606
|
server.on("close", () => {
|
|
1572
1607
|
void shutdown().catch((error) => reportDurableLocalTaskError(error, quiet));
|
|
1573
1608
|
});
|
|
1609
|
+
const getDesktopStatus = async () => {
|
|
1610
|
+
const auth = desktopAuthStatus(session, { webOrigin: apiOrigin });
|
|
1611
|
+
return {
|
|
1612
|
+
schemaVersion: 1,
|
|
1613
|
+
sampledAt: new Date().toISOString(),
|
|
1614
|
+
version: CLI_VERSION,
|
|
1615
|
+
webOrigin: apiOrigin,
|
|
1616
|
+
auth,
|
|
1617
|
+
connection: connectionStatus.snapshot({ authenticated: auth.state === "signed_in" }),
|
|
1618
|
+
tasks: desktopTaskStatus([registry, directRegistry, localTaskRegistry]),
|
|
1619
|
+
update: updateManager?.snapshot?.() ?? null,
|
|
1620
|
+
codex: await codexStatus(),
|
|
1621
|
+
loginUrl: auth.state === "signed_in" ? null : requestDesktopLogin(),
|
|
1622
|
+
};
|
|
1623
|
+
};
|
|
1574
1624
|
return {
|
|
1575
1625
|
server,
|
|
1576
1626
|
port,
|
|
@@ -1582,8 +1632,17 @@ export async function startAgent({
|
|
|
1582
1632
|
shutdown,
|
|
1583
1633
|
webOrigin: apiOrigin,
|
|
1584
1634
|
get loginUrl() {
|
|
1585
|
-
return
|
|
1635
|
+
return requestDesktopLogin();
|
|
1636
|
+
},
|
|
1637
|
+
requestDesktopLogin,
|
|
1638
|
+
getDesktopStatus,
|
|
1639
|
+
async refreshDesktopStatus() {
|
|
1640
|
+
if (isSessionValid(session, Date.now(), apiOrigin)) {
|
|
1641
|
+
await heartbeat().catch((error) => reportHeartbeatError(error, quiet));
|
|
1642
|
+
}
|
|
1643
|
+
return getDesktopStatus();
|
|
1586
1644
|
},
|
|
1645
|
+
refreshCodexStatus: () => codexStatus({ force: true }),
|
|
1587
1646
|
workspace,
|
|
1588
1647
|
repositoryScanRoot,
|
|
1589
1648
|
get capabilities() {
|
|
@@ -1778,7 +1837,9 @@ export async function heartbeatLocalDevice({
|
|
|
1778
1837
|
);
|
|
1779
1838
|
if (!response.ok) {
|
|
1780
1839
|
const payload = await response.json().catch(() => null);
|
|
1781
|
-
|
|
1840
|
+
const error = new Error(webApiErrorMessage(payload, response.status));
|
|
1841
|
+
error.status = response.status;
|
|
1842
|
+
throw error;
|
|
1782
1843
|
}
|
|
1783
1844
|
}
|
|
1784
1845
|
|