@amistio/cli 0.1.37 → 0.1.38
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 +4 -2
- package/dist/index.js +53 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@ npm install -g @amistio/cli
|
|
|
9
9
|
amistio --help
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
The package install provides the `amistio` command and the optional `amistio-host-helper` executable. Repository cloning, project pairing, credential storage, sync watching, helper activation, and runner execution happen only when the user explicitly runs commands such as `amistio bootstrap`, `amistio import`, `amistio pair`, `amistio sync watch`, `amistio host-helper status`, or `amistio run --watch`. When the app copies a personal project into an organization, the CLI command syntax stays the same; create the org-scoped code and run `amistio import <code>` from the intended local checkout. Import scans repo-local project-brain docs plus recognized repo-local IDE
|
|
12
|
+
The package install provides the `amistio` command and the optional `amistio-host-helper` executable. Repository cloning, project pairing, credential storage, sync watching, helper activation, and runner execution happen only when the user explicitly runs commands such as `amistio bootstrap`, `amistio import`, `amistio pair`, `amistio sync watch`, `amistio host-helper status`, or `amistio run --watch`. When the app copies a personal project into an organization, the CLI command syntax stays the same; create the org-scoped code and run `amistio import <code>` from the intended local checkout. Import scans repo-local project-brain docs plus recognized repo-local IDE and local AI tool memory or instruction files such as `AGENTS.md`, `.github/copilot-instructions.md`, `.cursor/rules/*.mdc`, `.windsurfrules`, and `memories/*.md`; durable Amistio memory belongs in `docs/memory/`, and global plugin memory outside the repository is not scanned by default.
|
|
13
13
|
|
|
14
|
-
For enterprise setup, use the web Runner panel as the primary guide. It shows repository, pairing code, AI provider, local runner, and
|
|
14
|
+
For enterprise setup, use the web Runner panel as the primary guide. It shows repository, pairing code, GitHub access, AI provider, local runner, and verification readiness with plain next actions; advanced CLI logs remain secondary diagnostics. The panel also shows trust/privacy boundaries, cost forecast and budget posture, runner health, blockers, verification health, and runner-version distribution from safe runner metadata.
|
|
15
15
|
|
|
16
16
|
Optional host helpers are configured outside the SaaS with `AMISTIO_HOST_HELPER_PATH`. The official npm package ships `amistio-host-helper` for Level 1 supervised process execution diagnostics; enable it with `AMISTIO_HOST_HELPER_PATH=$(command -v amistio-host-helper)` on reviewed runner machines and confirm `amistio host-helper status` plus `amistio host-helper conformance`. PTY and sandbox requests use a helper only when its versioned handshake advertises support; otherwise the CLI returns deterministic unsupported results instead of silently downgrading. The npm helper does not advertise PTY or sandbox support. Helper request envelopes include allowlisted environment values, explicit sandbox policy metadata, and bounded normalized output, and must never include provider tokens, OAuth material, runner API tokens, local auth files, or arbitrary SaaS-originated shell text.
|
|
17
17
|
|
|
@@ -83,6 +83,8 @@ Watch mode prints a completed-work success once per work item, keeps fresh compl
|
|
|
83
83
|
|
|
84
84
|
Known validation failures such as `unsafe_context_path` are printed with attention-needed next steps. For project-context refresh path-safety failures, deploy the latest web/API fix, update and restart the runner when applicable, retry the refresh, and capture only bounded non-secret output if it repeats.
|
|
85
85
|
|
|
86
|
+
If watch mode reports that the runner was forgotten by the server, stop the foreground process and start or pair a new runner from the Runner panel. Forgotten runner IDs are intentionally blocked from heartbeats and work claims, so the CLI exits instead of retrying with the tombstoned identity.
|
|
87
|
+
|
|
86
88
|
App-evaluation result finalization rejections print safe validation paths and preserve the local finalization evidence without exposing raw source or secrets. If a structured app-evaluation result is rejected, update and restart the runner, confirm the web/API deployment is current, and retry the evaluation before acting on cleanup or implementation recommendations.
|
|
87
89
|
|
|
88
90
|
When brain generation or plan revision output is parsed but the Amistio API is temporarily unavailable during finalization, the runner keeps a safe pending result envelope in user-level Amistio config and replays it before claiming more work. The envelope uses a stable idempotency key and does not store raw tool stdout, provider sessions, credentials, or arbitrary local paths.
|
package/dist/index.js
CHANGED
|
@@ -2730,6 +2730,9 @@ var AmistioApiError = class extends Error {
|
|
|
2730
2730
|
statusText;
|
|
2731
2731
|
detail;
|
|
2732
2732
|
};
|
|
2733
|
+
function isForgottenRunnerApiError(error) {
|
|
2734
|
+
return error instanceof AmistioApiError && error.status === 403 && error.detail.includes("This runner was forgotten");
|
|
2735
|
+
}
|
|
2733
2736
|
function isRetryableApiError(error) {
|
|
2734
2737
|
if (error instanceof AmistioApiError) {
|
|
2735
2738
|
return error.status === 408 || error.status === 429 || error.status >= 500;
|
|
@@ -5491,6 +5494,41 @@ async function readRunnerDaemonMetadataFile(filePath) {
|
|
|
5491
5494
|
}
|
|
5492
5495
|
}
|
|
5493
5496
|
|
|
5497
|
+
// src/runner-watch-errors.ts
|
|
5498
|
+
var forgottenRunnerWatchMessage = "This runner was forgotten by the server. Start or pair a new runner from the Runner panel; this runner ID cannot heartbeat or claim work anymore.";
|
|
5499
|
+
async function handleRunnerWatchError(options) {
|
|
5500
|
+
const consoleError = options.consoleError ?? console.error;
|
|
5501
|
+
if (isForgottenRunnerApiError(options.error)) {
|
|
5502
|
+
if (options.verbose && options.detail) {
|
|
5503
|
+
consoleError(`${forgottenRunnerWatchMessage}
|
|
5504
|
+
${options.detail}`);
|
|
5505
|
+
} else {
|
|
5506
|
+
consoleError(forgottenRunnerWatchMessage);
|
|
5507
|
+
}
|
|
5508
|
+
return { status: "failed", exitCode: 1, message: forgottenRunnerWatchMessage, stopRunner: true };
|
|
5509
|
+
}
|
|
5510
|
+
const message = "Runner hit an error while watching and will keep listening.";
|
|
5511
|
+
if (options.verbose) {
|
|
5512
|
+
consoleError(`${message}
|
|
5513
|
+
${options.detail}`);
|
|
5514
|
+
} else {
|
|
5515
|
+
consoleError(`${message} Run with --verbose for details.`);
|
|
5516
|
+
}
|
|
5517
|
+
const settlements = await Promise.allSettled([
|
|
5518
|
+
options.client.sendRunnerHeartbeat(options.projectId, options.runnerId, options.repositoryLinkId, "blocked", { ...options.heartbeatMetadata, preferenceMessage: message }),
|
|
5519
|
+
options.client.recordRunnerLog(options.projectId, {
|
|
5520
|
+
runnerId: options.runnerId,
|
|
5521
|
+
repositoryLinkId: options.repositoryLinkId,
|
|
5522
|
+
status: "failed",
|
|
5523
|
+
message,
|
|
5524
|
+
error: options.detail,
|
|
5525
|
+
machineId: options.machineId
|
|
5526
|
+
})
|
|
5527
|
+
]);
|
|
5528
|
+
options.logRejectedSettlements("record watch error", settlements);
|
|
5529
|
+
return { status: "failed", exitCode: 1, message };
|
|
5530
|
+
}
|
|
5531
|
+
|
|
5494
5532
|
// src/runner-service.ts
|
|
5495
5533
|
import { spawn as spawn3 } from "node:child_process";
|
|
5496
5534
|
import { createHash as createHash4 } from "node:crypto";
|
|
@@ -10225,6 +10263,9 @@ program.command("run").description("Claim and run approved Amistio work locally"
|
|
|
10225
10263
|
}
|
|
10226
10264
|
}
|
|
10227
10265
|
if (result.stopRunner) {
|
|
10266
|
+
if (result.exitCode !== 0) {
|
|
10267
|
+
process.exitCode = result.exitCode;
|
|
10268
|
+
}
|
|
10228
10269
|
return;
|
|
10229
10270
|
}
|
|
10230
10271
|
if (options.maxIterations !== void 0 && iterations >= options.maxIterations) {
|
|
@@ -10491,26 +10532,18 @@ async function runWatchIteration({ command, context, options, runnerId }) {
|
|
|
10491
10532
|
throw error;
|
|
10492
10533
|
}
|
|
10493
10534
|
const detail = truncateLogExcerpt(errorDetail(error));
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
status: "failed",
|
|
10507
|
-
message,
|
|
10508
|
-
error: detail,
|
|
10509
|
-
machineId: runnerMachineId()
|
|
10510
|
-
})
|
|
10511
|
-
]);
|
|
10512
|
-
logRejectedSettlements("record watch error", settlements);
|
|
10513
|
-
return { status: "failed", exitCode: 1, message };
|
|
10535
|
+
return await handleRunnerWatchError({
|
|
10536
|
+
client: context.client,
|
|
10537
|
+
detail,
|
|
10538
|
+
error,
|
|
10539
|
+
heartbeatMetadata: runnerHeartbeatMetadata(),
|
|
10540
|
+
logRejectedSettlements,
|
|
10541
|
+
machineId: runnerMachineId(),
|
|
10542
|
+
projectId: context.metadata.amistioProjectId,
|
|
10543
|
+
repositoryLinkId: context.metadata.repositoryLinkId,
|
|
10544
|
+
runnerId,
|
|
10545
|
+
...options.verbose !== void 0 ? { verbose: options.verbose } : {}
|
|
10546
|
+
});
|
|
10514
10547
|
}
|
|
10515
10548
|
}
|
|
10516
10549
|
function claimLaneIds(maxConcurrentWork) {
|