@remits/remits-cli 0.1.150 → 0.1.152
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/index.js
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
- L621 Local State, Workspaces, And Verification Evidence
|
|
9
9
|
- L2659 Account Repos, Guide Sync, And Platform Repo
|
|
10
10
|
- L3499 Component Discovery And HTTP Logging
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
11
|
+
- L4267 Skill Delivery And TOC Resolution
|
|
12
|
+
- L4582 Auth And Component Staging
|
|
13
|
+
- L5214 Component Summaries, Status, And Sync Gates
|
|
14
|
+
- L7515 Branches, Promotion, Commit, And Test Runs
|
|
15
|
+
- L9631 Tokens, Tools, Verification, And Config
|
|
16
|
+
- L11058 Service Dashboard And WebSocket Listener
|
|
17
|
+
- L13557 Agent And Ticket Workflows
|
|
18
|
+
- L17692 Help, Auto Update, And Command Dispatch
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/*
|
|
@@ -4142,6 +4142,48 @@ function describeToolsSnapshotWorld(world) {
|
|
|
4142
4142
|
'data ' + (world.dataMode || '?')].filter(Boolean).join(', ');
|
|
4143
4143
|
}
|
|
4144
4144
|
|
|
4145
|
+
// How many times a `WORKLOAD_BUSY` refusal is retried before it is handed to the caller. About 90 seconds
|
|
4146
|
+
// in total: long enough to ride out another agent's stage or sync, short enough that a gate filled by
|
|
4147
|
+
// long-running suites still answers as "busy" rather than as a hang.
|
|
4148
|
+
const WORKLOAD_BUSY_MAX_RETRIES = 6;
|
|
4149
|
+
|
|
4150
|
+
/**
|
|
4151
|
+
* How long to wait before retrying a request the platform refused as `WORKLOAD_BUSY`, or null when the
|
|
4152
|
+
* failure is anything else (or the retries are spent).
|
|
4153
|
+
*
|
|
4154
|
+
* The platform admits only a few heavyweight requests per instance and answers the rest with HTTP 429
|
|
4155
|
+
* BEFORE doing any work, so repeating the identical request is safe — which is not true of any other
|
|
4156
|
+
* failure, and is why this matches on the code rather than on the status alone. The wait starts at the
|
|
4157
|
+
* server's Retry-After and grows, with jitter so several refused agents do not come back in step.
|
|
4158
|
+
*/
|
|
4159
|
+
function workloadBusyRetryDelayMs(err, attempt, maxRetries, random) {
|
|
4160
|
+
const response = err && err.response;
|
|
4161
|
+
const body = response && response.data;
|
|
4162
|
+
if (!response || response.status !== 429 || !body || body.code !== 'WORKLOAD_BUSY') return null;
|
|
4163
|
+
if (attempt >= maxRetries) return null;
|
|
4164
|
+
const headers = response.headers || {};
|
|
4165
|
+
const advised = Number(body.retryAfterSeconds || headers['retry-after']);
|
|
4166
|
+
const baseSeconds = Number.isFinite(advised) && advised > 0 ? Math.min(advised, 60) : 5;
|
|
4167
|
+
const grown = Math.min(baseSeconds * Math.pow(1.5, attempt), 30);
|
|
4168
|
+
return Math.round(grown * 1000 * (0.75 + 0.5 * random()));
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
async function postRidingOutBusy(api, endpoint, payload) {
|
|
4172
|
+
const configured = Number(process.env.REMITS_CLI_BUSY_RETRIES);
|
|
4173
|
+
const maxRetries = Number.isInteger(configured) && configured >= 0 ? configured : WORKLOAD_BUSY_MAX_RETRIES;
|
|
4174
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
4175
|
+
try {
|
|
4176
|
+
return await api.post(endpoint, payload);
|
|
4177
|
+
} catch (err) {
|
|
4178
|
+
const delayMs = workloadBusyRetryDelayMs(err, attempt, maxRetries, Math.random);
|
|
4179
|
+
if (delayMs == null) throw err;
|
|
4180
|
+
console.error('Platform instance is busy with ' + (err.response.data.workload || 'other work') +
|
|
4181
|
+
'; retrying in ' + Math.round(delayMs / 1000) + 's (' + (attempt + 1) + '/' + maxRetries + ').');
|
|
4182
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4145
4187
|
async function loggedPost(api, cwd, endpoint, payload, options = {}) {
|
|
4146
4188
|
const requestId = options.requestId || crypto.randomUUID();
|
|
4147
4189
|
const started = Date.now();
|
|
@@ -4155,7 +4197,7 @@ async function loggedPost(api, cwd, endpoint, payload, options = {}) {
|
|
|
4155
4197
|
}
|
|
4156
4198
|
|
|
4157
4199
|
try {
|
|
4158
|
-
responseData = await api
|
|
4200
|
+
responseData = await postRidingOutBusy(api, endpoint, payload).then((r) => r.data);
|
|
4159
4201
|
if (options.toolResponseFile) {
|
|
4160
4202
|
const callId = options.toolCallId || (responseData && responseData.callId) || requestId;
|
|
4161
4203
|
responseFile = writeToolResponseFile(cwd, callId, responseData);
|
|
@@ -8537,6 +8579,32 @@ function selectPivotCases(tests, limit = 6) {
|
|
|
8537
8579
|
return { shown: representatives.slice(0, limit), failedCount: failed.length, rootCount: representatives.length };
|
|
8538
8580
|
}
|
|
8539
8581
|
|
|
8582
|
+
// What a PASSING case reported: report(...) / diagnostic(...) values and captured println output. Failed
|
|
8583
|
+
// cases print theirs in the pivot block below. Without this, the only way to read a value out of a run
|
|
8584
|
+
// was to end the case in a deliberately failing assertion. Bounded, because this output is an agent's
|
|
8585
|
+
// context: a few cases, a few hundred characters each, and a count for the rest.
|
|
8586
|
+
const PASSING_DIAGNOSTIC_CASES = 6;
|
|
8587
|
+
const PASSING_DIAGNOSTIC_CHARS = 700;
|
|
8588
|
+
function passingCaseDiagnostics(tests) {
|
|
8589
|
+
return (Array.isArray(tests) ? tests : []).filter((test) => {
|
|
8590
|
+
const passed = test && (test.passed === true || test.outcome === 'passed') && !test.error;
|
|
8591
|
+
const diagnostics = test && test.diagnostics && typeof test.diagnostics === 'object' ? test.diagnostics : null;
|
|
8592
|
+
return passed && diagnostics && Object.keys(diagnostics).length > 0;
|
|
8593
|
+
});
|
|
8594
|
+
}
|
|
8595
|
+
function printPassingCaseDiagnostics(tests) {
|
|
8596
|
+
const reporting = passingCaseDiagnostics(tests);
|
|
8597
|
+
if (!reporting.length) return;
|
|
8598
|
+
reporting.slice(0, PASSING_DIAGNOSTIC_CASES).forEach((test) => {
|
|
8599
|
+
const text = JSON.stringify(test.diagnostics);
|
|
8600
|
+
console.log('Reported by passing case:', (test.name || '(unnamed)'));
|
|
8601
|
+
console.log(' Diagnostics:', text.length > PASSING_DIAGNOSTIC_CHARS ? text.slice(0, PASSING_DIAGNOSTIC_CHARS) + '... (' + text.length + ' chars; --json for all)' : text);
|
|
8602
|
+
});
|
|
8603
|
+
if (reporting.length > PASSING_DIAGNOSTIC_CASES) {
|
|
8604
|
+
console.log(' ' + (reporting.length - PASSING_DIAGNOSTIC_CASES) + ' more passing case(s) reported diagnostics; use --json to read them.');
|
|
8605
|
+
}
|
|
8606
|
+
}
|
|
8607
|
+
|
|
8540
8608
|
function printTestRunPivots(status = {}) {
|
|
8541
8609
|
const tests = status.result && Array.isArray(status.result.tests) ? status.result.tests : [];
|
|
8542
8610
|
if (!tests.length) return;
|
|
@@ -8544,6 +8612,7 @@ function printTestRunPivots(status = {}) {
|
|
|
8544
8612
|
if (slowest && slowest.duration != null) {
|
|
8545
8613
|
console.log('Slowest case:', (slowest.name || '(unnamed)') + ' in ' + formatDurationMs(slowest.duration));
|
|
8546
8614
|
}
|
|
8615
|
+
printPassingCaseDiagnostics(tests);
|
|
8547
8616
|
const selection = selectPivotCases(tests);
|
|
8548
8617
|
selection.shown.forEach((test) => {
|
|
8549
8618
|
console.log('Pivots for failed case:', test.name || '(unnamed)');
|
package/package.json
CHANGED
|
@@ -736,9 +736,10 @@ Read `classification` first:
|
|
|
736
736
|
- `ORPHANED_*` / `RECOVERED_*` — the attempt was abandoned; read `abandonmentCause`.
|
|
737
737
|
- `REQUEST_TIMEOUT_LIKELY` — it used its whole deadline (`timing.deadlineUsed` near `1.0`). The unit of
|
|
738
738
|
work is too big for one event; the fix is resumable batches, not component logic.
|
|
739
|
-
- `PROCESS_TERMINATED_LIKELY` —
|
|
740
|
-
|
|
741
|
-
|
|
739
|
+
- `PROCESS_TERMINATED_LIKELY` — its last recorded sign of life came well inside its deadline
|
|
740
|
+
(`timing.deadlineUsed` near `0`). A killed worker (memory pressure, restart) is one explanation; a
|
|
741
|
+
stalled heartbeat or a missed completion write leaves the same evidence. Not a logic bug; check the
|
|
742
|
+
correlated worker logs, then JVM/node health and container lifecycle logs.
|
|
742
743
|
- `UNKNOWN_NO_DEADLINE_EVIDENCE` — no deadline was recorded, so the cause is genuinely unknown. Use the
|
|
743
744
|
returned `logQuery` filters; do not assume. Events predating delivery-envelope capture always look
|
|
744
745
|
like this.
|
|
@@ -996,14 +997,17 @@ every command, so you navigate iteratively.
|
|
|
996
997
|
| `ticketId` / `artifactType` / `artifactLabel` / `artifactNotes` | no | Attach a screenshot/pdf/trace/video to a support ticket |
|
|
997
998
|
|
|
998
999
|
### `mcp_jvm_spike_triage`
|
|
999
|
-
|
|
1000
|
-
optional
|
|
1000
|
+
Single-instance triage bundle for a Cloud Run service showing a latency/memory spike.
|
|
1001
|
+
Summary, optional histogram and stacks come from one request with an explicit process UUID.
|
|
1002
|
+
Requires the bundle-capable platform; deploy it before promoting the updated System Account tool.
|
|
1003
|
+
Preserves container/heap/non-heap memory, classes, buffers, all-thread family totals and HTTP pool counters.
|
|
1004
|
+
Optional logs are service-region scope and can concern other JVMs. No heap dump or JFR.
|
|
1001
1005
|
|
|
1002
1006
|
| Parameter | Required | Description |
|
|
1003
1007
|
|-----------|----------|-------------|
|
|
1004
1008
|
| `serviceName` | yes | e.g. `remits`, `remits-actions` |
|
|
1005
1009
|
| `region` | yes | e.g. `us-east5`, `us-east1` |
|
|
1006
|
-
| `sampleHeap` | no | Default
|
|
1010
|
+
| `sampleHeap` | no | Default false — explicitly request a live-object histogram; it can trigger GC and pause the JVM |
|
|
1007
1011
|
| `top` | no | Top classes to return. Default 20, max 100. |
|
|
1008
1012
|
| `includeThreadDump` / `threadLimit` | no | Fuller thread dump beyond the built-in top-thread preview |
|
|
1009
1013
|
| `includeLogs` / `logLookbackMinutes` / `logLimit` | no | Recent WARNING+ log signals for the same service |
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
| Need to learn command behavior | Read the `remits-cli` skill and its references, repo docs, or CLI source. Do not run unsupported mutating subcommand variants such as `remits-cli components commit --help`; if a command unexpectedly mutates or commits, run `remits-cli doctor local-state` and inspect the active actor's repo-local session log before doing anything else. |
|
|
26
26
|
| Sync response reports unexpected deletes, creates, renames, uniqueness errors, or component ID drift | Stop immediately. Do not rerun sync, do not create replacement components to paper over the mismatch, and do not promote more changes. Preserve session logs/tool responses, compare `account-info.json`, local filenames, live inventory, and git history, then prepare a repair/escalation summary. |
|
|
27
27
|
| 500 / `Internal Server Error` from Remits | Stop normal task work. Capture the exact command, error, and response artifact, then escalate to a Remits system admin. Do not invent a workaround. |
|
|
28
|
+
| `Platform instance is busy with ...; retrying` on stderr, or a final `WORKLOAD_BUSY` (HTTP 429) | The platform runs only a few stage/sync/commit requests and Test suites at once per instance, and refused yours before doing any work. The CLI already retried for about 90 seconds. Nothing is broken and nothing was half-applied by the refused request: wait for the other work and run the same command again. If the refusal came from the last step of `components commit`, read the outcome it printed: a branch that was pushed but not synced needs `remits-cli components sync`, not another commit. |
|
|
28
29
|
| Tool parameters rejected | Tool schemas may be cached. Run `remits-cli tools` to refresh `.remits-cli/shared/tools/tools.json` with latest schemas. |
|
|
29
30
|
| Tool response missing | Run `remits-cli doctor local-state`, then check `./.remits-cli/actors/<local-agent>/tool-responses/` and any legacy flat `./.remits-cli/tool-responses/` fallback it reports. |
|
|
30
31
|
| Long-running tool times out | For `mcp_run_action`/`mcp_run_agent`, use the tool's own `executionMode:"async"` and poll with a `controlAction:"status"` call (see `command-reference.md` → *Tool Execution Lifecycle*). For other long tools without their own async, use `remits-cli tool --async true` and poll `remits-cli tool status --call-id <callId>`. `--timeout-ms` only adjusts the per-request HTTP timeout; it is not a substitute for async. |
|