@jini-ai/daemon 0.3.2 → 0.3.6
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/dist/agent-executor.d.ts +133 -3
- package/dist/agent-executor.d.ts.map +1 -1
- package/dist/agent-executor.js +265 -11
- package/dist/agent-executor.js.map +1 -1
- package/dist/artifacts/index.d.ts +14 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +14 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/manifest.d.ts +90 -0
- package/dist/artifacts/manifest.d.ts.map +1 -0
- package/dist/artifacts/manifest.js +229 -0
- package/dist/artifacts/manifest.js.map +1 -0
- package/dist/artifacts/publication-guard.d.ts +28 -0
- package/dist/artifacts/publication-guard.d.ts.map +1 -0
- package/dist/artifacts/publication-guard.js +77 -0
- package/dist/artifacts/publication-guard.js.map +1 -0
- package/dist/artifacts/runtime-compat.d.ts +37 -0
- package/dist/artifacts/runtime-compat.d.ts.map +1 -0
- package/dist/artifacts/runtime-compat.js +33 -0
- package/dist/artifacts/runtime-compat.js.map +1 -0
- package/dist/artifacts/store.d.ts +85 -0
- package/dist/artifacts/store.d.ts.map +1 -0
- package/dist/artifacts/store.js +92 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/artifacts/stub-guard.d.ts +73 -0
- package/dist/artifacts/stub-guard.d.ts.map +1 -0
- package/dist/artifacts/stub-guard.js +198 -0
- package/dist/artifacts/stub-guard.js.map +1 -0
- package/dist/artifacts/text-suppression.d.ts +68 -0
- package/dist/artifacts/text-suppression.d.ts.map +1 -0
- package/dist/artifacts/text-suppression.js +184 -0
- package/dist/artifacts/text-suppression.js.map +1 -0
- package/dist/run-lifecycle.d.ts +20 -0
- package/dist/run-lifecycle.d.ts.map +1 -1
- package/dist/run-lifecycle.js +20 -0
- package/dist/run-lifecycle.js.map +1 -1
- package/dist/tool-result-surfaces.d.ts +1 -1
- package/dist/tool-result-surfaces.js +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export type ArtifactStubGuardMode = 'reject' | 'warn' | 'off';
|
|
2
|
+
export interface ArtifactStubGuardConfig {
|
|
3
|
+
readonly mode: ArtifactStubGuardMode;
|
|
4
|
+
readonly minRetainedRatio: number;
|
|
5
|
+
readonly minPriorBytes: number;
|
|
6
|
+
/** File-name extensions (including the leading dot) this guard scans for prior siblings, e.g. `['.html', '.htm']`. */
|
|
7
|
+
readonly siblingExtensions: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface PriorArtifactSibling {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly size: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ArtifactStubGuardWarning {
|
|
14
|
+
readonly code: 'ARTIFACT_REGRESSION';
|
|
15
|
+
readonly message: string;
|
|
16
|
+
readonly identifier: string;
|
|
17
|
+
readonly newSize: number;
|
|
18
|
+
readonly priorSize: number;
|
|
19
|
+
readonly priorName: string;
|
|
20
|
+
}
|
|
21
|
+
export interface EvaluateArtifactStubGuardInput {
|
|
22
|
+
readonly scanDir: string;
|
|
23
|
+
readonly identifier: string;
|
|
24
|
+
readonly newSize: number;
|
|
25
|
+
readonly config: ArtifactStubGuardConfig;
|
|
26
|
+
}
|
|
27
|
+
export interface EvaluateArtifactStubGuardResult {
|
|
28
|
+
readonly outcome: 'pass' | 'warn' | 'reject';
|
|
29
|
+
readonly warning?: ArtifactStubGuardWarning;
|
|
30
|
+
}
|
|
31
|
+
export declare class ArtifactRegressionError extends Error {
|
|
32
|
+
readonly code = "ARTIFACT_REGRESSION";
|
|
33
|
+
readonly identifier: string;
|
|
34
|
+
readonly newSize: number;
|
|
35
|
+
readonly priorSize: number;
|
|
36
|
+
readonly priorName: string;
|
|
37
|
+
constructor(message: string, details: {
|
|
38
|
+
identifier: string;
|
|
39
|
+
newSize: number;
|
|
40
|
+
priorSize: number;
|
|
41
|
+
priorName: string;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export declare const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG: ArtifactStubGuardConfig;
|
|
45
|
+
/** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
|
|
46
|
+
export declare function slugifyArtifactIdentifier(value: string): string;
|
|
47
|
+
/** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
|
|
48
|
+
export declare const EMPTY_SLUG_FALLBACK_NAME = "artifact";
|
|
49
|
+
/**
|
|
50
|
+
* Two identifiers refer to the same artifact lineage when they're literally
|
|
51
|
+
* equal, or one is the canonical slug form of the other (and that slug is
|
|
52
|
+
* non-empty). Slug equality alone is not enough: a slugifier that truncates
|
|
53
|
+
* at a fixed length would otherwise falsely bridge two distinct identifiers
|
|
54
|
+
* that only diverge past that length — requiring one side to *be* the slug
|
|
55
|
+
* form of the other avoids that while still bridging e.g. "Landing Page" and
|
|
56
|
+
* "landing-page".
|
|
57
|
+
*/
|
|
58
|
+
export declare function artifactIdentifiersMatch(a: string, b: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Finds prior siblings on disk that share an identifier with a newly-written
|
|
61
|
+
* artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
|
|
62
|
+
* The scan deliberately includes any file at the same path as the new write
|
|
63
|
+
* — when a write overwrites an existing file with the same name, the file
|
|
64
|
+
* currently on disk is the prior content (the overwrite happens after this
|
|
65
|
+
* scan runs).
|
|
66
|
+
*/
|
|
67
|
+
export declare function findPriorArtifactSiblings(scanDir: string, identifier: string, config: Pick<ArtifactStubGuardConfig, 'siblingExtensions'>): Promise<PriorArtifactSibling[]>;
|
|
68
|
+
/** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
|
|
69
|
+
export declare function readArtifactStubGuardConfigFromEnv(env?: NodeJS.ProcessEnv, defaults?: ArtifactStubGuardConfig): ArtifactStubGuardConfig;
|
|
70
|
+
/** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
|
|
71
|
+
export declare function classifyArtifactStubGuard(priors: readonly PriorArtifactSibling[], identifier: string, newSize: number, config: ArtifactStubGuardConfig): EvaluateArtifactStubGuardResult;
|
|
72
|
+
export declare function evaluateArtifactStubGuard(input: EvaluateArtifactStubGuardInput): Promise<EvaluateArtifactStubGuardResult>;
|
|
73
|
+
//# sourceMappingURL=stub-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub-guard.d.ts","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sHAAsH;IACtH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;CAC1C;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;CAC7C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAGzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;CASzF;AAED,eAAO,MAAM,kCAAkC,EAAE,uBAKhD,CAAC;AAMF,8GAA8G;AAC9G,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,wHAAwH;AACxH,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAOtE;AA0BD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,GACzD,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA2CjC;AAED,uLAAuL;AACvL,wBAAgB,kCAAkC,CAChD,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,uBAA4D,GACrE,uBAAuB,CAezB;AAiBD,gMAAgM;AAChM,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,uBAAuB,GAC9B,+BAA+B,CAqBjC;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAK1C"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export class ArtifactRegressionError extends Error {
|
|
4
|
+
code = 'ARTIFACT_REGRESSION';
|
|
5
|
+
identifier;
|
|
6
|
+
newSize;
|
|
7
|
+
priorSize;
|
|
8
|
+
priorName;
|
|
9
|
+
constructor(message, details) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'ArtifactRegressionError';
|
|
12
|
+
this.identifier = details.identifier;
|
|
13
|
+
this.newSize = details.newSize;
|
|
14
|
+
this.priorSize = details.priorSize;
|
|
15
|
+
this.priorName = details.priorName;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG = {
|
|
19
|
+
mode: 'warn',
|
|
20
|
+
minRetainedRatio: 0.2,
|
|
21
|
+
minPriorBytes: 4096,
|
|
22
|
+
siblingExtensions: ['.html', '.htm'],
|
|
23
|
+
};
|
|
24
|
+
function escapeRegExp(value) {
|
|
25
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
26
|
+
}
|
|
27
|
+
/** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
|
|
28
|
+
export function slugifyArtifactIdentifier(value) {
|
|
29
|
+
return value
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
32
|
+
.replace(/^-+|-+$/g, '')
|
|
33
|
+
.slice(0, 60);
|
|
34
|
+
}
|
|
35
|
+
/** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
|
|
36
|
+
export const EMPTY_SLUG_FALLBACK_NAME = 'artifact';
|
|
37
|
+
/**
|
|
38
|
+
* Two identifiers refer to the same artifact lineage when they're literally
|
|
39
|
+
* equal, or one is the canonical slug form of the other (and that slug is
|
|
40
|
+
* non-empty). Slug equality alone is not enough: a slugifier that truncates
|
|
41
|
+
* at a fixed length would otherwise falsely bridge two distinct identifiers
|
|
42
|
+
* that only diverge past that length — requiring one side to *be* the slug
|
|
43
|
+
* form of the other avoids that while still bridging e.g. "Landing Page" and
|
|
44
|
+
* "landing-page".
|
|
45
|
+
*/
|
|
46
|
+
export function artifactIdentifiersMatch(a, b) {
|
|
47
|
+
if (a === b)
|
|
48
|
+
return true;
|
|
49
|
+
const slugA = slugifyArtifactIdentifier(a);
|
|
50
|
+
if (slugA.length === 0)
|
|
51
|
+
return false;
|
|
52
|
+
const slugB = slugifyArtifactIdentifier(b);
|
|
53
|
+
if (slugA !== slugB)
|
|
54
|
+
return false;
|
|
55
|
+
return a === slugA || b === slugB;
|
|
56
|
+
}
|
|
57
|
+
async function readSidecarIdentifier(scanDir, entryName) {
|
|
58
|
+
try {
|
|
59
|
+
const raw = await readFile(path.join(scanDir, `${entryName}.artifact.json`), 'utf8');
|
|
60
|
+
const parsed = JSON.parse(raw);
|
|
61
|
+
const id = parsed?.metadata?.identifier;
|
|
62
|
+
return typeof id === 'string' && id.length > 0 ? id : null;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function extensionAlternation(extensions) {
|
|
69
|
+
return extensions.map((ext) => escapeRegExp(ext)).join('|');
|
|
70
|
+
}
|
|
71
|
+
function legacyCandidateIdentifiers(filename, extensionPattern, suffixPattern) {
|
|
72
|
+
const fullBasename = filename.replace(extensionPattern, '');
|
|
73
|
+
const stripped = filename.replace(suffixPattern, '');
|
|
74
|
+
const candidates = [];
|
|
75
|
+
if (fullBasename.length > 0)
|
|
76
|
+
candidates.push(fullBasename);
|
|
77
|
+
if (stripped.length > 0 && stripped !== fullBasename)
|
|
78
|
+
candidates.push(stripped);
|
|
79
|
+
return candidates;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Finds prior siblings on disk that share an identifier with a newly-written
|
|
83
|
+
* artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
|
|
84
|
+
* The scan deliberately includes any file at the same path as the new write
|
|
85
|
+
* — when a write overwrites an existing file with the same name, the file
|
|
86
|
+
* currently on disk is the prior content (the overwrite happens after this
|
|
87
|
+
* scan runs).
|
|
88
|
+
*/
|
|
89
|
+
export async function findPriorArtifactSiblings(scanDir, identifier, config) {
|
|
90
|
+
if (identifier.length === 0)
|
|
91
|
+
return [];
|
|
92
|
+
const extAlternation = extensionAlternation(config.siblingExtensions);
|
|
93
|
+
if (!extAlternation)
|
|
94
|
+
return [];
|
|
95
|
+
const extensionPattern = new RegExp(`(?:${extAlternation})$`, 'i');
|
|
96
|
+
const suffixPattern = new RegExp(`(?:-\\d+)?(?:${extAlternation})$`, 'i');
|
|
97
|
+
const tokens = new Set();
|
|
98
|
+
tokens.add(identifier);
|
|
99
|
+
const slug = slugifyArtifactIdentifier(identifier);
|
|
100
|
+
if (slug.length > 0)
|
|
101
|
+
tokens.add(slug);
|
|
102
|
+
else
|
|
103
|
+
tokens.add(EMPTY_SLUG_FALLBACK_NAME);
|
|
104
|
+
const alternation = Array.from(tokens, escapeRegExp).join('|');
|
|
105
|
+
const pattern = new RegExp(`^(?:${alternation})(?:-\\d+)?(?:${extAlternation})$`, 'i');
|
|
106
|
+
let entries;
|
|
107
|
+
try {
|
|
108
|
+
entries = await readdir(scanDir, { withFileTypes: true });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const results = [];
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
if (!entry.isFile())
|
|
116
|
+
continue;
|
|
117
|
+
if (!pattern.test(entry.name))
|
|
118
|
+
continue;
|
|
119
|
+
const sidecarIdentifier = await readSidecarIdentifier(scanDir, entry.name);
|
|
120
|
+
// `legacyCandidateIdentifiers` always returns at least one non-empty
|
|
121
|
+
// candidate here: `entry.name` already matched `pattern` above, which
|
|
122
|
+
// requires its basename to start with one of `tokens` (all non-empty),
|
|
123
|
+
// so an explicit `candidateIdentifiers.length === 0` guard would be
|
|
124
|
+
// dead code — an empty array's `.some()` below already `continue`s.
|
|
125
|
+
const candidateIdentifiers = sidecarIdentifier !== null
|
|
126
|
+
? [sidecarIdentifier]
|
|
127
|
+
: legacyCandidateIdentifiers(entry.name, extensionPattern, suffixPattern);
|
|
128
|
+
if (!candidateIdentifiers.some((c) => artifactIdentifiersMatch(identifier, c)))
|
|
129
|
+
continue;
|
|
130
|
+
try {
|
|
131
|
+
const st = await stat(path.join(scanDir, entry.name));
|
|
132
|
+
results.push({ name: entry.name, size: st.size });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Ignore unreadable entries — they don't influence the guard decision.
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
140
|
+
/** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
|
|
141
|
+
export function readArtifactStubGuardConfigFromEnv(env = process.env, defaults = DEFAULT_ARTIFACT_STUB_GUARD_CONFIG) {
|
|
142
|
+
const rawMode = (env.ARTIFACT_STUB_GUARD ?? '').toLowerCase();
|
|
143
|
+
const mode = rawMode === 'reject' || rawMode === 'warn' || rawMode === 'off' ? rawMode : defaults.mode;
|
|
144
|
+
const ratioRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_RATIO);
|
|
145
|
+
// Accept (0, 1] so a caller can set 1 to reject any shrinkage. Values <=0 or >1 fall back to default.
|
|
146
|
+
const minRetainedRatio = Number.isFinite(ratioRaw) && ratioRaw > 0 && ratioRaw <= 1 ? ratioRaw : defaults.minRetainedRatio;
|
|
147
|
+
const minPriorBytesRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES);
|
|
148
|
+
const minPriorBytes = Number.isInteger(minPriorBytesRaw) && minPriorBytesRaw > 0 ? minPriorBytesRaw : defaults.minPriorBytes;
|
|
149
|
+
return { mode, minRetainedRatio, minPriorBytes, siblingExtensions: defaults.siblingExtensions };
|
|
150
|
+
}
|
|
151
|
+
function buildWarning(identifier, newSize, prior) {
|
|
152
|
+
return {
|
|
153
|
+
code: 'ARTIFACT_REGRESSION',
|
|
154
|
+
message: `New artifact body for identifier "${identifier}" is ${newSize} bytes, ` +
|
|
155
|
+
`but the largest prior sibling "${prior.name}" is ${prior.size} bytes. ` +
|
|
156
|
+
'This pattern usually means the write emitted a placeholder instead of the full document. ' +
|
|
157
|
+
'Set the guard mode to "warn" to record the warning without rejecting, or "off" to disable the guard entirely.',
|
|
158
|
+
identifier,
|
|
159
|
+
newSize,
|
|
160
|
+
priorSize: prior.size,
|
|
161
|
+
priorName: prior.name,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
|
|
165
|
+
export function classifyArtifactStubGuard(priors, identifier, newSize, config) {
|
|
166
|
+
if (config.mode === 'off')
|
|
167
|
+
return { outcome: 'pass' };
|
|
168
|
+
if (identifier.length === 0)
|
|
169
|
+
return { outcome: 'pass' };
|
|
170
|
+
if (priors.length === 0)
|
|
171
|
+
return { outcome: 'pass' };
|
|
172
|
+
let largestSoFar = null;
|
|
173
|
+
for (const prior of priors) {
|
|
174
|
+
if (largestSoFar === null || prior.size > largestSoFar.size)
|
|
175
|
+
largestSoFar = prior;
|
|
176
|
+
}
|
|
177
|
+
// Non-null assertion, not a runtime guard: `priors.length === 0` already
|
|
178
|
+
// returned above, so this loop always runs at least once, and its first
|
|
179
|
+
// iteration always satisfies `largestSoFar === null` — it's always
|
|
180
|
+
// assigned by the time the loop finishes.
|
|
181
|
+
const largest = largestSoFar;
|
|
182
|
+
if (largest.size < config.minPriorBytes)
|
|
183
|
+
return { outcome: 'pass' };
|
|
184
|
+
const threshold = largest.size * config.minRetainedRatio;
|
|
185
|
+
if (newSize >= threshold)
|
|
186
|
+
return { outcome: 'pass' };
|
|
187
|
+
const warning = buildWarning(identifier, newSize, largest);
|
|
188
|
+
return { outcome: config.mode === 'reject' ? 'reject' : 'warn', warning };
|
|
189
|
+
}
|
|
190
|
+
export async function evaluateArtifactStubGuard(input) {
|
|
191
|
+
if (input.config.mode === 'off')
|
|
192
|
+
return { outcome: 'pass' };
|
|
193
|
+
if (input.identifier.length === 0)
|
|
194
|
+
return { outcome: 'pass' };
|
|
195
|
+
const priors = await findPriorArtifactSiblings(input.scanDir, input.identifier, input.config);
|
|
196
|
+
return classifyArtifactStubGuard(priors, input.identifier, input.newSize, input.config);
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=stub-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub-guard.js","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module artifacts/text-suppression
|
|
3
|
+
*
|
|
4
|
+
* A streaming-text state machine that suppresses a tagged block (matched by
|
|
5
|
+
* caller-supplied open/close patterns) from user-visible output while it's
|
|
6
|
+
* still arriving — used to hide an artifact's raw markup from chat prose
|
|
7
|
+
* while it streams in, without buffering the whole response first. Ported
|
|
8
|
+
* from OD's `apps/daemon/src/artifacts/text-suppression.ts`.
|
|
9
|
+
*
|
|
10
|
+
* The core (`createTaggedTextSuppressor`) was already fully generic in the
|
|
11
|
+
* origin — it takes its open/close regexes and open/close prefix-match
|
|
12
|
+
* predicates as parameters, no product coupling. What needed de-branding
|
|
13
|
+
* were the origin's two pre-built instances: `createDsmlArtifactTextSuppressor`
|
|
14
|
+
* hardcoded OD's own "DSML" markup-language tag name family
|
|
15
|
+
* (`<|DSML artifact>`/`<artifact>`) as its open/close patterns.
|
|
16
|
+
* `createXmlTagTextSuppressor` below replaces it — a generic factory taking
|
|
17
|
+
* the caller's own tag-name list instead of a hardcoded vocabulary. The
|
|
18
|
+
* `tool_call`/`edit` pairing the origin's other instance
|
|
19
|
+
* (`createToolCallTextSuppressor`) suppressed is a generic agent-protocol
|
|
20
|
+
* convention, not OD-branded, and is kept as a named default instance.
|
|
21
|
+
*/
|
|
22
|
+
export type StreamTextEvent = {
|
|
23
|
+
readonly type: 'text_delta';
|
|
24
|
+
readonly delta: string;
|
|
25
|
+
};
|
|
26
|
+
export type StreamEventSink = (event: StreamTextEvent) => void;
|
|
27
|
+
export interface ArtifactTextSuppressor {
|
|
28
|
+
strip(text: string): string;
|
|
29
|
+
flush(): string;
|
|
30
|
+
isSuppressing(): boolean;
|
|
31
|
+
hasPendingCandidate(): boolean;
|
|
32
|
+
stats(): ArtifactTextSuppressorStats;
|
|
33
|
+
}
|
|
34
|
+
export interface ArtifactTextSuppressorStats {
|
|
35
|
+
readonly suppressedChars: number;
|
|
36
|
+
readonly suppressedChunks: number;
|
|
37
|
+
readonly openedBlocks: number;
|
|
38
|
+
readonly closedBlocks: number;
|
|
39
|
+
readonly pendingCandidateChars: number;
|
|
40
|
+
readonly suppressing: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Builds a suppressor for a tagged block delimited by `openRe`/`closeRe`.
|
|
44
|
+
* `isPossibleOpen`/`isPossibleClose` decide whether a trailing `<...`
|
|
45
|
+
* fragment (with no closing `>` yet) *could* still become a match once more
|
|
46
|
+
* text arrives — this is what lets the suppressor hold back a
|
|
47
|
+
* not-yet-decidable tail across streaming chunk boundaries instead of
|
|
48
|
+
* either emitting a tag fragment early or hanging indefinitely on a `<` that
|
|
49
|
+
* turns out to be unrelated text.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createTaggedTextSuppressor(args: {
|
|
52
|
+
openRe: RegExp;
|
|
53
|
+
closeRe: RegExp;
|
|
54
|
+
isPossibleOpen: (text: string) => boolean;
|
|
55
|
+
isPossibleClose: (text: string) => boolean;
|
|
56
|
+
}): ArtifactTextSuppressor;
|
|
57
|
+
/** Feeds `text` through `suppressor` and emits a `text_delta` on `onEvent` only when something survives. Returns whether an event was emitted. */
|
|
58
|
+
export declare function emitWithTextSuppressor(suppressor: ArtifactTextSuppressor, onEvent: StreamEventSink, text: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Builds a suppressor for an XML-like `<tagName ...>...</tagName>` block (or
|
|
61
|
+
* a bracket-pipe variant `<|tagName ...>...<|/tagName|>`), matched
|
|
62
|
+
* case-insensitively against any of `tagNames`. Replaces the origin's
|
|
63
|
+
* hardcoded "DSML" tag-name family with a caller-supplied vocabulary.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createXmlTagTextSuppressor(tagNames: readonly string[]): ArtifactTextSuppressor;
|
|
66
|
+
/** Suppresses a `<tool_call>...</tool_call>` or `<edit>...</edit>` block — a generic agent-protocol convention, not product-branded. */
|
|
67
|
+
export declare function createToolCallTextSuppressor(): ArtifactTextSuppressor;
|
|
68
|
+
//# sourceMappingURL=text-suppression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-suppression.d.ts","sourceRoot":"","sources":["../../src/artifacts/text-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,KAAK,IAAI,MAAM,CAAC;IAChB,aAAa,IAAI,OAAO,CAAC;IACzB,mBAAmB,IAAI,OAAO,CAAC;IAC/B,KAAK,IAAI,2BAA2B,CAAC;CACtC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAID;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,GAAG,sBAAsB,CAgFzB;AAED,kJAAkJ;AAClJ,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAKT;AAqBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,sBAAsB,CAmB9F;AAoBD,wIAAwI;AACxI,wBAAgB,4BAA4B,IAAI,sBAAsB,CAOrE"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module artifacts/text-suppression
|
|
3
|
+
*
|
|
4
|
+
* A streaming-text state machine that suppresses a tagged block (matched by
|
|
5
|
+
* caller-supplied open/close patterns) from user-visible output while it's
|
|
6
|
+
* still arriving — used to hide an artifact's raw markup from chat prose
|
|
7
|
+
* while it streams in, without buffering the whole response first. Ported
|
|
8
|
+
* from OD's `apps/daemon/src/artifacts/text-suppression.ts`.
|
|
9
|
+
*
|
|
10
|
+
* The core (`createTaggedTextSuppressor`) was already fully generic in the
|
|
11
|
+
* origin — it takes its open/close regexes and open/close prefix-match
|
|
12
|
+
* predicates as parameters, no product coupling. What needed de-branding
|
|
13
|
+
* were the origin's two pre-built instances: `createDsmlArtifactTextSuppressor`
|
|
14
|
+
* hardcoded OD's own "DSML" markup-language tag name family
|
|
15
|
+
* (`<|DSML artifact>`/`<artifact>`) as its open/close patterns.
|
|
16
|
+
* `createXmlTagTextSuppressor` below replaces it — a generic factory taking
|
|
17
|
+
* the caller's own tag-name list instead of a hardcoded vocabulary. The
|
|
18
|
+
* `tool_call`/`edit` pairing the origin's other instance
|
|
19
|
+
* (`createToolCallTextSuppressor`) suppressed is a generic agent-protocol
|
|
20
|
+
* convention, not OD-branded, and is kept as a named default instance.
|
|
21
|
+
*/
|
|
22
|
+
const MAX_CANDIDATE_LENGTH = 512;
|
|
23
|
+
/**
|
|
24
|
+
* Builds a suppressor for a tagged block delimited by `openRe`/`closeRe`.
|
|
25
|
+
* `isPossibleOpen`/`isPossibleClose` decide whether a trailing `<...`
|
|
26
|
+
* fragment (with no closing `>` yet) *could* still become a match once more
|
|
27
|
+
* text arrives — this is what lets the suppressor hold back a
|
|
28
|
+
* not-yet-decidable tail across streaming chunk boundaries instead of
|
|
29
|
+
* either emitting a tag fragment early or hanging indefinitely on a `<` that
|
|
30
|
+
* turns out to be unrelated text.
|
|
31
|
+
*/
|
|
32
|
+
export function createTaggedTextSuppressor(args) {
|
|
33
|
+
let suppressing = false;
|
|
34
|
+
let candidate = '';
|
|
35
|
+
let suppressedChars = 0;
|
|
36
|
+
let suppressedChunks = 0;
|
|
37
|
+
let openedBlocks = 0;
|
|
38
|
+
let closedBlocks = 0;
|
|
39
|
+
function noteSuppressed(text) {
|
|
40
|
+
if (text.length <= 0)
|
|
41
|
+
return;
|
|
42
|
+
suppressedChars += text.length;
|
|
43
|
+
suppressedChunks += 1;
|
|
44
|
+
}
|
|
45
|
+
function strip(text) {
|
|
46
|
+
const current = `${candidate}${text}`;
|
|
47
|
+
candidate = '';
|
|
48
|
+
if (suppressing) {
|
|
49
|
+
const close = args.closeRe.exec(current);
|
|
50
|
+
if (!close || close.index === undefined) {
|
|
51
|
+
const closeCandidateStart = possibleTagStart(current, args.isPossibleClose);
|
|
52
|
+
if (closeCandidateStart !== -1) {
|
|
53
|
+
candidate = current.slice(closeCandidateStart);
|
|
54
|
+
noteSuppressed(current.slice(0, closeCandidateStart));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
noteSuppressed(current);
|
|
58
|
+
}
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
suppressing = false;
|
|
62
|
+
const end = close.index + close[0].length;
|
|
63
|
+
closedBlocks += 1;
|
|
64
|
+
noteSuppressed(current.slice(0, end));
|
|
65
|
+
return strip(current.slice(end));
|
|
66
|
+
}
|
|
67
|
+
const open = args.openRe.exec(current);
|
|
68
|
+
if (open && open.index !== undefined) {
|
|
69
|
+
suppressing = true;
|
|
70
|
+
openedBlocks += 1;
|
|
71
|
+
const prefix = current.slice(0, open.index);
|
|
72
|
+
const tail = current.slice(open.index + open[0].length);
|
|
73
|
+
noteSuppressed(open[0]);
|
|
74
|
+
return `${prefix}${strip(tail)}`;
|
|
75
|
+
}
|
|
76
|
+
const candidateStart = possibleTagStart(current, args.isPossibleOpen);
|
|
77
|
+
if (candidateStart === -1)
|
|
78
|
+
return current;
|
|
79
|
+
candidate = current.slice(candidateStart);
|
|
80
|
+
return current.slice(0, candidateStart);
|
|
81
|
+
}
|
|
82
|
+
function flush() {
|
|
83
|
+
const text = candidate;
|
|
84
|
+
candidate = '';
|
|
85
|
+
return suppressing ? '' : text;
|
|
86
|
+
}
|
|
87
|
+
function isSuppressing() {
|
|
88
|
+
return suppressing;
|
|
89
|
+
}
|
|
90
|
+
function hasPendingCandidate() {
|
|
91
|
+
return candidate.length > 0;
|
|
92
|
+
}
|
|
93
|
+
function stats() {
|
|
94
|
+
return {
|
|
95
|
+
suppressedChars,
|
|
96
|
+
suppressedChunks,
|
|
97
|
+
openedBlocks,
|
|
98
|
+
closedBlocks,
|
|
99
|
+
pendingCandidateChars: candidate.length,
|
|
100
|
+
suppressing,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return { strip, flush, isSuppressing, hasPendingCandidate, stats };
|
|
104
|
+
}
|
|
105
|
+
/** Feeds `text` through `suppressor` and emits a `text_delta` on `onEvent` only when something survives. Returns whether an event was emitted. */
|
|
106
|
+
export function emitWithTextSuppressor(suppressor, onEvent, text) {
|
|
107
|
+
const delta = suppressor.strip(text);
|
|
108
|
+
if (!delta)
|
|
109
|
+
return false;
|
|
110
|
+
onEvent({ type: 'text_delta', delta });
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
function possibleTagStart(text, predicate) {
|
|
114
|
+
const min = Math.max(0, text.length - MAX_CANDIDATE_LENGTH);
|
|
115
|
+
let index = text.lastIndexOf('<');
|
|
116
|
+
while (index >= min) {
|
|
117
|
+
const tail = text.slice(index);
|
|
118
|
+
if (predicate(tail))
|
|
119
|
+
return index;
|
|
120
|
+
if (index === 0)
|
|
121
|
+
break;
|
|
122
|
+
index = text.lastIndexOf('<', index - 1);
|
|
123
|
+
}
|
|
124
|
+
return -1;
|
|
125
|
+
}
|
|
126
|
+
// `text` is always a `possibleTagStart` tail slice starting at a `<`
|
|
127
|
+
// position (its only caller) — no `!text.startsWith('<')` re-check needed.
|
|
128
|
+
function compactTagCandidate(text, stripChars) {
|
|
129
|
+
if (text.includes('>'))
|
|
130
|
+
return null;
|
|
131
|
+
return text.toLowerCase().replace(stripChars, '');
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Builds a suppressor for an XML-like `<tagName ...>...</tagName>` block (or
|
|
135
|
+
* a bracket-pipe variant `<|tagName ...>...<|/tagName|>`), matched
|
|
136
|
+
* case-insensitively against any of `tagNames`. Replaces the origin's
|
|
137
|
+
* hardcoded "DSML" tag-name family with a caller-supplied vocabulary.
|
|
138
|
+
*/
|
|
139
|
+
export function createXmlTagTextSuppressor(tagNames) {
|
|
140
|
+
const canonicals = tagNames.map((t) => t.toLowerCase());
|
|
141
|
+
const namesPattern = canonicals.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
142
|
+
const openRe = new RegExp(`(?:<\\s*\\|?\\s*(?:${namesPattern})\\b[^>]*>)`, 'i');
|
|
143
|
+
const closeRe = new RegExp(`(?:<\\/(?:${namesPattern})>|<\\s*\\|?\\s*\\/\\s*(?:${namesPattern})\\s*\\|?\\s*>)`, 'i');
|
|
144
|
+
function isPossibleOpen(text) {
|
|
145
|
+
const compact = compactTagCandidate(text, /[<|,\s]/g);
|
|
146
|
+
if (compact === null)
|
|
147
|
+
return false;
|
|
148
|
+
return compact.length === 0 || canonicals.some((c) => c.startsWith(compact) || compact.startsWith(c));
|
|
149
|
+
}
|
|
150
|
+
function isPossibleClose(text) {
|
|
151
|
+
const compact = compactTagCandidate(text, /[<|/\s]/g);
|
|
152
|
+
if (compact === null)
|
|
153
|
+
return false;
|
|
154
|
+
return compact.length === 0 || canonicals.some((c) => c.startsWith(compact) || compact.startsWith(c));
|
|
155
|
+
}
|
|
156
|
+
return createTaggedTextSuppressor({ openRe, closeRe, isPossibleOpen, isPossibleClose });
|
|
157
|
+
}
|
|
158
|
+
const TOOL_CALL_OPEN_RE = /(?:<\s*tool_call\b[^>]*>|<\s*edit\s*>)/i;
|
|
159
|
+
const TOOL_CALL_CLOSE_RE = /(?:<\/\s*tool_call\s*>|<\/\s*edit\s*>)/i;
|
|
160
|
+
const TOOL_CALL_CANONICALS = ['toolcall', 'edit'];
|
|
161
|
+
// Same reasoning as compactTagCandidate above: `text` always starts with
|
|
162
|
+
// `<` here (a `possibleTagStart` tail slice) — no re-check needed.
|
|
163
|
+
function isPossibleToolCallOpen(text) {
|
|
164
|
+
if (text.includes('>'))
|
|
165
|
+
return false;
|
|
166
|
+
const compact = text.toLowerCase().replace(/[<|,\s_-]/g, '');
|
|
167
|
+
return compact.length === 0 || TOOL_CALL_CANONICALS.some((c) => c.startsWith(compact) || compact.startsWith(c));
|
|
168
|
+
}
|
|
169
|
+
function isPossibleToolCallClose(text) {
|
|
170
|
+
if (text.includes('>'))
|
|
171
|
+
return false;
|
|
172
|
+
const compact = text.toLowerCase().replace(/[<|/\s_-]/g, '');
|
|
173
|
+
return compact.length === 0 || TOOL_CALL_CANONICALS.some((c) => c.startsWith(compact) || compact.startsWith(c));
|
|
174
|
+
}
|
|
175
|
+
/** Suppresses a `<tool_call>...</tool_call>` or `<edit>...</edit>` block — a generic agent-protocol convention, not product-branded. */
|
|
176
|
+
export function createToolCallTextSuppressor() {
|
|
177
|
+
return createTaggedTextSuppressor({
|
|
178
|
+
openRe: TOOL_CALL_OPEN_RE,
|
|
179
|
+
closeRe: TOOL_CALL_CLOSE_RE,
|
|
180
|
+
isPossibleOpen: isPossibleToolCallOpen,
|
|
181
|
+
isPossibleClose: isPossibleToolCallClose,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=text-suppression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-suppression.js","sourceRoot":"","sources":["../../src/artifacts/text-suppression.ts"],"names":[],"mappings":"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"}
|
package/dist/run-lifecycle.d.ts
CHANGED
|
@@ -83,6 +83,26 @@ export interface RunLifecycle {
|
|
|
83
83
|
/** Idempotent terminal transition; a second call while already terminal is a no-op that returns the existing status unchanged. */
|
|
84
84
|
finish(input: FinishRunInput): Promise<RunStatus>;
|
|
85
85
|
resume(runId: string): Promise<ResumeRunResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Suspends the slow-run watchdog for `runId` while a daemon-managed operation of legitimately
|
|
88
|
+
* unbounded duration is in flight (e.g. an auto-resolved tool call the daemon itself awaits) — pair
|
|
89
|
+
* with {@link RunLifecycle.resumeSlowRunNotice} once that operation concludes. `emit()` is the
|
|
90
|
+
* *only* other reset signal the watchdog has, and it fires nothing while such an operation is
|
|
91
|
+
* running (there is no output to stream), so without this call a tool that legitimately runs past
|
|
92
|
+
* the threshold (an install, a build, a repo-wide scan) is indistinguishable from the exact
|
|
93
|
+
* CPU-starved-and-silent condition the watchdog exists to catch, and fires a "still working" notice
|
|
94
|
+
* on a run that never actually stalled. A driver that knows exactly why a run is quiet must say so
|
|
95
|
+
* rather than leaving the watchdog to guess from silence alone. No-op if `runId` is unknown,
|
|
96
|
+
* already terminal, or the slow-run notice is disabled kernel-wide (`slowRunThresholdMs: null`).
|
|
97
|
+
*/
|
|
98
|
+
suspendSlowRunNotice(runId: string): void;
|
|
99
|
+
/**
|
|
100
|
+
* Re-arms the slow-run watchdog for `runId` with a fresh timeout window, undoing
|
|
101
|
+
* {@link RunLifecycle.suspendSlowRunNotice} once the known operation concludes — so a genuinely
|
|
102
|
+
* stalled stretch starting *after* that point is still caught. No-op under the same conditions as
|
|
103
|
+
* `suspendSlowRunNotice`.
|
|
104
|
+
*/
|
|
105
|
+
resumeSlowRunNotice(runId: string): void;
|
|
86
106
|
/** Resolves once `runId` reaches a terminal state; resolves immediately if it already has. */
|
|
87
107
|
waitForTerminal(runId: string): Promise<RunStatus>;
|
|
88
108
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-lifecycle.d.ts","sourceRoot":"","sources":["../src/run-lifecycle.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"run-lifecycle.d.ts","sourceRoot":"","sources":["../src/run-lifecycle.ts"],"names":[],"mappings":"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"}
|
package/dist/run-lifecycle.js
CHANGED
|
@@ -735,12 +735,32 @@ export function createRunLifecycle(input) {
|
|
|
735
735
|
record.cancelRequested = false;
|
|
736
736
|
record.lastCancelRequest = undefined;
|
|
737
737
|
record.terminalEndEntry = undefined;
|
|
738
|
+
// Mirrors `start()`'s own arm call: a resumed run gets exactly the same fresh slow-run window a
|
|
739
|
+
// freshly-started one does. Without this, `finish()`'s `record.slowRunWatchdog?.cancel()` (which
|
|
740
|
+
// never fires again on its own — the underlying timer is one-shot) left the notice permanently
|
|
741
|
+
// dark for the rest of a resumed run's life, silently disabling a feature the run is otherwise
|
|
742
|
+
// still eligible for.
|
|
743
|
+
armSlowRunWatchdogIfConfigured(record, slowRunThresholdMs, () => {
|
|
744
|
+
void handleSlowRunNotice(runId);
|
|
745
|
+
});
|
|
738
746
|
// No protocol event is emitted here: none of RunProtocolEvent's six
|
|
739
747
|
// kinds represents "resumed" (extraction-plan scope decision — see
|
|
740
748
|
// source-map.md). The event log's cursor sequence continues
|
|
741
749
|
// unbroken; only RunStatus.state changes.
|
|
742
750
|
return { run: toPublicStatus(record), resumed: true };
|
|
743
751
|
},
|
|
752
|
+
suspendSlowRunNotice(runId) {
|
|
753
|
+
const record = runs.get(runId);
|
|
754
|
+
if (!record || isTerminalRunState(record.status.state))
|
|
755
|
+
return;
|
|
756
|
+
record.slowRunWatchdog?.cancel();
|
|
757
|
+
},
|
|
758
|
+
resumeSlowRunNotice(runId) {
|
|
759
|
+
const record = runs.get(runId);
|
|
760
|
+
if (!record || isTerminalRunState(record.status.state))
|
|
761
|
+
return;
|
|
762
|
+
record.slowRunWatchdog?.noteActivity();
|
|
763
|
+
},
|
|
744
764
|
async waitForTerminal(runId) {
|
|
745
765
|
const record = requireRun(runId);
|
|
746
766
|
// Awaited (and *propagated*, unlike in `get`/`list`) before any waiter is registered. A run
|