@kontourai/flow-agents 3.6.0 → 3.8.0
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/CHANGELOG.md +19 -0
- package/build/src/builder-flow-run-adapter.d.ts +22 -2
- package/build/src/builder-flow-run-adapter.js +93 -28
- package/build/src/builder-flow-runtime.d.ts +8 -3
- package/build/src/builder-flow-runtime.js +407 -51
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +80 -14
- package/build/src/cli/builder-run.js +14 -18
- package/build/src/cli/workflow-sidecar.d.ts +28 -4
- package/build/src/cli/workflow-sidecar.js +825 -103
- package/build/src/cli/workflow.js +301 -43
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.js +5 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/tools/build-universal-bundles.js +53 -3
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +78 -9
- package/docs/context-map.md +22 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/getting-started.md +9 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +75 -40
- package/docs/workflow-usage-guide.md +109 -42
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +52 -41
- package/evals/integration/test_builder_step_producers.sh +330 -6
- package/evals/integration/test_bundle_install.sh +318 -65
- package/evals/integration/test_bundle_lifecycle.sh +4 -6
- package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
- package/evals/integration/test_current_json_per_actor.sh +12 -0
- package/evals/integration/test_dual_emit_flow_step.sh +62 -43
- package/evals/integration/test_flowdef_session_activation.sh +145 -25
- package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
- package/evals/integration/test_gate_lockdown.sh +3 -5
- package/evals/integration/test_goal_fit_hook.sh +60 -2
- package/evals/integration/test_install_merge.sh +18 -8
- package/evals/integration/test_liveness_verdict.sh +14 -17
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
- package/evals/integration/test_public_workflow_cli.sh +334 -14
- package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
- package/evals/integration/test_sidecar_field_preservation.sh +36 -11
- package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
- package/evals/integration/test_workflow_steering_hook.sh +15 -38
- package/evals/run.sh +2 -0
- package/evals/static/test_builder_skill_coherence.sh +247 -0
- package/evals/static/test_library_exports.sh +5 -2
- package/evals/static/test_universal_bundles.sh +44 -1
- package/evals/static/test_workflow_skills.sh +13 -325
- package/kits/builder/flows/build.flow.json +22 -0
- package/kits/builder/flows/shape.flow.json +9 -9
- package/kits/builder/kit.json +70 -16
- package/kits/builder/skills/builder-shape/SKILL.md +75 -75
- package/kits/builder/skills/continue-work/SKILL.md +45 -106
- package/kits/builder/skills/deliver/SKILL.md +96 -442
- package/kits/builder/skills/design-probe/SKILL.md +40 -139
- package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
- package/kits/builder/skills/execute-plan/SKILL.md +54 -125
- package/kits/builder/skills/fix-bug/SKILL.md +42 -132
- package/kits/builder/skills/gate-review/SKILL.md +60 -211
- package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
- package/kits/builder/skills/learning-review/SKILL.md +63 -170
- package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
- package/kits/builder/skills/plan-work/SKILL.md +51 -185
- package/kits/builder/skills/pull-work/SKILL.md +136 -485
- package/kits/builder/skills/release-readiness/SKILL.md +66 -107
- package/kits/builder/skills/review-work/SKILL.md +89 -176
- package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
- package/kits/builder/skills/verify-work/SKILL.md +101 -113
- package/package.json +2 -2
- package/packaging/README.md +1 -1
- package/scripts/README.md +1 -1
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/scripts/install-codex-home.sh +63 -23
- package/scripts/install-owned-files.js +18 -2
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +426 -64
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +75 -14
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +436 -18
- package/src/cli/builder-run.ts +3 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +746 -103
- package/src/cli/workflow.ts +288 -41
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +6 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/tools/build-universal-bundles.ts +51 -3
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { randomBytes } from "node:crypto";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { parseArgs, flagString } from "../lib/args.js";
|
|
@@ -186,18 +187,27 @@ function subjectLockDir(artifactRoot, subjectId) {
|
|
|
186
187
|
const sanitized = loadActorIdentityHelper().sanitizeSegment(subjectId);
|
|
187
188
|
return path.join(assignmentDir, `.${sanitized}.lockdir`);
|
|
188
189
|
}
|
|
190
|
+
// Lock age is adjudicated by the current contender, never by metadata written
|
|
191
|
+
// by the lock owner. The environment is only an operator tuning input; clamp it
|
|
192
|
+
// so a caller cannot turn a transient owner-file write into immediate takeover.
|
|
193
|
+
const SUBJECT_LOCK_STALE_MIN_MS = 1_000;
|
|
194
|
+
const SUBJECT_LOCK_STALE_MAX_MS = 30 * 60 * 1_000;
|
|
195
|
+
const SUBJECT_LOCK_STALE_DEFAULT_MS = 5 * 60 * 1_000;
|
|
196
|
+
function trustedSubjectLockStaleMs() {
|
|
197
|
+
const configured = Number(process.env.FLOW_AGENTS_ASSIGNMENT_STALE_LOCK_MS);
|
|
198
|
+
if (!Number.isFinite(configured))
|
|
199
|
+
return SUBJECT_LOCK_STALE_DEFAULT_MS;
|
|
200
|
+
return Math.min(SUBJECT_LOCK_STALE_MAX_MS, Math.max(SUBJECT_LOCK_STALE_MIN_MS, Math.floor(configured)));
|
|
201
|
+
}
|
|
189
202
|
/**
|
|
190
203
|
* F1 fix (fix-plan iteration 1, CRITICAL): claimLocalFile/releaseLocalFile/supersedeLocalFile were
|
|
191
204
|
* a plain read -> compare-actor -> write with no lock, so two concurrently-launched OS processes
|
|
192
205
|
* could both read "no conflicting claim" before either wrote, and the second write would silently
|
|
193
206
|
* clobber the first with zero error and zero audit-trail entry for the loser (reproduced 29/40
|
|
194
|
-
* races against the built CLI).
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* is reclaimed rather than waited on forever) and a bounded deadline, `finally` rmSync release —
|
|
199
|
-
* as a small LOCAL helper (not a cross-import of that private function, which would pull the
|
|
200
|
-
* entire workflow-sidecar module in for one primitive). Deliberately synchronous (sleepSync's
|
|
207
|
+
* races against the built CLI). Atomic directory creation establishes ownership before metadata
|
|
208
|
+
* is written; contenders treat even an ownerless directory as held. Live contention waits with a
|
|
209
|
+
* bounded deadline; stale or malformed residue fails closed for explicit operator cleanup because portable Node
|
|
210
|
+
* filesystem APIs cannot compare-and-swap a directory identity safely. Deliberately synchronous (sleepSync's
|
|
201
211
|
* Atomics.wait spin, not setTimeout/await) so claim/release/supersede can stay sync `number`
|
|
202
212
|
* -returning functions and the CLI dispatcher (src/cli.ts, `number | Promise<number>`) does not
|
|
203
213
|
* need any ripple to async. On lock-acquire failure (any error other than a live contested lock,
|
|
@@ -208,23 +218,33 @@ function subjectLockDir(artifactRoot, subjectId) {
|
|
|
208
218
|
*/
|
|
209
219
|
export function withSubjectLock(artifactRoot, subjectId, body) {
|
|
210
220
|
const lockDir = subjectLockDir(artifactRoot, subjectId);
|
|
211
|
-
const staleMs =
|
|
221
|
+
const staleMs = trustedSubjectLockStaleMs();
|
|
222
|
+
const token = randomBytes(16).toString("hex");
|
|
223
|
+
const ownerFile = path.join(lockDir, "owner.json");
|
|
212
224
|
const deadline = Date.now() + 30000;
|
|
213
225
|
while (true) {
|
|
226
|
+
let createdLockDir = false;
|
|
214
227
|
try {
|
|
215
228
|
fs.mkdirSync(lockDir);
|
|
229
|
+
createdLockDir = true;
|
|
230
|
+
fs.writeFileSync(ownerFile, `${JSON.stringify({ token, pid: process.pid, acquired_at: isoNow() })}\n`, { flag: "wx", mode: 0o600 });
|
|
216
231
|
break;
|
|
217
232
|
}
|
|
218
233
|
catch (error) {
|
|
219
234
|
const lockError = error;
|
|
235
|
+
if (createdLockDir)
|
|
236
|
+
fs.rmSync(lockDir, { recursive: true, force: true });
|
|
220
237
|
if (lockError.code !== "EEXIST") {
|
|
221
238
|
throw new Error(`failed to acquire assignment lock for subject ${subjectId}: ${lockDir}: ${lockError.message || lockError.code || String(lockError)}`);
|
|
222
239
|
}
|
|
223
240
|
try {
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
241
|
+
const owner = readSubjectLockOwner(ownerFile);
|
|
242
|
+
const stat = fs.lstatSync(owner?.token ? ownerFile : lockDir);
|
|
243
|
+
if (stat.isSymbolicLink() || !(owner?.token ? stat.isFile() : stat.isDirectory())) {
|
|
244
|
+
throw new Error(`assignment lock has an unsafe ${owner?.token ? "owner file" : "directory"}: ${lockDir}`);
|
|
245
|
+
}
|
|
246
|
+
if (Date.now() - stat.mtimeMs > staleMs) {
|
|
247
|
+
throw new Error(`assignment lock is stale or malformed and requires explicit operator cleanup after confirming no owner is active: ${lockDir}`);
|
|
228
248
|
}
|
|
229
249
|
}
|
|
230
250
|
catch (statError) {
|
|
@@ -238,7 +258,14 @@ export function withSubjectLock(artifactRoot, subjectId, body) {
|
|
|
238
258
|
sleepSync(20);
|
|
239
259
|
}
|
|
240
260
|
}
|
|
241
|
-
|
|
261
|
+
let heartbeat;
|
|
262
|
+
const ownsLock = () => readSubjectLockOwner(ownerFile)?.token === token;
|
|
263
|
+
const release = () => {
|
|
264
|
+
if (heartbeat)
|
|
265
|
+
clearInterval(heartbeat);
|
|
266
|
+
if (ownsLock())
|
|
267
|
+
fs.rmSync(lockDir, { recursive: true, force: true });
|
|
268
|
+
};
|
|
242
269
|
let result;
|
|
243
270
|
try {
|
|
244
271
|
result = body();
|
|
@@ -248,11 +275,38 @@ export function withSubjectLock(artifactRoot, subjectId, body) {
|
|
|
248
275
|
throw error;
|
|
249
276
|
}
|
|
250
277
|
if (result && typeof result.then === "function") {
|
|
278
|
+
// An async owner can legitimately hold the lock longer than the stale-lock
|
|
279
|
+
// threshold while an authority-bound command is running. Keep its mtime fresh
|
|
280
|
+
// so lifecycle operations and takeovers continue to observe the live lock.
|
|
281
|
+
const heartbeatMs = Math.max(10, Math.min(1_000, Math.floor(staleMs > 0 ? staleMs / 3 : 1_000)));
|
|
282
|
+
heartbeat = setInterval(() => {
|
|
283
|
+
try {
|
|
284
|
+
if (!ownsLock())
|
|
285
|
+
return;
|
|
286
|
+
const timestamp = new Date();
|
|
287
|
+
fs.utimesSync(ownerFile, timestamp, timestamp);
|
|
288
|
+
fs.utimesSync(lockDir, timestamp, timestamp);
|
|
289
|
+
}
|
|
290
|
+
catch { /* release, reclamation, or process teardown owns cleanup */ }
|
|
291
|
+
}, heartbeatMs);
|
|
251
292
|
return Promise.resolve(result).finally(release);
|
|
252
293
|
}
|
|
253
294
|
release();
|
|
254
295
|
return result;
|
|
255
296
|
}
|
|
297
|
+
function readSubjectLockOwner(file) {
|
|
298
|
+
try {
|
|
299
|
+
const value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
300
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
301
|
+
? value
|
|
302
|
+
: null;
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
if (error.code === "ENOENT" || error instanceof SyntaxError)
|
|
306
|
+
return null;
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
256
310
|
/**
|
|
257
311
|
* The assignment ⋈ liveness join (contract doc's "assignment ⋈ liveness join" section, ADR 0021
|
|
258
312
|
* §1). Pure function: `{ assignment, freshHoldersList, selfActor, nowMs }` -> one of five
|
|
@@ -572,7 +626,19 @@ export function performLocalReleaseUnderLock(artifactRoot, subjectId, releasedBy
|
|
|
572
626
|
// seam, relocated to this write path).
|
|
573
627
|
const holderActorKey = existing.actor_key || helper.serializeActor(existing.actor);
|
|
574
628
|
const releasedByActorKey = opts.actorKey || helper.serializeActor(releasedBy);
|
|
575
|
-
|
|
629
|
+
// Pre-3.7 lifecycle events could persist the derived ancestry actor before
|
|
630
|
+
// sanitizeSegment removed ':' separators. Modern explicit/env release paths
|
|
631
|
+
// always use the sanitized form. Accept only that one-way legacy migration;
|
|
632
|
+
// never normalize two modern keys or relax ownership to a prefix match.
|
|
633
|
+
const sameActorStruct = existing.actor.runtime === releasedBy.runtime
|
|
634
|
+
&& existing.actor.session_id === releasedBy.session_id
|
|
635
|
+
&& existing.actor.host === releasedBy.host
|
|
636
|
+
&& (existing.actor.human ?? null) === (releasedBy.human ?? null);
|
|
637
|
+
const legacyActorKeyMatches = holderActorKey.includes(":")
|
|
638
|
+
&& holderActorKey === helper.serializeActor(existing.actor)
|
|
639
|
+
&& helper.sanitizeSegment(holderActorKey) === releasedByActorKey
|
|
640
|
+
&& sameActorStruct;
|
|
641
|
+
if (holderActorKey !== releasedByActorKey && !legacyActorKeyMatches) {
|
|
576
642
|
if (tolerateNoActiveClaim)
|
|
577
643
|
return null;
|
|
578
644
|
throw new Error(`--actor-json does not match the current holder (${holderActorKey}); refusing to release a claim held by someone else`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { flagString, parseArgs } from "../lib/args.js";
|
|
2
|
-
import { cancelBuilderFlowSession, archiveBuilderFlowSession, pauseBuilderFlowSession, recoverBuilderFlowSession, releaseBuilderFlowAssignment, resumeBuilderFlowSession,
|
|
3
|
-
const USAGE = "Usage: flow-agents builder-run <
|
|
2
|
+
import { cancelBuilderFlowSession, archiveBuilderFlowSession, pauseBuilderFlowSession, recoverBuilderFlowSession, releaseBuilderFlowAssignment, resumeBuilderFlowSession, } from "../builder-flow-runtime.js";
|
|
3
|
+
const USAGE = "Usage: flow-agents builder-run <recover|pause|resume|cancel|release-assignment|archive> --session-dir <path> [--reason <text> | --authorization-file <path>]";
|
|
4
4
|
export async function main(argv) {
|
|
5
5
|
const parsed = parseArgs(argv);
|
|
6
6
|
const action = parsed.positionals[0];
|
|
@@ -18,7 +18,7 @@ export async function main(argv) {
|
|
|
18
18
|
console.error("builder-run requires --session-dir .kontourai/flow-agents/<slug>");
|
|
19
19
|
return 64;
|
|
20
20
|
}
|
|
21
|
-
if (!action || !["
|
|
21
|
+
if (!action || !["recover", "pause", "resume", "cancel", "release-assignment", "archive"].includes(action)) {
|
|
22
22
|
console.error(USAGE);
|
|
23
23
|
return 64;
|
|
24
24
|
}
|
|
@@ -42,21 +42,17 @@ export async function main(argv) {
|
|
|
42
42
|
console.error(USAGE);
|
|
43
43
|
return 64;
|
|
44
44
|
}
|
|
45
|
-
const result = action === "
|
|
46
|
-
? await
|
|
47
|
-
: action === "
|
|
48
|
-
? await
|
|
49
|
-
: action === "
|
|
50
|
-
? await
|
|
51
|
-
: action === "
|
|
52
|
-
? await
|
|
53
|
-
: action === "
|
|
54
|
-
? await
|
|
55
|
-
:
|
|
56
|
-
? await cancelBuilderFlowSession({ sessionDir, authorizationFile: authorizationFile })
|
|
57
|
-
: action === "release-assignment"
|
|
58
|
-
? await releaseBuilderFlowAssignment({ sessionDir, reason: reason })
|
|
59
|
-
: await archiveBuilderFlowSession({ sessionDir, authorizationFile: authorizationFile });
|
|
45
|
+
const result = action === "recover"
|
|
46
|
+
? await recoverBuilderFlowSession({ sessionDir })
|
|
47
|
+
: action === "pause"
|
|
48
|
+
? await pauseBuilderFlowSession({ sessionDir, reason: reason })
|
|
49
|
+
: action === "resume"
|
|
50
|
+
? await resumeBuilderFlowSession({ sessionDir, reason: reason })
|
|
51
|
+
: action === "cancel"
|
|
52
|
+
? await cancelBuilderFlowSession({ sessionDir, authorizationFile: authorizationFile })
|
|
53
|
+
: action === "release-assignment"
|
|
54
|
+
? await releaseBuilderFlowAssignment({ sessionDir, reason: reason })
|
|
55
|
+
: await archiveBuilderFlowSession({ sessionDir, authorizationFile: authorizationFile });
|
|
60
56
|
console.log(JSON.stringify({
|
|
61
57
|
run_id: result.run.runId,
|
|
62
58
|
definition_id: result.run.definitionId,
|
|
@@ -174,10 +174,13 @@ export declare function reduceCaptureLogByCommand(commandLog: AnyObj[] | undefin
|
|
|
174
174
|
* @param timestamp ISO-8601 timestamp for createdAt / updatedAt / observedAt
|
|
175
175
|
* @param checks Normalized check objects (from record-evidence --check-json / --surface-trust-json)
|
|
176
176
|
* @param criteria Acceptance criteria objects (from acceptance.json .criteria array)
|
|
177
|
-
* @param critiques Critique objects
|
|
177
|
+
* @param critiques Critique objects reconstructed from trust.bundle claims
|
|
178
178
|
* @param commandLog Optional parsed command-log.jsonl entries (capture-authoritative fold)
|
|
179
179
|
*/
|
|
180
|
-
export declare function buildTrustBundle(slug: string, timestamp: string, checks: AnyObj[], criteria: AnyObj[], critiques: AnyObj[], commandLog?: AnyObj[], flowAgentsDir?: string, actorKey?: string
|
|
180
|
+
export declare function buildTrustBundle(slug: string, timestamp: string, checks: AnyObj[], criteria: AnyObj[], critiques: AnyObj[], commandLog?: AnyObj[], flowAgentsDir?: string, actorKey?: string, exactFlowContext?: {
|
|
181
|
+
flowId: string;
|
|
182
|
+
stepId: string;
|
|
183
|
+
}): Promise<AnyObj | null>;
|
|
181
184
|
/**
|
|
182
185
|
* Fail-open wrapper: builds (via Surface), validates, and writes a trust.bundle.
|
|
183
186
|
* Accepts raw check/criterion/critique inputs directly (ADR 0010 Phase 4a).
|
|
@@ -191,7 +194,10 @@ export declare function buildTrustBundle(slug: string, timestamp: string, checks
|
|
|
191
194
|
* @param criteria Acceptance criteria objects (same as buildTrustBundle)
|
|
192
195
|
* @param critiques Critique objects (same as buildTrustBundle)
|
|
193
196
|
*/
|
|
194
|
-
export declare function writeTrustBundle(dir: string, slug: string, timestamp: string, checks: AnyObj[], criteria: AnyObj[], critiques: AnyObj[], actorKey?: string
|
|
197
|
+
export declare function writeTrustBundle(dir: string, slug: string, timestamp: string, checks: AnyObj[], criteria: AnyObj[], critiques: AnyObj[], actorKey?: string, exactFlowContext?: {
|
|
198
|
+
flowId: string;
|
|
199
|
+
stepId: string;
|
|
200
|
+
}): Promise<{
|
|
195
201
|
written: boolean;
|
|
196
202
|
errors: string[];
|
|
197
203
|
}>;
|
|
@@ -199,6 +205,23 @@ export declare function sidecarBase(slug: string): AnyObj;
|
|
|
199
205
|
export declare function currentWorkflowSessionDir(root: string): string | null;
|
|
200
206
|
export declare function validateEvidenceRef(ref: AnyObj, label: string): AnyObj;
|
|
201
207
|
export declare function normalizeEvidenceRefs(raw: unknown, label: string): AnyObj[];
|
|
208
|
+
/** Validate test-evidence command shape without executing it. */
|
|
209
|
+
type TestExecutionProof = {
|
|
210
|
+
kind: "local-process-exit";
|
|
211
|
+
runner: string;
|
|
212
|
+
static_test_units: number;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Produce evidence from the locally executed command and statically reviewable
|
|
216
|
+
* test units. Runner stdout is deliberately excluded: any executable can print
|
|
217
|
+
* a Vitest/Jest-looking success summary, but it cannot turn a non-test script
|
|
218
|
+
* into a supported test workflow or supply this locally-created proof.
|
|
219
|
+
*/
|
|
220
|
+
export declare function testExecutionProof(command: string, projectRoot: string, seenScripts?: Set<string>, packageScriptBody?: boolean): TestExecutionProof | null;
|
|
221
|
+
/** Validate test-evidence command shape without executing it. */
|
|
222
|
+
export declare function isMeaningfulTestCommand(command: string, projectRoot: string, seenScripts?: Set<string>, packageScriptBody?: boolean): boolean;
|
|
223
|
+
export declare function observedExecutedTestCount(output: string): number;
|
|
224
|
+
export declare function inferExecutedTestCount(command: string, projectRoot: string, output: string, seenScripts?: Set<string>): number;
|
|
202
225
|
export declare function normalizeCheck(raw: AnyObj, allowGateClaimPrefix?: boolean, existingCheckStampById?: ReadonlyMap<string, boolean>): AnyObj;
|
|
203
226
|
/**
|
|
204
227
|
* Derive kit identity from a parsed trust.bundle by structurally reading the
|
|
@@ -624,4 +647,5 @@ export declare function buildGateInquiryRecords(bundle: BundleFile, blockSignal:
|
|
|
624
647
|
export declare const LIVENESS_TERMINAL: Set<string>;
|
|
625
648
|
export { buildClaimExplanation } from "./sidecar-claim-explain.js";
|
|
626
649
|
export type { ClaimEvidenceItem, ClaimExplanation } from "./sidecar-claim-explain.js";
|
|
627
|
-
export declare function
|
|
650
|
+
export declare function mainFromPublicWorkflow(argv: string[]): Promise<number>;
|
|
651
|
+
export declare function main(argv?: string[], authority?: symbol): Promise<number>;
|