amsd-pipeline-shared 0.5.25 → 0.5.27
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.
|
@@ -23,12 +23,20 @@ function signaturesFor(runtime, injected) {
|
|
|
23
23
|
internalFrame: rxOf(s.internalFrame), dependencyDir: s.dependencyDir };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function classify({ profile, portRoot, res, crash, aborted, since, signatures, evidence }) {
|
|
26
|
+
function classify({ profile, portRoot, res, crash, aborted, since, signatures, evidence, runDir }) {
|
|
27
27
|
const sig = signaturesFor(profile.classify.runtime, signatures);
|
|
28
28
|
const takesMost = profile.classify.policy === 'all-but-refusals';
|
|
29
29
|
// WHAT IS EXTERNAL: the machine, the network, the model service, a kill. Under "all-but-refusals" a kill that happened inside the pipeline's OWN memory budget (the bounded wrapper's start banner is in the text:
|
|
30
30
|
// the cap the pipeline chose, so what ran inside it is the pipeline's to bound — run 11, jest workers inside a Writer session's cap) is not external
|
|
31
|
-
|
|
31
|
+
// An access error on the leg's OWN run folder is the code's too (live run 13, 2026-10-22: the driver copied a locked set into the run's
|
|
32
|
+
// project copy and could not clear it — "EACCES … rmdir '<run>/project/…'"): every path the message quotes is inside runDir
|
|
33
|
+
const ownRunPaths = (text) => {
|
|
34
|
+
if (!takesMost || !runDir || !/\bE(ACCES|PERM)\b/.test(text)) return false;
|
|
35
|
+
const paths = [...String(text).matchAll(/'(\/[^']+)'/g)].map((m) => path.resolve(m[1]));
|
|
36
|
+
const root = path.resolve(runDir);
|
|
37
|
+
return paths.length > 0 && paths.every((p) => p === root || p.startsWith(`${root}${path.sep}`));
|
|
38
|
+
};
|
|
39
|
+
const isExternal = (text) => sig.external.test(text) && !(takesMost && sig.ownBudget.test(text)) && !ownRunPaths(text);
|
|
32
40
|
if (!res || typeof res !== 'object') return no('no-result', 'the leg gave no result');
|
|
33
41
|
if (aborted) return no('aborted', 'the operator or a watcher ended the leg');
|
|
34
42
|
// AN AGENT-CAUSED ABORT (operator, 2026-10-20: look for the agentic solution first): a failed leg whose reason is one of the pipeline's own agent-caused
|
|
@@ -33,7 +33,7 @@ async function handle(a) {
|
|
|
33
33
|
// the logs are cumulative across legs: the decision reads only what follows the last leg-start line in each file (the whole tail when the profile names none or the tail holds none)
|
|
34
34
|
const thisLeg = (text) => { if (!profile.logs.legStart) return text; const ls = text.split('\n'); let at = -1; ls.forEach((l, i) => { if (profile.logs.legStart.test(l)) at = i; }); return at < 0 ? text : ls.slice(at).join('\n'); };
|
|
35
35
|
const evidence = profile.logs.evidence.map((f) => thisLeg(tail(path.join(runDir, f), profile.logs.evidenceTailLines))).join('\n');
|
|
36
|
-
const c = classify({ profile, portRoot, res, crash, aborted, since, evidence });
|
|
36
|
+
const c = classify({ profile, portRoot, res, crash, aborted, since, evidence, runDir });
|
|
37
37
|
if (!c.call) { d.event('not-called', { kind: c.kind, why: c.why }); return { handled: false, kind: c.kind, why: c.why }; }
|
|
38
38
|
d.event('trigger', { kind: c.kind, layer: c.layer, why: c.why, step: (crash && crash.step) || '' });
|
|
39
39
|
|
|
@@ -129,6 +129,13 @@ function cache({ install, project, codeline, variant = process.env.EPAM_BROWNFIE
|
|
|
129
129
|
const C = path.join(O, 'projects', project, '.prompt-cache', codeline);
|
|
130
130
|
const b = require(path.join(scriptsOf(install), 'lib', 'project-prompt-builder.js'));
|
|
131
131
|
const tpl = (t) => path.join(O, 'prompts', 'templates', `${t}.json`);
|
|
132
|
+
// A COMPLETE SET IS REUSED WHOLE (2026-10-22): the mint step keeps a codeline whose set is complete ("completed its agents and
|
|
133
|
+
// prompts — kept") and no prompt is built, so per-prompt entries are not needed — the builder's own test, as the mint step's
|
|
134
|
+
const prev = process.env.EPAM_BROWNFIELD; process.env.EPAM_BROWNFIELD = variant === 'brownfield' ? '1' : '';
|
|
135
|
+
let whole;
|
|
136
|
+
try { whole = b.codelineSetComplete({ projectConfigDir: path.join(O, 'projects', project), codeline, templatesDir: path.join(O, 'prompts', 'templates'), registryFile: path.join(O, 'agents', 'invocation-profiles.json') }); }
|
|
137
|
+
finally { if (prev === undefined) delete process.env.EPAM_BROWNFIELD; else process.env.EPAM_BROWNFIELD = prev; }
|
|
138
|
+
if (whole && whole.complete) return res('cache', true, `${codeline}: its complete set is reused whole by the mint step — nothing rebuilt`, { required: 0, missing: [], willRebuild: [] });
|
|
132
139
|
const problems = [];
|
|
133
140
|
const prompts = fs.existsSync(path.join(C, 'prompts')) ? fs.readdirSync(path.join(C, 'prompts')).filter((n) => n.endsWith('.json')).map((n) => n.replace(/\.json$/, '')) : [];
|
|
134
141
|
if (!prompts.length) problems.push(`no cached prompt set (${path.join(C, 'prompts')})`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amsd-pipeline-shared",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.27",
|
|
4
4
|
"description": "The AMSD pipeline's shared components, one source for the bash pipeline and its Claude workflows: the model-call gateway (llm-handler.sh — retry, ladder, self-heal, cost) and the libraries it runs.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|