@worca/app 1.0.0 → 1.2.0-rc.1
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 +30 -9
- package/agents/clarify.meta.json +4 -4
- package/agents/decomposer.meta.json +5 -5
- package/agents/implementer.meta.json +15 -5
- package/agents/manualTestsChecklist.meta.json +5 -4
- package/agents/manualWebUiTesting.meta.json +9 -4
- package/agents/planReviewer.meta.json +12 -4
- package/agents/planner.meta.json +12 -5
- package/agents/refiner.meta.json +15 -4
- package/agents/reviewer.meta.json +14 -4
- package/agents/worca-cc-clarify.md +7 -0
- package/agents/worca-cc-code-reviewer.md +11 -6
- package/agents/worca-cc-decomposer.md +7 -0
- package/agents/worca-cc-implementer.md +9 -0
- package/agents/worca-cc-manual-tests-checklist.md +8 -5
- package/agents/worca-cc-manual-web-ui-testing.md +10 -6
- package/agents/worca-cc-plan-refiner.md +11 -6
- package/agents/worca-cc-plan-reviewer.md +10 -7
- package/agents/worca-cc-planner.md +9 -0
- package/agents/worca-cc-workspace-reviewer.md +11 -4
- package/agents/worca-cc-workspace-scanner.md +8 -4
- package/agents/workspaceReviewer.meta.json +15 -4
- package/agents/workspaceScanner.meta.json +5 -4
- package/package.json +8 -2
- package/skills/worca/SKILL.md +5 -5
- package/src/cli/render.mjs +148 -0
- package/src/cli/worca-cc.mjs +386 -56
- package/src/core/agent-gen.mjs +69 -31
- package/src/core/agent-registry.mjs +124 -144
- package/src/core/agent-store.mjs +164 -4
- package/src/core/artifacts.mjs +199 -23
- package/src/core/ask/attachment-kind.mjs +95 -0
- package/src/core/ask/catalog.mjs +111 -0
- package/src/core/ask/comment-deps.mjs +55 -0
- package/src/core/ask/events.mjs +545 -0
- package/src/core/ask/follow.mjs +113 -0
- package/src/core/ask/git-allowlist.mjs +226 -0
- package/src/core/ask/limits.mjs +57 -0
- package/src/core/ask/mcp-stdio.mjs +135 -0
- package/src/core/ask/models.mjs +125 -0
- package/src/core/ask/prompt.mjs +286 -0
- package/src/core/ask/proposal.mjs +170 -0
- package/src/core/ask/redact.mjs +30 -0
- package/src/core/ask/spawn.mjs +156 -0
- package/src/core/ask/store.mjs +438 -0
- package/src/core/ask/tool-deps.mjs +87 -0
- package/src/core/ask/tools.mjs +879 -0
- package/src/core/ask/turn.mjs +462 -0
- package/src/core/ask/worktree-deps.mjs +27 -0
- package/src/core/ask/worktrees.mjs +285 -0
- package/src/core/chat/command-router.mjs +28 -7
- package/src/core/chat/notifier.mjs +6 -1
- package/src/core/chat/renderers.mjs +15 -8
- package/src/core/claude-runner.mjs +541 -62
- package/src/core/config.mjs +310 -44
- package/src/core/cost-budget.mjs +29 -2
- package/src/core/db.mjs +773 -53
- package/src/core/diff-anchor.mjs +213 -0
- package/src/core/diff-comments.mjs +273 -0
- package/src/core/engine-select.mjs +32 -0
- package/src/core/failure-policy.mjs +201 -0
- package/src/core/git-info.mjs +49 -10
- package/src/core/graph/builtin-workflows.mjs +51 -0
- package/src/core/graph/executor.mjs +894 -0
- package/src/core/graph/registry-ports.mjs +12 -0
- package/src/core/graph/scheduler.mjs +1072 -0
- package/src/core/graph/seed-templates.mjs +318 -0
- package/src/core/host-guard.mjs +271 -0
- package/src/core/model-env.mjs +180 -8
- package/src/core/model-test.mjs +79 -0
- package/src/core/orchestrator.mjs +994 -4097
- package/src/core/overview-agent.mjs +15 -3
- package/src/core/phases.mjs +208 -537
- package/src/core/pipeline-delete.mjs +13 -2
- package/src/core/plugin-api.mjs +8 -3
- package/src/core/plugin-config.mjs +178 -28
- package/src/core/plugin-inventory.mjs +6 -2
- package/src/core/plugin-manifest.mjs +199 -11
- package/src/core/plugin-models.mjs +1 -0
- package/src/core/plugin-repo.mjs +16 -4
- package/src/core/plugin-shim-child.mjs +9 -3
- package/src/core/plugin-shim.mjs +80 -17
- package/src/core/plugin-store.mjs +236 -29
- package/src/core/plugin-workflows.mjs +90 -41
- package/src/core/preflight.mjs +135 -3
- package/src/core/projects.mjs +7 -5
- package/src/core/protocol.mjs +8 -35
- package/src/core/recoverable-error.mjs +1 -1
- package/src/core/run-harness.mjs +3934 -0
- package/src/core/run-manifest.mjs +5 -1
- package/src/core/settings.mjs +184 -13
- package/src/core/skills.mjs +10 -3
- package/src/core/source-bindings.mjs +175 -0
- package/src/core/sources.mjs +87 -25
- package/src/core/stats.mjs +25 -6
- package/src/core/title.mjs +51 -4
- package/src/core/workflows.mjs +358 -259
- package/src/core/workspace-scan.mjs +4 -0
- package/src/core/worktree.mjs +98 -7
- package/src/shared/graph/agent-meta.mjs +278 -0
- package/src/shared/graph/constants.mjs +105 -0
- package/src/shared/graph/geometry.mjs +157 -0
- package/src/shared/graph/layout.mjs +134 -0
- package/src/shared/graph/loops.mjs +130 -0
- package/src/shared/graph/manifest.mjs +257 -0
- package/src/shared/graph/ports.mjs +153 -0
- package/src/shared/graph/route.mjs +397 -0
- package/src/shared/graph/template.mjs +165 -0
- package/src/shared/graph/thumbnail.mjs +67 -0
- package/src/shared/graph/validate.mjs +491 -0
- package/src/shared/graph/verdict.mjs +41 -0
- package/ui/public/app.js +4240 -1682
- package/ui/public/ask-markdown.mjs +145 -0
- package/ui/public/ask-model.mjs +317 -0
- package/ui/public/ask-panel.mjs +2129 -0
- package/ui/public/chat-settings-view.mjs +6 -2
- package/ui/public/diff-view.mjs +66 -11
- package/ui/public/file-tree.mjs +305 -0
- package/ui/public/graph/composer.mjs +889 -0
- package/ui/public/graph/inspector.mjs +183 -0
- package/ui/public/graph/model.mjs +37 -0
- package/ui/public/graph/palette.mjs +144 -0
- package/ui/public/graph/run-decor.mjs +410 -0
- package/ui/public/graph/run-hosts.mjs +201 -0
- package/ui/public/graph/save-dialog.mjs +56 -0
- package/ui/public/graph/view.mjs +858 -0
- package/ui/public/guardrails-view.mjs +4 -2
- package/ui/public/hljs-loader.mjs +180 -0
- package/ui/public/index.html +311 -265
- package/ui/public/log-filter.mjs +22 -4
- package/ui/public/log-line.mjs +45 -19
- package/ui/public/models-view.mjs +171 -9
- package/ui/public/plugins-view.mjs +106 -4
- package/ui/public/source-pane.mjs +190 -8
- package/ui/public/stats-view.mjs +81 -1
- package/ui/public/style.css +1487 -229
- package/ui/public/syntax-highlight.mjs +270 -0
- package/ui/public/thinking-orb.mjs +110 -0
- package/ui/server.mjs +1894 -104
- package/src/core/channels.mjs +0 -302
- package/src/core/runners.mjs +0 -167
- package/src/core/workflow-validator.mjs +0 -185
- package/ui/public/composer-core.mjs +0 -211
package/src/core/preflight.mjs
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
import { spawn } from 'node:child_process';
|
|
13
13
|
import { access } from 'node:fs/promises';
|
|
14
|
-
import { join } from 'node:path';
|
|
14
|
+
import { join, dirname } from 'node:path';
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
|
-
import { constants as FS } from 'node:fs';
|
|
16
|
+
import { constants as FS, existsSync, statSync, openSync, readSync, closeSync } from 'node:fs';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Run a command and resolve to its trimmed stdout, or null on any failure.
|
|
@@ -332,8 +332,140 @@ export async function detectToolsPerProject(projectDirs) {
|
|
|
332
332
|
* @param {string} [bin] the claude binary (defaults to `claude`)
|
|
333
333
|
* @returns {Promise<{mcpConfig: boolean, version: string|null}>}
|
|
334
334
|
*/
|
|
335
|
+
// ── Windows: the executable behind a bare `claude` ────────────────────────────
|
|
336
|
+
// Native Windows resolves a bare name on PATH to `.exe` only, and Node refuses
|
|
337
|
+
// to run .cmd/.bat shims without a shell (CVE-2024-27980). The npm install of
|
|
338
|
+
// Claude Code (>= 2.1 — every version Worca supports) puts a `claude.cmd` shim
|
|
339
|
+
// on PATH whose target is a REAL native binary at npm's fixed layout:
|
|
340
|
+
// <shim dir>\node_modules\@anthropic-ai\claude-code\bin\claude.exe
|
|
341
|
+
// (the package's postinstall copies the platform binary over a ~500-byte text
|
|
342
|
+
// placeholder there). resolveClaudeBin() spawns that .exe directly — no shell,
|
|
343
|
+
// correct kill target, no quoting surface — and explainUnspawnableClaude()
|
|
344
|
+
// covers the cases where that is not possible.
|
|
345
|
+
|
|
346
|
+
export const NPM_CLAUDE_EXE_SEGMENTS = Object.freeze(['node_modules', '@anthropic-ai', 'claude-code', 'bin', 'claude.exe']);
|
|
347
|
+
|
|
348
|
+
/** A real PE executable (MZ header, bigger than npm's placeholder stub). */
|
|
349
|
+
export function isNativeExe(p) {
|
|
350
|
+
try {
|
|
351
|
+
const st = statSync(p);
|
|
352
|
+
if (!st.isFile() || st.size < 4096) return false;
|
|
353
|
+
const fd = openSync(p, 'r');
|
|
354
|
+
try {
|
|
355
|
+
const head = Buffer.alloc(2);
|
|
356
|
+
readSync(fd, head, 0, 2, 0);
|
|
357
|
+
return head.toString('latin1') === 'MZ';
|
|
358
|
+
} finally { closeSync(fd); }
|
|
359
|
+
} catch { return false; }
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const _ov = { isNativeExe: null };
|
|
363
|
+
const _resolveCache = new Map();
|
|
364
|
+
/** Test seam (mirrors folder-dialog.mjs): swap the PE check so an end-to-end
|
|
365
|
+
* test on a POSIX host can stand in a shell script for claude.exe. */
|
|
366
|
+
export const _testing = {
|
|
367
|
+
set({ isNativeExe: native = _ov.isNativeExe } = {}) { _ov.isNativeExe = native; _resolveCache.clear(); },
|
|
368
|
+
reset() { _ov.isNativeExe = null; _resolveCache.clear(); },
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
/** What `bin` reaches on a Windows PATH: a real .exe (spawn works as-is), the
|
|
372
|
+
* shims found, and — next to the FIRST shim — the npm package's native binary
|
|
373
|
+
* when present, with whether it is real or still the placeholder. */
|
|
374
|
+
function probeWindowsClaude(bin, { pathEnv, exists, native }) {
|
|
375
|
+
const name = String(bin || 'claude').trim() || 'claude';
|
|
376
|
+
const ok = (p) => { try { return !!exists(p); } catch { return false; } }; // a probe error is "absent"
|
|
377
|
+
const out = { name, exe: null, shims: [], npm: null };
|
|
378
|
+
if (/\.exe$/i.test(name)) { out.exe = name; return out; } // explicit .exe: nothing to resolve
|
|
379
|
+
const explicitPath = /[\\/]/.test(name);
|
|
380
|
+
const shimExt = /\.(cmd|bat|ps1)$/i.test(name);
|
|
381
|
+
const stems = explicitPath ? [name] : pathEnv.split(';').filter(Boolean).map((d) => join(d, name));
|
|
382
|
+
for (const stem of stems) {
|
|
383
|
+
if (!shimExt && ok(stem + '.exe')) { out.exe = stem + '.exe'; return out; }
|
|
384
|
+
for (const ext of shimExt ? [''] : ['.cmd', '.bat', '.ps1']) {
|
|
385
|
+
const shim = stem + ext;
|
|
386
|
+
if (!ok(shim)) continue;
|
|
387
|
+
out.shims.push(shim);
|
|
388
|
+
if (!out.npm) {
|
|
389
|
+
const candidate = join(dirname(shim), ...NPM_CLAUDE_EXE_SEGMENTS);
|
|
390
|
+
if (ok(candidate)) out.npm = { exe: candidate, native: !!native(candidate) };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return out;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* The executable to spawn for `bin` on THIS host. Off Windows, and whenever a
|
|
399
|
+
* real .exe is reachable, that is `bin` unchanged (spawn's own PATH lookup is
|
|
400
|
+
* correct). When the only PATH hit is npm's .cmd shim and the package's native
|
|
401
|
+
* claude.exe sits next to it, that .exe is returned instead — with a one-line
|
|
402
|
+
* `note` for the log. Otherwise `bin` unchanged again, and the spawn's ENOENT
|
|
403
|
+
* is what explainUnspawnableClaude() turns into an actionable message.
|
|
404
|
+
*
|
|
405
|
+
* Pure with injected platform/pathEnv/exists/isNativeExe; the default
|
|
406
|
+
* (uninjected) resolution is memoised per bin+PATH — PATH does not change under
|
|
407
|
+
* a running process, and the probe is a handful of stat()s per spawn otherwise.
|
|
408
|
+
* @param {string} [bin]
|
|
409
|
+
* @param {{platform?:string, pathEnv?:string, exists?:(p:string)=>boolean, isNativeExe?:(p:string)=>boolean}} [opts]
|
|
410
|
+
* @returns {{bin:string, source:'as-is'|'exe'|'npm', note:string|null}}
|
|
411
|
+
*/
|
|
412
|
+
export function resolveClaudeBin(bin = 'claude', opts = {}) {
|
|
413
|
+
const platform = opts.platform ?? process.platform;
|
|
414
|
+
if (platform !== 'win32') return { bin, source: 'as-is', note: null };
|
|
415
|
+
const pathEnv = opts.pathEnv ?? (process.env.PATH ?? '');
|
|
416
|
+
const injected = Object.keys(opts).length > 0;
|
|
417
|
+
const key = `${bin}\0${pathEnv}`;
|
|
418
|
+
if (!injected && _resolveCache.has(key)) return _resolveCache.get(key);
|
|
419
|
+
const p = probeWindowsClaude(bin, {
|
|
420
|
+
pathEnv, exists: opts.exists ?? existsSync, native: opts.isNativeExe ?? _ov.isNativeExe ?? isNativeExe,
|
|
421
|
+
});
|
|
422
|
+
let out;
|
|
423
|
+
if (p.exe) out = { bin, source: 'exe', note: null };
|
|
424
|
+
else if (p.npm && p.npm.native) {
|
|
425
|
+
out = { bin: p.npm.exe, source: 'npm', note:
|
|
426
|
+
`using the npm-installed Claude Code binary ${p.npm.exe} ("${p.name}" on PATH is npm's .cmd shim, which Node cannot spawn directly)` };
|
|
427
|
+
} else out = { bin, source: 'as-is', note: null };
|
|
428
|
+
if (!injected) _resolveCache.set(key, out);
|
|
429
|
+
return out;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Why a bare `claude` cannot be spawned on THIS host, or null when the generic
|
|
434
|
+
* error is the whole story (or when resolveClaudeBin() would have handled it).
|
|
435
|
+
* Two Windows cases get an actionable message: the npm shim with the package's
|
|
436
|
+
* binary still being the postinstall placeholder, and a shim with no native
|
|
437
|
+
* binary next to it at all (non-npm layout, or a pre-native package).
|
|
438
|
+
*
|
|
439
|
+
* Pure: platform / PATH / existence / PE check are injectable. Never throws.
|
|
440
|
+
* @param {string} [bin] the configured claude binary (name or path)
|
|
441
|
+
* @param {{platform?:string, pathEnv?:string, exists?:(p:string)=>boolean, isNativeExe?:(p:string)=>boolean}} [o]
|
|
442
|
+
* @returns {string|null}
|
|
443
|
+
*/
|
|
444
|
+
export function explainUnspawnableClaude(bin = 'claude', {
|
|
445
|
+
platform = process.platform,
|
|
446
|
+
pathEnv = process.env.PATH ?? '',
|
|
447
|
+
exists = existsSync,
|
|
448
|
+
isNativeExe: native = _ov.isNativeExe ?? isNativeExe,
|
|
449
|
+
} = {}) {
|
|
450
|
+
if (platform !== 'win32') return null;
|
|
451
|
+
const p = probeWindowsClaude(bin, { pathEnv, exists, native });
|
|
452
|
+
if (p.exe || !p.shims.length) return null; // a real exe, or a plain "not installed"
|
|
453
|
+
if (p.npm && p.npm.native) return null; // resolveClaudeBin() spawns this one — not a failure
|
|
454
|
+
const base = `"${p.name}" resolves to a script shim (${p.shims[0]}) — the npm install of Claude Code. ` +
|
|
455
|
+
'Windows only launches a .exe by name and Node cannot run a .cmd/.bat shim without a shell. ';
|
|
456
|
+
if (p.npm) {
|
|
457
|
+
const installer = join(dirname(dirname(p.npm.exe)), 'install.cjs');
|
|
458
|
+
return base + `Worca would run the package's native binary instead, but ${p.npm.exe} is still npm's ` +
|
|
459
|
+
`placeholder — the package's postinstall did not run (--ignore-scripts / --omit=optional). Run: node ${installer}, ` +
|
|
460
|
+
'or reinstall Claude Code without those flags.';
|
|
461
|
+
}
|
|
462
|
+
return base + `No native binary was found next to it (${join(dirname(p.shims[0]), ...NPM_CLAUDE_EXE_SEGMENTS)}). ` +
|
|
463
|
+
'Install the native Windows build (irm https://claude.ai/install.ps1 | iex), or set WORCA_CLAUDE_BIN to the full path of claude.exe.';
|
|
464
|
+
}
|
|
465
|
+
|
|
335
466
|
export async function probeClaudeCapabilities(bin = 'claude') {
|
|
336
|
-
const
|
|
467
|
+
const name = bin && String(bin).trim() ? String(bin).trim() : 'claude';
|
|
468
|
+
const exe = resolveClaudeBin(name).bin; // same resolution as the runner's spawn (npm shim → native .exe)
|
|
337
469
|
const help = await execSafe(exe, ['--help'], { timeout: 8000 });
|
|
338
470
|
const raw = await execSafe(exe, ['--version'], { timeout: 8000 });
|
|
339
471
|
const version = raw ? (/(\d+\.\d+\.\d+)/.exec(raw)?.[1] ?? raw.split(/\s+/)[0] ?? null) : null;
|
package/src/core/projects.mjs
CHANGED
|
@@ -87,12 +87,14 @@ function readRows() {
|
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* List saved projects, each annotated with a runtime `exists` flag (true when the
|
|
90
|
-
* path is an existing directory). The flag is computed, never persisted.
|
|
91
|
-
*
|
|
92
|
-
*
|
|
90
|
+
* path is an existing directory). The flag is computed, never persisted. `key` is
|
|
91
|
+
* the registry key (store.mjs#projectKey at registration) — the id the Ask Worca
|
|
92
|
+
* catalog and propose_run use, so callers never re-derive it from the path.
|
|
93
|
+
* Reads from the projects table; never throws.
|
|
94
|
+
* @returns {Promise<Array<{key:string, name:string, path:string, exists:boolean}>>}
|
|
93
95
|
*/
|
|
94
96
|
export async function listProjects() {
|
|
95
|
-
return readRows().map((e) => ({ name: e.name, path: e.path, exists: isDir(e.path) }));
|
|
97
|
+
return readRows().map((e) => ({ key: e.key, name: e.name, path: e.path, exists: isDir(e.path) }));
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
/**
|
|
@@ -144,7 +146,7 @@ export async function addProject(input) {
|
|
|
144
146
|
/**
|
|
145
147
|
* Remove a project by name (case-insensitive). Absent name is a no-op.
|
|
146
148
|
* @param {string} name
|
|
147
|
-
* @returns {Promise<Array<{name:string, path:string, exists:boolean}>>}
|
|
149
|
+
* @returns {Promise<Array<{key:string, name:string, path:string, exists:boolean}>>}
|
|
148
150
|
*/
|
|
149
151
|
export async function removeProject(name) {
|
|
150
152
|
const key = (typeof name === 'string' ? name : '').trim();
|
package/src/core/protocol.mjs
CHANGED
|
@@ -8,20 +8,13 @@
|
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/** Normalize an arbitrary value to one of SEVERITIES (default "minor"). */
|
|
20
|
-
function normalizeSeverity(value) {
|
|
21
|
-
if (typeof value !== 'string') return 'minor';
|
|
22
|
-
const v = value.trim().toLowerCase();
|
|
23
|
-
return SEVERITIES.includes(v) ? v : 'minor';
|
|
24
|
-
}
|
|
11
|
+
// The verdict vocabulary lives in the browser-safe shared core (this module
|
|
12
|
+
// imports node:fs/promises and can never be loaded in a browser); re-exported
|
|
13
|
+
// here so every existing importer of protocol.mjs keeps working unchanged.
|
|
14
|
+
export {
|
|
15
|
+
SEVERITIES, BLOCKING, normalizeSeverity, hasBlocking, blockingIssues,
|
|
16
|
+
} from '../shared/graph/verdict.mjs';
|
|
17
|
+
import { normalizeSeverity } from '../shared/graph/verdict.mjs';
|
|
25
18
|
|
|
26
19
|
/** Coerce any value to a trimmed string (empty string for null/undefined). */
|
|
27
20
|
function asString(value) {
|
|
@@ -204,7 +197,7 @@ export async function readQuestionsFile(absPath) {
|
|
|
204
197
|
* { issues: [ { severity, title, detail, location } ], summary }
|
|
205
198
|
* Always returns { issues: [], summary: '' } on bad input.
|
|
206
199
|
*/
|
|
207
|
-
function normalizeReview(data) {
|
|
200
|
+
export function normalizeReview(data) {
|
|
208
201
|
if (!data || typeof data !== 'object') return { issues: [], summary: '' };
|
|
209
202
|
const list = Array.isArray(data.issues) ? data.issues : [];
|
|
210
203
|
const issues = [];
|
|
@@ -235,23 +228,3 @@ export async function readReview(jsonPath) {
|
|
|
235
228
|
}
|
|
236
229
|
return normalizeReview(safeParseJson(text));
|
|
237
230
|
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* True if a review contains any critical or major issue.
|
|
241
|
-
* @param {{issues: Array}} review
|
|
242
|
-
* @returns {boolean}
|
|
243
|
-
*/
|
|
244
|
-
export function hasBlocking(review) {
|
|
245
|
-
if (!review || !Array.isArray(review.issues)) return false;
|
|
246
|
-
return review.issues.some((i) => BLOCKING.has(normalizeSeverity(i?.severity)));
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* The subset of issues that are critical or major.
|
|
251
|
-
* @param {{issues: Array}} review
|
|
252
|
-
* @returns {Array}
|
|
253
|
-
*/
|
|
254
|
-
export function blockingIssues(review) {
|
|
255
|
-
if (!review || !Array.isArray(review.issues)) return [];
|
|
256
|
-
return review.issues.filter((i) => BLOCKING.has(normalizeSeverity(i?.severity)));
|
|
257
|
-
}
|
|
@@ -33,7 +33,7 @@ export function classifyError(err) {
|
|
|
33
33
|
if (/\bsession limit\b|hit your[^.]*\blimit\b|reached your[^.]*\blimit\b|\blimit\b[^.]*\bresets?\b/i.test(msg)) return 'usage_limit';
|
|
34
34
|
if (/\b429\b|\b529\b|rate.?limit|overloaded/i.test(msg)) return 'rate_limit';
|
|
35
35
|
if (/credit balance|usage limit|quota|insufficient_quota|billing/i.test(msg)) return 'quota';
|
|
36
|
-
if (/ECONNRESET|ETIMEDOUT|ENOTFOUND|ECONNREFUSED|EAI_AGAIN|EPIPE|socket hang up|fetch failed|network|connection (refused|reset|closed|error)|closed mid-response|response above may be incomplete/i.test(msg)) return 'network';
|
|
36
|
+
if (/ECONNRESET|ETIMEDOUT|ENOTFOUND|ECONNREFUSED|EAI_AGAIN|EPIPE|socket hang up|fetch failed|network|connection (refused|reset|closed|error)|closed mid-response|response above may be incomplete|\btimed?[ -]?out\b|\btimeout\b|\b500\b|Internal Server Error/i.test(msg)) return 'network';
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
|