@kontourai/flow-agents 2.3.0 → 2.4.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/.github/CODEOWNERS +8 -0
- package/.github/workflows/ci.yml +32 -0
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +39 -0
- package/CONTEXT.md +14 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +22 -6
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +792 -69
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +23 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +38 -7
- package/context/contracts/builder-kit-workflow-state-contract.md +3 -2
- package/context/contracts/decision-registry-contract.md +263 -0
- package/context/contracts/delivery-contract.md +1 -1
- package/context/contracts/planning-contract.md +2 -1
- package/context/contracts/review-contract.md +5 -3
- package/context/contracts/verification-contract.md +9 -1
- package/context/contracts/work-item-contract.md +1 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +283 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +9 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +14 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +3 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +1 -1
- package/docs/workflow-usage-guide.md +254 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +65 -1
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +2 -2
- package/evals/integration/test_pull_work_liveness_preflight.sh +386 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +4 -4
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +2 -2
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +151 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +723 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +22 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +56 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +13 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +80 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +8 -4
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +436 -79
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +22 -6
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +795 -71
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +23 -1
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
export interface KitDependencyEntry {
|
|
2
|
+
kit_id: string;
|
|
3
|
+
reason?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parse and shape-validate a kit manifest's `dependencies` field (Flow Agents
|
|
7
|
+
* extension-layer metadata; see docs/adr/0019-kit-dependency-ownership.md).
|
|
8
|
+
*
|
|
9
|
+
* Shape rules:
|
|
10
|
+
* - `dependencies` (if present) must be an array.
|
|
11
|
+
* - each entry must be an object with a `kit_id` string matching ^[a-z][a-z0-9-]*$.
|
|
12
|
+
* - `kit_id` must not equal the declaring kit's own id (no self-reference).
|
|
13
|
+
* - no duplicate `kit_id` across entries.
|
|
14
|
+
* - `reason` is an optional string.
|
|
15
|
+
*
|
|
16
|
+
* Returns the parsed entries plus any shape errors (empty errors = valid). This is
|
|
17
|
+
* a sibling shape check, not a member of the file-path-oriented EXTENSION_ASSET_CLASSES
|
|
18
|
+
* loop, because dependency entries have no `path`/file to check.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseKitDependencies(manifest: Record<string, unknown>, manifestPath: string): {
|
|
21
|
+
entries: KitDependencyEntry[];
|
|
22
|
+
errors: string[];
|
|
23
|
+
};
|
|
1
24
|
export type KitTargetConsumer = "flow" | "flow-agents" | string;
|
|
2
25
|
export interface KitConformanceLevel {
|
|
3
26
|
/** K0: valid core Flow Kit container with at least one flow (gates evaluable agentlessly). */
|
|
@@ -7,6 +7,66 @@ const EXTENSION_ASSET_CLASSES = ["skills", "docs", "adapters", "evals", "assets"
|
|
|
7
7
|
// agent-extension fields are skills, docs, adapters, evals, assets.
|
|
8
8
|
const CORE_CONTAINER_FIELDS = new Set(["schema_version", "id", "name", "description", "product_name", "flows"]);
|
|
9
9
|
const AGENT_EXTENSION_CLASSES = new Set(["skills", "docs", "adapters", "evals", "assets"]);
|
|
10
|
+
// Flow Agents-recognized metadata fields that are neither core container fields nor
|
|
11
|
+
// agent-extension asset classes. Recognized here so they are never misreported as
|
|
12
|
+
// unknown third-party extension namespaces. `dependencies` declares cross-kit skill
|
|
13
|
+
// dependencies (extension-layer ownership; see docs/adr/0019-kit-dependency-ownership.md).
|
|
14
|
+
const KNOWN_METADATA_FIELDS = new Set(["dependencies"]);
|
|
15
|
+
/**
|
|
16
|
+
* Parse and shape-validate a kit manifest's `dependencies` field (Flow Agents
|
|
17
|
+
* extension-layer metadata; see docs/adr/0019-kit-dependency-ownership.md).
|
|
18
|
+
*
|
|
19
|
+
* Shape rules:
|
|
20
|
+
* - `dependencies` (if present) must be an array.
|
|
21
|
+
* - each entry must be an object with a `kit_id` string matching ^[a-z][a-z0-9-]*$.
|
|
22
|
+
* - `kit_id` must not equal the declaring kit's own id (no self-reference).
|
|
23
|
+
* - no duplicate `kit_id` across entries.
|
|
24
|
+
* - `reason` is an optional string.
|
|
25
|
+
*
|
|
26
|
+
* Returns the parsed entries plus any shape errors (empty errors = valid). This is
|
|
27
|
+
* a sibling shape check, not a member of the file-path-oriented EXTENSION_ASSET_CLASSES
|
|
28
|
+
* loop, because dependency entries have no `path`/file to check.
|
|
29
|
+
*/
|
|
30
|
+
export function parseKitDependencies(manifest, manifestPath) {
|
|
31
|
+
const entries = [];
|
|
32
|
+
const errors = [];
|
|
33
|
+
const raw = manifest.dependencies;
|
|
34
|
+
if (raw === undefined)
|
|
35
|
+
return { entries, errors };
|
|
36
|
+
if (!Array.isArray(raw)) {
|
|
37
|
+
errors.push(`${manifestPath}: .dependencies must be a list`);
|
|
38
|
+
return { entries, errors };
|
|
39
|
+
}
|
|
40
|
+
const ownId = typeof manifest.id === "string" ? manifest.id : "";
|
|
41
|
+
const seen = new Set();
|
|
42
|
+
raw.forEach((entry, index) => {
|
|
43
|
+
if (typeof entry !== "object" || entry === null) {
|
|
44
|
+
errors.push(`${manifestPath}: dependencies[${index}] must be an object`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const record = entry;
|
|
48
|
+
const kitId = record.kit_id;
|
|
49
|
+
if (typeof kitId !== "string" || !/^[a-z][a-z0-9-]*$/.test(kitId)) {
|
|
50
|
+
errors.push(`${manifestPath}: dependencies[${index}].kit_id must be a kebab-case kit id (^[a-z][a-z0-9-]*$)`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (ownId && kitId === ownId) {
|
|
54
|
+
errors.push(`${manifestPath}: dependencies[${index}].kit_id must not reference the declaring kit itself ('${kitId}')`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (seen.has(kitId)) {
|
|
58
|
+
errors.push(`${manifestPath}: dependencies[${index}].kit_id duplicates '${kitId}'`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
seen.add(kitId);
|
|
62
|
+
if (record.reason !== undefined && typeof record.reason !== "string") {
|
|
63
|
+
errors.push(`${manifestPath}: dependencies[${index}].reason must be a string when present`);
|
|
64
|
+
}
|
|
65
|
+
const reason = typeof record.reason === "string" ? record.reason : undefined;
|
|
66
|
+
entries.push({ kit_id: kitId, ...(reason ? { reason } : {}) });
|
|
67
|
+
});
|
|
68
|
+
return { entries, errors };
|
|
69
|
+
}
|
|
10
70
|
/**
|
|
11
71
|
* Allowlist of kit IDs that Kontour authors, tests, and ships with the flow-agents package.
|
|
12
72
|
*
|
|
@@ -106,7 +166,7 @@ export async function deriveKitTargets(manifest, kitDir = "") {
|
|
|
106
166
|
// Detect third-party extension namespaces: top-level keys that are neither
|
|
107
167
|
// core fields nor Flow Agents extension classes.
|
|
108
168
|
const thirdPartyExtensions = Object.keys(manifest)
|
|
109
|
-
.filter((key) => !CORE_CONTAINER_FIELDS.has(key) && !AGENT_EXTENSION_CLASSES.has(key))
|
|
169
|
+
.filter((key) => !CORE_CONTAINER_FIELDS.has(key) && !AGENT_EXTENSION_CLASSES.has(key) && !KNOWN_METADATA_FIELDS.has(key))
|
|
110
170
|
.sort();
|
|
111
171
|
const targets = [];
|
|
112
172
|
if (k0)
|
|
@@ -187,6 +247,12 @@ export async function validateKitRepository(kitDir) {
|
|
|
187
247
|
}
|
|
188
248
|
});
|
|
189
249
|
}
|
|
250
|
+
// Flow Agents metadata: cross-kit dependency declarations (extension-layer;
|
|
251
|
+
// see docs/adr/0019-kit-dependency-ownership.md). Shape-only here — presence is
|
|
252
|
+
// checked separately (non-blocking at install, hard error at activation).
|
|
253
|
+
const depResult = parseKitDependencies(manifest, manifestPath);
|
|
254
|
+
for (const err of depResult.errors)
|
|
255
|
+
errors.push(err);
|
|
190
256
|
return errors;
|
|
191
257
|
}
|
|
192
258
|
export async function assertKitRepository(kitDir) {
|
package/build/src/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { defaultArtifactRootForRead, defaultTelemetryDirForRead, defaultTelemetryDirsForRead,
|
|
1
|
+
export { defaultArtifactRootForRead, defaultCodexHome, defaultTelemetryDirForRead, defaultTelemetryDirsForRead, durableFlowAgentsRoot, durableInstallRecordPath, DURABLE_FLOW_AGENTS_DIR, FLOW_AGENTS_RUNTIME_DIR, FLOW_AGENTS_RUNTIME_SUBDIR, firstExistingPath, flowAgentsArtifactRoot, KONTOURAI_DIR, legacyTelemetryDataDir, LEGACY_TELEMETRY_DIR, telemetryDataDir, } from "./lib/local-artifact-root.js";
|
|
2
2
|
export { validateTrustBundle, normalizeCheck, normalizeFinding, normalizeLearning, normalizeEvidenceRefs, validateEvidenceRef, validateLearningCorrection, loadJson, writeJson, appendJsonl, sidecarBase, writeState, statuses, phases, checkKinds, checkStatuses, verdicts, } from "./cli/workflow-sidecar.js";
|
|
3
3
|
/** Read a sidecar JSON file from a workflow artifact directory; returns `{}` if absent. */
|
|
4
4
|
export declare function readSidecar(dir: string, name: string): Record<string, any>;
|
package/build/src/index.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
import { loadJson as _loadJson, writeJson as _writeJson } from "./cli/workflow-sidecar.js";
|
|
18
|
-
export { defaultArtifactRootForRead, defaultTelemetryDirForRead, defaultTelemetryDirsForRead,
|
|
18
|
+
export { defaultArtifactRootForRead, defaultCodexHome, defaultTelemetryDirForRead, defaultTelemetryDirsForRead, durableFlowAgentsRoot, durableInstallRecordPath, DURABLE_FLOW_AGENTS_DIR, FLOW_AGENTS_RUNTIME_DIR, FLOW_AGENTS_RUNTIME_SUBDIR, firstExistingPath, flowAgentsArtifactRoot, KONTOURAI_DIR, legacyTelemetryDataDir, LEGACY_TELEMETRY_DIR, telemetryDataDir, } from "./lib/local-artifact-root.js";
|
|
19
19
|
export {
|
|
20
20
|
// Trust-bundle (Hachure) validation — the same validator the writer uses.
|
|
21
21
|
validateTrustBundle,
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Returns the validated absolute file path, or null when:
|
|
19
19
|
* - kitId or flowName contains chars outside SLUG_RE (rejects traversal)
|
|
20
|
-
* - FLOW_AGENTS_FLOW_DEFS_DIR resolves into a
|
|
20
|
+
* - FLOW_AGENTS_FLOW_DEFS_DIR resolves into a runtime artifact directory
|
|
21
21
|
* - The resolved path escapes the expected root (belt-and-suspenders)
|
|
22
22
|
*
|
|
23
|
-
* When the override is unsafe
|
|
24
|
-
*
|
|
23
|
+
* When the override is unsafe, it is ignored and the resolver uses the
|
|
24
|
+
* canonical repoRoot/kits/ source for legitimate flows.
|
|
25
25
|
*/
|
|
26
26
|
export declare function resolveFlowFilePath(kitId: string, flowName: string, flowId: string, repoRoot: string): string | null;
|
|
27
27
|
/** A single gate expectation from a FlowDefinition expects[] entry. */
|
|
@@ -41,6 +41,8 @@ export type ActiveFlowStep = {
|
|
|
41
41
|
stepId: string;
|
|
42
42
|
gateId: string;
|
|
43
43
|
gateExpects: GateExpectation[];
|
|
44
|
+
/** When resolved through a parent step's uses_flow edge, names the child FlowDefinition that owns the gate. */
|
|
45
|
+
sourceFlowId?: string;
|
|
44
46
|
};
|
|
45
47
|
/**
|
|
46
48
|
* Resolve the gate expects[] for a specific (flowId, stepId) pair.
|
|
@@ -76,7 +78,7 @@ export declare function resolvePhaseMap(flowId: string, repoRoot: string): Recor
|
|
|
76
78
|
* with a fallback to process.cwd(). This handles temp dirs, CI workspaces, and
|
|
77
79
|
* subproject layouts without hardcoding the repo structure.
|
|
78
80
|
*
|
|
79
|
-
* @param flowAgentsDir Path to the
|
|
81
|
+
* @param flowAgentsDir Path to the runtime artifact root directory (contains current.json).
|
|
80
82
|
* @returns ActiveFlowStep or null when fields are absent or resolution fails.
|
|
81
83
|
*/
|
|
82
84
|
export declare function resolveActiveFlowStep(flowAgentsDir: string): ActiveFlowStep | null;
|
|
@@ -18,9 +18,9 @@ import * as path from "node:path";
|
|
|
18
18
|
//
|
|
19
19
|
// Both kitId and flowName originate from agent-writable sources (active_flow_id
|
|
20
20
|
// in current.json, and FLOW_AGENTS_FLOW_DEFS_DIR set by the runtime). A crafted
|
|
21
|
-
// value like "builder.../../../.flow-agents/slug/fake-flow" produces:
|
|
21
|
+
// value like "builder.../../../.kontourai/flow-agents/slug/fake-flow" produces:
|
|
22
22
|
// kitId = "builder"
|
|
23
|
-
// flowName = "../../../.flow-agents/slug/fake-flow"
|
|
23
|
+
// flowName = "../../../.kontourai/flow-agents/slug/fake-flow"
|
|
24
24
|
// which resolves OUTSIDE kits/ via path.join traversal.
|
|
25
25
|
//
|
|
26
26
|
// SLUG_RE closes this: it rejects any value containing path separators, dots,
|
|
@@ -32,23 +32,36 @@ import * as path from "node:path";
|
|
|
32
32
|
/** Strict slug pattern — allows only URL-safe identifier chars. */
|
|
33
33
|
const SLUG_RE = /^[a-zA-Z0-9_-]+$/;
|
|
34
34
|
/**
|
|
35
|
-
* Returns true when the given resolved absolute path falls within a
|
|
36
|
-
* directory (an agent-writable area). Used to reject FLOW_AGENTS_FLOW_DEFS_DIR
|
|
35
|
+
* Returns true when the given resolved absolute path falls within a Flow Agents
|
|
36
|
+
* runtime artifact directory (an agent-writable area). Used to reject FLOW_AGENTS_FLOW_DEFS_DIR
|
|
37
37
|
* overrides that point into agent-controlled storage.
|
|
38
38
|
*/
|
|
39
|
+
function hasAgentWritableRuntimeSegment(resolvedDir) {
|
|
40
|
+
const parts = resolvedDir.split(path.sep);
|
|
41
|
+
if (parts.includes(".flow-agents"))
|
|
42
|
+
return true;
|
|
43
|
+
return parts.some((part, index) => part === ".kontourai" && parts[index + 1] === "flow-agents");
|
|
44
|
+
}
|
|
39
45
|
function isAgentWritableDir(resolvedDir) {
|
|
40
|
-
|
|
46
|
+
if (hasAgentWritableRuntimeSegment(resolvedDir))
|
|
47
|
+
return true;
|
|
48
|
+
try {
|
|
49
|
+
return hasAgentWritableRuntimeSegment(fs.realpathSync.native(resolvedDir));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
55
|
/**
|
|
43
56
|
* Build and validate the FlowDefinition file path.
|
|
44
57
|
*
|
|
45
58
|
* Returns the validated absolute file path, or null when:
|
|
46
59
|
* - kitId or flowName contains chars outside SLUG_RE (rejects traversal)
|
|
47
|
-
* - FLOW_AGENTS_FLOW_DEFS_DIR resolves into a
|
|
60
|
+
* - FLOW_AGENTS_FLOW_DEFS_DIR resolves into a runtime artifact directory
|
|
48
61
|
* - The resolved path escapes the expected root (belt-and-suspenders)
|
|
49
62
|
*
|
|
50
|
-
* When the override is unsafe
|
|
51
|
-
*
|
|
63
|
+
* When the override is unsafe, it is ignored and the resolver uses the
|
|
64
|
+
* canonical repoRoot/kits/ source for legitimate flows.
|
|
52
65
|
*/
|
|
53
66
|
export function resolveFlowFilePath(kitId, flowName, flowId, repoRoot) {
|
|
54
67
|
// Primary defense: reject any slug containing traversal chars or non-identifier chars.
|
|
@@ -60,8 +73,8 @@ export function resolveFlowFilePath(kitId, flowName, flowId, repoRoot) {
|
|
|
60
73
|
if (override) {
|
|
61
74
|
const resolvedOverride = path.resolve(override);
|
|
62
75
|
if (isAgentWritableDir(resolvedOverride)) {
|
|
63
|
-
// Override targets an agent-writable
|
|
64
|
-
//
|
|
76
|
+
// Override targets an agent-writable runtime path; ignore it and use
|
|
77
|
+
// the canonical kit root. The session will resolve the real kit flow.
|
|
65
78
|
expectedRoot = path.resolve(repoRoot, "kits");
|
|
66
79
|
flowFilePath = path.join(repoRoot, "kits", kitId, "flows", `${flowName}.flow.json`);
|
|
67
80
|
}
|
|
@@ -83,7 +96,47 @@ export function resolveFlowFilePath(kitId, flowName, flowId, repoRoot) {
|
|
|
83
96
|
if (!resolvedPath.startsWith(expectedRoot + path.sep) && resolvedPath !== expectedRoot) {
|
|
84
97
|
return null; // traversal still detected — paranoid fallback
|
|
85
98
|
}
|
|
86
|
-
|
|
99
|
+
// If the file exists, resolve final symlinks before returning a readable path.
|
|
100
|
+
// `readFileSync` follows symlinks; this keeps lexical containment from turning
|
|
101
|
+
// into an out-of-root file read through a symlinked FlowDefinition.
|
|
102
|
+
try {
|
|
103
|
+
const realExpectedRoot = fs.existsSync(expectedRoot) ? fs.realpathSync.native(expectedRoot) : expectedRoot;
|
|
104
|
+
const realPath = fs.realpathSync.native(resolvedPath);
|
|
105
|
+
if (!realPath.startsWith(realExpectedRoot + path.sep) && realPath !== realExpectedRoot) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return realPath;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return resolvedPath;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function flowIdParts(flowId) {
|
|
115
|
+
if (!flowId)
|
|
116
|
+
return null;
|
|
117
|
+
const dotIdx = flowId.indexOf(".");
|
|
118
|
+
if (dotIdx < 1)
|
|
119
|
+
return null;
|
|
120
|
+
const kitId = flowId.slice(0, dotIdx);
|
|
121
|
+
const flowName = flowId.slice(dotIdx + 1);
|
|
122
|
+
if (!kitId || !flowName)
|
|
123
|
+
return null;
|
|
124
|
+
return { kitId, flowName };
|
|
125
|
+
}
|
|
126
|
+
function readFlowDefinition(flowId, repoRoot) {
|
|
127
|
+
const parts = flowIdParts(flowId);
|
|
128
|
+
if (!parts)
|
|
129
|
+
return null;
|
|
130
|
+
const flowFilePath = resolveFlowFilePath(parts.kitId, parts.flowName, flowId, repoRoot);
|
|
131
|
+
if (!flowFilePath)
|
|
132
|
+
return null;
|
|
133
|
+
try {
|
|
134
|
+
const raw = fs.readFileSync(flowFilePath, "utf8");
|
|
135
|
+
return JSON.parse(raw);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null; // ENOENT, permission error, or parse error → fail-open
|
|
139
|
+
}
|
|
87
140
|
}
|
|
88
141
|
/**
|
|
89
142
|
* Resolve the gate expects[] for a specific (flowId, stepId) pair.
|
|
@@ -95,41 +148,73 @@ export function resolveFlowFilePath(kitId, flowName, flowId, repoRoot) {
|
|
|
95
148
|
* @returns ActiveFlowStep with the matched gate's expects[], or null on any error.
|
|
96
149
|
*/
|
|
97
150
|
export function resolveFlowStep(flowId, stepId, repoRoot) {
|
|
151
|
+
const resolved = resolveFlowStepInternal(flowId, stepId, repoRoot, new Set());
|
|
152
|
+
if (!resolved)
|
|
153
|
+
return null;
|
|
154
|
+
const { flowExports: _flowExports, ...publicStep } = resolved;
|
|
155
|
+
return publicStep;
|
|
156
|
+
}
|
|
157
|
+
function expectationExportKeys(expectation) {
|
|
158
|
+
const keys = [];
|
|
159
|
+
if (typeof expectation.id === "string" && expectation.id)
|
|
160
|
+
keys.push(expectation.id);
|
|
161
|
+
const claimType = expectation.bundle_claim?.claimType;
|
|
162
|
+
if (typeof claimType === "string" && claimType)
|
|
163
|
+
keys.push(claimType);
|
|
164
|
+
return keys;
|
|
165
|
+
}
|
|
166
|
+
function exportedExpectations(expectations, exportsList) {
|
|
167
|
+
if (!Array.isArray(exportsList))
|
|
168
|
+
return null;
|
|
169
|
+
const exported = new Set(exportsList.filter((item) => typeof item === "string" && item.length > 0));
|
|
170
|
+
const allowed = expectations.filter((expectation) => expectationExportKeys(expectation).some((key) => exported.has(key)));
|
|
171
|
+
return allowed.length === expectations.length ? allowed : null;
|
|
172
|
+
}
|
|
173
|
+
function resolveFlowStepInternal(flowId, stepId, repoRoot, seen) {
|
|
98
174
|
if (!flowId || !stepId)
|
|
99
175
|
return null;
|
|
100
|
-
|
|
101
|
-
if (dotIdx < 1)
|
|
102
|
-
return null; // flowId must have at least one "." to derive kitId
|
|
103
|
-
const kitId = flowId.slice(0, dotIdx);
|
|
104
|
-
// The flow filename is the part after the first "." (e.g. "build" from "builder.build")
|
|
105
|
-
const flowName = flowId.slice(dotIdx + 1);
|
|
106
|
-
if (!kitId || !flowName)
|
|
176
|
+
if (!flowIdParts(flowId))
|
|
107
177
|
return null;
|
|
108
178
|
// Layer 1 defense: validate stepId too — it is matched against gate.step values but
|
|
109
179
|
// still originates from agent-writable current.json active_step_id.
|
|
110
180
|
if (!SLUG_RE.test(stepId))
|
|
111
181
|
return null;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const flowFilePath = resolveFlowFilePath(kitId, flowName, flowId, repoRoot);
|
|
115
|
-
if (!flowFilePath)
|
|
182
|
+
const seenKey = `${flowId}:${stepId}`;
|
|
183
|
+
if (seen.has(seenKey))
|
|
116
184
|
return null;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
catch {
|
|
123
|
-
return null; // ENOENT, permission error, or parse error → fail-open
|
|
124
|
-
}
|
|
125
|
-
if (!flowDef || typeof flowDef !== "object" || !flowDef.gates)
|
|
185
|
+
seen.add(seenKey);
|
|
186
|
+
const flowDef = readFlowDefinition(flowId, repoRoot);
|
|
187
|
+
if (!flowDef)
|
|
188
|
+
return null;
|
|
189
|
+
if (!flowDef || typeof flowDef !== "object")
|
|
126
190
|
return null;
|
|
127
191
|
// Find the gate whose .step matches stepId.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
192
|
+
if (flowDef.gates) {
|
|
193
|
+
for (const [gateId, gate] of Object.entries(flowDef.gates)) {
|
|
194
|
+
if (!gate || gate.step !== stepId)
|
|
195
|
+
continue;
|
|
196
|
+
const expects = Array.isArray(gate.expects) ? gate.expects : [];
|
|
197
|
+
return { flowId, stepId, gateId, gateExpects: expects, flowExports: flowDef.exports };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const composedStep = Array.isArray(flowDef.steps)
|
|
201
|
+
? flowDef.steps.find((step) => step && step.id === stepId && typeof step.uses_flow === "string" && step.uses_flow.trim())
|
|
202
|
+
: null;
|
|
203
|
+
if (composedStep?.uses_flow) {
|
|
204
|
+
const child = resolveFlowStepInternal(composedStep.uses_flow, stepId, repoRoot, seen);
|
|
205
|
+
if (child) {
|
|
206
|
+
const childGateExpects = exportedExpectations(child.gateExpects, child.flowExports);
|
|
207
|
+
if (!childGateExpects)
|
|
208
|
+
return null;
|
|
209
|
+
return {
|
|
210
|
+
flowId,
|
|
211
|
+
stepId,
|
|
212
|
+
gateId: `${child.flowId}:${child.gateId}`,
|
|
213
|
+
gateExpects: childGateExpects,
|
|
214
|
+
sourceFlowId: child.flowId,
|
|
215
|
+
flowExports: flowDef.exports,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
133
218
|
}
|
|
134
219
|
return null; // no gate matched the given stepId
|
|
135
220
|
}
|
|
@@ -148,27 +233,9 @@ export function resolveFlowStep(flowId, stepId, repoRoot) {
|
|
|
148
233
|
* @returns Record<string,string> phase→stepId map, or null on absence/error.
|
|
149
234
|
*/
|
|
150
235
|
export function resolvePhaseMap(flowId, repoRoot) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const dotIdx = flowId.indexOf(".");
|
|
154
|
-
if (dotIdx < 1)
|
|
155
|
-
return null;
|
|
156
|
-
const kitId = flowId.slice(0, dotIdx);
|
|
157
|
-
const flowName = flowId.slice(dotIdx + 1);
|
|
158
|
-
if (!kitId || !flowName)
|
|
236
|
+
const flowDef = readFlowDefinition(flowId, repoRoot);
|
|
237
|
+
if (!flowDef)
|
|
159
238
|
return null;
|
|
160
|
-
// Layer 1 defense: same slug validation + path containment as resolveFlowStep.
|
|
161
|
-
const flowFilePath = resolveFlowFilePath(kitId, flowName, flowId, repoRoot);
|
|
162
|
-
if (!flowFilePath)
|
|
163
|
-
return null;
|
|
164
|
-
let flowDef;
|
|
165
|
-
try {
|
|
166
|
-
const raw = fs.readFileSync(flowFilePath, "utf8");
|
|
167
|
-
flowDef = JSON.parse(raw);
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
return null; // ENOENT, permission error, or parse error → fail-open
|
|
171
|
-
}
|
|
172
239
|
if (!flowDef || typeof flowDef !== "object")
|
|
173
240
|
return null;
|
|
174
241
|
const pm = flowDef.phase_map;
|
|
@@ -186,7 +253,7 @@ export function resolvePhaseMap(flowId, repoRoot) {
|
|
|
186
253
|
* the nearest ancestor that contains a `kits/` subdirectory. If none is found,
|
|
187
254
|
* falls back to `process.cwd()` so the default "run from repo root" case still works.
|
|
188
255
|
*
|
|
189
|
-
* This is required because the
|
|
256
|
+
* This is required because the runtime artifact directory can live anywhere (temp dirs,
|
|
190
257
|
* subprojects, CI workspaces) while the kits/ directory is always at the repo root.
|
|
191
258
|
*/
|
|
192
259
|
function findRepoRoot(startDir) {
|
|
@@ -212,7 +279,7 @@ function findRepoRoot(startDir) {
|
|
|
212
279
|
* with a fallback to process.cwd(). This handles temp dirs, CI workspaces, and
|
|
213
280
|
* subproject layouts without hardcoding the repo structure.
|
|
214
281
|
*
|
|
215
|
-
* @param flowAgentsDir Path to the
|
|
282
|
+
* @param flowAgentsDir Path to the runtime artifact root directory (contains current.json).
|
|
216
283
|
* @returns ActiveFlowStep or null when fields are absent or resolution fails.
|
|
217
284
|
*/
|
|
218
285
|
export function resolveActiveFlowStep(flowAgentsDir) {
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
export declare const KONTOURAI_DIR = ".kontourai";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const FLOW_AGENTS_RUNTIME_SUBDIR = "flow-agents";
|
|
3
|
+
export declare const FLOW_AGENTS_RUNTIME_DIR = ".kontourai/flow-agents";
|
|
4
|
+
export declare const DURABLE_FLOW_AGENTS_DIR = ".flow-agents";
|
|
3
5
|
export declare const LEGACY_TELEMETRY_DIR = ".telemetry";
|
|
6
|
+
/**
|
|
7
|
+
* Default Codex home: `$CODEX_HOME` when set, else `~/.codex`.
|
|
8
|
+
*
|
|
9
|
+
* This is the Codex CLI's own config/state root and is conceptually
|
|
10
|
+
* distinct from the Flow Agents global bundle install root (`~/.flow-agents`)
|
|
11
|
+
* and the durable per-destination install record root
|
|
12
|
+
* (`DURABLE_FLOW_AGENTS_DIR`, i.e. `.flow-agents`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function defaultCodexHome(): string;
|
|
4
15
|
export declare function flowAgentsArtifactRoot(cwd?: string): string;
|
|
5
|
-
export declare function
|
|
16
|
+
export declare function durableFlowAgentsRoot(cwd?: string): string;
|
|
17
|
+
export declare function durableInstallRecordPath(cwd?: string): string;
|
|
6
18
|
export declare function telemetryDataDir(cwd?: string): string;
|
|
7
19
|
export declare function legacyTelemetryDataDir(cwd?: string): string;
|
|
8
20
|
export declare function firstExistingPath(candidates: string[]): string;
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
export const KONTOURAI_DIR = ".kontourai";
|
|
4
|
-
export const
|
|
5
|
+
export const FLOW_AGENTS_RUNTIME_SUBDIR = "flow-agents";
|
|
6
|
+
export const FLOW_AGENTS_RUNTIME_DIR = `${KONTOURAI_DIR}/${FLOW_AGENTS_RUNTIME_SUBDIR}`;
|
|
7
|
+
export const DURABLE_FLOW_AGENTS_DIR = ".flow-agents";
|
|
5
8
|
export const LEGACY_TELEMETRY_DIR = ".telemetry";
|
|
9
|
+
/**
|
|
10
|
+
* Default Codex home: `$CODEX_HOME` when set, else `~/.codex`.
|
|
11
|
+
*
|
|
12
|
+
* This is the Codex CLI's own config/state root and is conceptually
|
|
13
|
+
* distinct from the Flow Agents global bundle install root (`~/.flow-agents`)
|
|
14
|
+
* and the durable per-destination install record root
|
|
15
|
+
* (`DURABLE_FLOW_AGENTS_DIR`, i.e. `.flow-agents`).
|
|
16
|
+
*/
|
|
17
|
+
export function defaultCodexHome() {
|
|
18
|
+
return process.env["CODEX_HOME"] || path.join(os.homedir(), ".codex");
|
|
19
|
+
}
|
|
6
20
|
export function flowAgentsArtifactRoot(cwd = process.cwd()) {
|
|
7
|
-
return path.resolve(cwd,
|
|
21
|
+
return path.resolve(cwd, FLOW_AGENTS_RUNTIME_DIR);
|
|
22
|
+
}
|
|
23
|
+
export function durableFlowAgentsRoot(cwd = process.cwd()) {
|
|
24
|
+
return path.resolve(cwd, DURABLE_FLOW_AGENTS_DIR);
|
|
8
25
|
}
|
|
9
|
-
export function
|
|
10
|
-
return path.
|
|
26
|
+
export function durableInstallRecordPath(cwd = process.cwd()) {
|
|
27
|
+
return path.join(durableFlowAgentsRoot(cwd), "install.json");
|
|
11
28
|
}
|
|
12
29
|
export function telemetryDataDir(cwd = process.cwd()) {
|
|
13
30
|
return path.resolve(cwd, KONTOURAI_DIR, "telemetry");
|
|
@@ -19,7 +36,7 @@ export function firstExistingPath(candidates) {
|
|
|
19
36
|
return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0];
|
|
20
37
|
}
|
|
21
38
|
export function defaultArtifactRootForRead(cwd = process.cwd()) {
|
|
22
|
-
return
|
|
39
|
+
return flowAgentsArtifactRoot(cwd);
|
|
23
40
|
}
|
|
24
41
|
export function defaultTelemetryDirForRead(cwd = process.cwd()) {
|
|
25
42
|
return firstExistingPath([telemetryDataDir(cwd), legacyTelemetryDataDir(cwd)]);
|
|
@@ -26,7 +26,7 @@ const KNOWN_CORRECTION_TYPES = new Set([
|
|
|
26
26
|
"provider",
|
|
27
27
|
"none",
|
|
28
28
|
]);
|
|
29
|
-
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history"]);
|
|
29
|
+
const SKIPPED_ROOT_ENTRIES = new Set(["archive", "changes", "delivery-history", "liveness"]);
|
|
30
30
|
const MAX_SIDECAR_BYTES = 1024 * 1024;
|
|
31
31
|
export function readWorkflowLearningSources(artifactRoot) {
|
|
32
32
|
const root = path.resolve(artifactRoot);
|
|
@@ -75,7 +75,7 @@ export function buildWorkflowLearningProjection(sources, options) {
|
|
|
75
75
|
sourceRef: {
|
|
76
76
|
product: "flow-agents",
|
|
77
77
|
kind: "workflow-learning",
|
|
78
|
-
id: ".flow-agents/*/learning.json",
|
|
78
|
+
id: ".kontourai/flow-agents/*/learning.json",
|
|
79
79
|
label: "Local workflow learning sidecars",
|
|
80
80
|
},
|
|
81
81
|
},
|
|
@@ -13,6 +13,18 @@ export type KitInventory = {
|
|
|
13
13
|
warnings: string[];
|
|
14
14
|
errors: string[];
|
|
15
15
|
};
|
|
16
|
+
/** A cross-kit dependency edge discovered while loading a kit manifest. */
|
|
17
|
+
export type KitDependencyRef = {
|
|
18
|
+
from_kit_id: string;
|
|
19
|
+
kit_id: string;
|
|
20
|
+
reason?: string;
|
|
21
|
+
};
|
|
22
|
+
/** The parsed result of a single kit manifest: its id, activatable assets, and declared dependencies. */
|
|
23
|
+
export type LoadedKit = {
|
|
24
|
+
kit_id: string;
|
|
25
|
+
assets: KitAsset[];
|
|
26
|
+
dependencies: KitDependencyRef[];
|
|
27
|
+
};
|
|
16
28
|
export declare function readKitInventory(sourceRoot: string, dest: string): KitInventory;
|
|
17
29
|
export declare function activateCodexLocal(sourceRoot: string, dest: string): Record<string, unknown>;
|
|
18
30
|
export declare function activateStrandsLocal(sourceRoot: string, dest: string): Record<string, unknown>;
|