@intentius/chant 0.49.0 → 0.51.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/dist/audit/catalog.d.ts +13 -3
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +9 -0
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +6 -0
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/fetch.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +6 -0
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +95 -0
- package/dist/audit/secrets.d.ts.map +1 -0
- package/dist/audit/wrangler.d.ts +33 -0
- package/dist/audit/wrangler.d.ts.map +1 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts +23 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts +31 -0
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts +11 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/op-progress.d.ts +57 -0
- package/dist/cli/handlers/op-progress.d.ts.map +1 -0
- package/dist/cli/handlers/operator.d.ts +32 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -0
- package/dist/cli/handlers/run-client.d.ts +21 -1
- package/dist/cli/handlers/run-client.d.ts.map +1 -1
- package/dist/cli/handlers/run-report.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/scenario.d.ts +39 -0
- package/dist/cli/handlers/scenario.d.ts.map +1 -0
- package/dist/cli/handlers/search.d.ts +22 -0
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts +35 -2
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/types.d.ts +29 -1
- package/dist/cli/mcp/types.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +47 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/docs-rule-scanning.d.ts.map +1 -1
- package/dist/components/capability.d.ts +17 -2
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +7 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +15 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +7 -5
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/index.d.ts +6 -1
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +499 -0
- package/dist/components/verbs/run-agent.d.ts.map +1 -0
- package/dist/components/verbs/sign.d.ts +30 -0
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/composite.d.ts +6 -1
- package/dist/composite.d.ts.map +1 -1
- package/dist/discovery/collect.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -1
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-rank.d.ts +66 -0
- package/dist/discovery/fold-rank.d.ts.map +1 -0
- package/dist/discovery/index.d.ts +15 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +17 -0
- package/dist/discovery/param-deps.d.ts.map +1 -0
- package/dist/fold/fold.d.ts +55 -2
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/fold/subset.d.ts +21 -14
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +2 -0
- package/dist/lexicon-schema.d.ts.map +1 -1
- package/dist/lexicon.d.ts +134 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts +77 -0
- package/dist/lifecycle/assert-live.d.ts.map +1 -0
- package/dist/lifecycle/change-set.d.ts +17 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/converge-ledger.d.ts +90 -0
- package/dist/lifecycle/converge-ledger.d.ts.map +1 -0
- package/dist/lifecycle/deep-diff.d.ts +18 -0
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts +9 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/disruption.d.ts +96 -0
- package/dist/lifecycle/disruption.d.ts.map +1 -0
- package/dist/lifecycle/gate-ledger.d.ts +33 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -0
- package/dist/lifecycle/git.d.ts +145 -21
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +6 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/lease.d.ts +113 -0
- package/dist/lifecycle/lease.d.ts.map +1 -0
- package/dist/lifecycle/replay.d.ts +2 -0
- package/dist/lifecycle/replay.d.ts.map +1 -1
- package/dist/lifecycle/scenario-eval.d.ts +42 -0
- package/dist/lifecycle/scenario-eval.d.ts.map +1 -0
- package/dist/lifecycle/scenario.d.ts +163 -0
- package/dist/lifecycle/scenario.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +63 -0
- package/dist/lifecycle/symptoms.d.ts.map +1 -0
- package/dist/lint/output-docs.d.ts +94 -0
- package/dist/lint/output-docs.d.ts.map +1 -0
- package/dist/lint/post-synth.d.ts +29 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.d.ts +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.d.ts.map +1 -0
- package/dist/lsp/lexicon-providers.d.ts +7 -0
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +139 -0
- package/dist/op/activity-contract.d.ts.map +1 -0
- package/dist/op/builders.d.ts +42 -2
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/converge-rule.d.ts +161 -0
- package/dist/op/converge-rule.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +39 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -0
- package/dist/op/index.d.ts +14 -0
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +7 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/op-verb-class.d.ts +42 -0
- package/dist/op/op-verb-class.d.ts.map +1 -0
- package/dist/op/operator.d.ts +128 -0
- package/dist/op/operator.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +187 -0
- package/dist/op/step-output-ref.d.ts.map +1 -0
- package/dist/op/types.d.ts +18 -1
- package/dist/op/types.d.ts.map +1 -1
- package/dist/provenance.d.ts +73 -3
- package/dist/provenance.d.ts.map +1 -1
- package/dist/runtime-adapter.d.ts +7 -1
- package/dist/runtime-adapter.d.ts.map +1 -1
- package/dist/serializer.d.ts +18 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/testing.d.ts +23 -2
- package/dist/testing.d.ts.map +1 -1
- package/dist/toml.d.ts +40 -5
- package/dist/toml.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/audit/catalog.test.ts +1 -1
- package/src/audit/catalog.ts +75 -3
- package/src/audit/core.ts +9 -0
- package/src/audit/discover.ts +29 -2
- package/src/audit/fetch.test.ts +216 -3
- package/src/audit/fetch.ts +270 -59
- package/src/audit/report-html.ts +5 -2
- package/src/audit/report-model.ts +9 -0
- package/src/audit/report.test.ts +22 -0
- package/src/audit/report.ts +3 -2
- package/src/audit/rules-doc.ts +2 -0
- package/src/audit/secrets.test.ts +303 -0
- package/src/audit/secrets.ts +406 -0
- package/src/audit/wrangler.test.ts +230 -0
- package/src/audit/wrangler.ts +290 -0
- package/src/build.ts +8 -3
- package/src/cli/command-group.ts +1 -1
- package/src/cli/commands/__fixtures__/schemas/sarif-2.1.0.schema.json +2882 -0
- package/src/cli/commands/audit.test.ts +215 -1
- package/src/cli/commands/audit.ts +86 -17
- package/src/cli/commands/build.test.ts +167 -2
- package/src/cli/commands/build.ts +114 -23
- package/src/cli/handlers/build.ts +2 -0
- package/src/cli/handlers/components.test.ts +199 -1
- package/src/cli/handlers/components.ts +160 -3
- package/src/cli/handlers/graph.test.ts +20 -0
- package/src/cli/handlers/graph.ts +10 -1
- package/src/cli/handlers/lifecycle.test.ts +90 -0
- package/src/cli/handlers/lifecycle.ts +30 -5
- package/src/cli/handlers/op-progress.test.ts +202 -0
- package/src/cli/handlers/op-progress.ts +192 -0
- package/src/cli/handlers/operator.test.ts +255 -0
- package/src/cli/handlers/operator.ts +240 -0
- package/src/cli/handlers/run-client.test.ts +82 -0
- package/src/cli/handlers/run-client.ts +85 -2
- package/src/cli/handlers/run-report.test.ts +62 -0
- package/src/cli/handlers/run-report.ts +20 -58
- package/src/cli/handlers/run.test.ts +144 -0
- package/src/cli/handlers/run.ts +40 -18
- package/src/cli/handlers/scenario.test.ts +456 -0
- package/src/cli/handlers/scenario.ts +330 -0
- package/src/cli/handlers/search-drift.test.ts +263 -0
- package/src/cli/handlers/search.ts +150 -1
- package/src/cli/main.test.ts +23 -0
- package/src/cli/main.ts +81 -1
- package/src/cli/mcp/op-tools.ts +17 -6
- package/src/cli/mcp/resource-handlers.ts +13 -5
- package/src/cli/mcp/server.test.ts +265 -2
- package/src/cli/mcp/server.ts +84 -7
- package/src/cli/mcp/types.ts +27 -1
- package/src/cli/registry.ts +47 -3
- package/src/codegen/docs-rule-scanning.test.ts +42 -0
- package/src/codegen/docs-rule-scanning.ts +25 -2
- package/src/components/README.md +7 -0
- package/src/components/capability.ts +17 -2
- package/src/components/cli-support.test.ts +17 -0
- package/src/components/cli-support.ts +13 -1
- package/src/components/component-schema.test.ts +32 -0
- package/src/components/component.schema.json +6 -0
- package/src/components/component.test.ts +21 -0
- package/src/components/component.ts +15 -0
- package/src/components/driver.ts +12 -4
- package/src/components/run-progress.ts +9 -5
- package/src/components/verbs/index.ts +6 -1
- package/src/components/verbs/run-agent.test.ts +683 -0
- package/src/components/verbs/run-agent.ts +786 -0
- package/src/components/verbs/sign.test.ts +19 -0
- package/src/components/verbs/sign.ts +34 -2
- package/src/composite.ts +31 -2
- package/src/discovery/collect.ts +11 -2
- package/src/discovery/fold-import.test.ts +54 -0
- package/src/discovery/fold-import.ts +178 -38
- package/src/discovery/fold-rank.test.ts +197 -0
- package/src/discovery/fold-rank.ts +346 -0
- package/src/discovery/index.ts +16 -1
- package/src/discovery/param-deps.test.ts +118 -0
- package/src/discovery/param-deps.ts +170 -0
- package/src/fold/fold.test.ts +6 -2
- package/src/fold/fold.ts +184 -3
- package/src/fold/subset.test.ts +82 -19
- package/src/fold/subset.ts +79 -41
- package/src/lexicon-schema.ts +3 -0
- package/src/lexicon.ts +154 -2
- package/src/lifecycle/assert-live.test.ts +125 -0
- package/src/lifecycle/assert-live.ts +154 -0
- package/src/lifecycle/change-set.ts +35 -3
- package/src/lifecycle/converge-ledger.test.ts +199 -0
- package/src/lifecycle/converge-ledger.ts +179 -0
- package/src/lifecycle/deep-diff.test.ts +79 -1
- package/src/lifecycle/deep-diff.ts +23 -0
- package/src/lifecycle/deep-observe.ts +13 -2
- package/src/lifecycle/disruption.test.ts +186 -0
- package/src/lifecycle/disruption.ts +224 -0
- package/src/lifecycle/gate-ledger.test.ts +103 -0
- package/src/lifecycle/gate-ledger.ts +140 -0
- package/src/lifecycle/git.test.ts +430 -0
- package/src/lifecycle/git.ts +446 -84
- package/src/lifecycle/index.ts +6 -0
- package/src/lifecycle/lease.test.ts +343 -0
- package/src/lifecycle/lease.ts +270 -0
- package/src/lifecycle/replay.test.ts +25 -0
- package/src/lifecycle/replay.ts +11 -3
- package/src/lifecycle/scenario-eval.test.ts +199 -0
- package/src/lifecycle/scenario-eval.ts +158 -0
- package/src/lifecycle/scenario.test.ts +195 -0
- package/src/lifecycle/scenario.ts +321 -0
- package/src/lifecycle/symptoms.test.ts +116 -0
- package/src/lifecycle/symptoms.ts +126 -0
- package/src/lint/output-docs.test.ts +220 -0
- package/src/lint/output-docs.ts +204 -0
- package/src/lint/post-synth.test.ts +97 -0
- package/src/lint/post-synth.ts +45 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.ts +26 -0
- package/src/lint/rules/comp/comp.test.ts +49 -1
- package/src/lint/rules/evl001-non-literal-expression.test.ts +8 -3
- package/src/lint/rules/evl001-non-literal-expression.ts +6 -6
- package/src/lsp/lexicon-providers.test.ts +44 -0
- package/src/lsp/lexicon-providers.ts +11 -1
- package/src/op/activity-contract.test.ts +180 -0
- package/src/op/activity-contract.ts +278 -0
- package/src/op/builders-exports.test.ts +17 -1
- package/src/op/builders.ts +59 -5
- package/src/op/converge-rule.test.ts +179 -0
- package/src/op/converge-rule.ts +311 -0
- package/src/op/generate-pipeline.test.ts +53 -0
- package/src/op/generate-pipeline.ts +99 -0
- package/src/op/index.ts +30 -0
- package/src/op/local-executor.test.ts +92 -0
- package/src/op/local-executor.ts +52 -10
- package/src/op/local-output.ts +1 -1
- package/src/op/op-verb-class.test.ts +126 -0
- package/src/op/op-verb-class.ts +115 -0
- package/src/op/operator.test.ts +346 -0
- package/src/op/operator.ts +213 -0
- package/src/op/step-output-ref.test.ts +334 -0
- package/src/op/step-output-ref.ts +453 -0
- package/src/op/types.ts +18 -1
- package/src/provenance.test.ts +151 -4
- package/src/provenance.ts +118 -4
- package/src/runtime-adapter.ts +31 -10
- package/src/serializer.ts +18 -0
- package/src/testing.test.ts +89 -2
- package/src/testing.ts +63 -3
- package/src/toml.test.ts +157 -384
- package/src/toml.ts +371 -5
|
@@ -8,7 +8,11 @@ import { discover } from "../../discovery/index";
|
|
|
8
8
|
|
|
9
9
|
import { observeResources } from "../../lifecycle/observe";
|
|
10
10
|
import { replaySnapshots, hasSnapshot } from "../../lifecycle/replay";
|
|
11
|
+
import { diffLive, type LiveDiffResult } from "../../lifecycle/live-diff";
|
|
11
12
|
import type { LiveObservation } from "../../graph-ir";
|
|
13
|
+
import type { ResourceMetadata } from "../../lexicon";
|
|
14
|
+
import type { ObservationDepth } from "../../lifecycle/types";
|
|
15
|
+
import { formatUnobserved } from "../../observation";
|
|
12
16
|
import { loadChantConfig, matchesDeclaredEnvironment } from "../../config";
|
|
13
17
|
import { loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
14
18
|
import { formatError, formatWarning } from "../format";
|
|
@@ -56,6 +60,31 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
56
60
|
}
|
|
57
61
|
const show = parseShow(args);
|
|
58
62
|
|
|
63
|
+
// Query-scoped drift (#1268): --check-live checks a snapshot answer against
|
|
64
|
+
// a live read, --check-snapshot checks a live answer against the recorded
|
|
65
|
+
// snapshot — the direction each needs is the source it does NOT already have.
|
|
66
|
+
if (args.checkLive && !args.at) {
|
|
67
|
+
console.error(formatError({
|
|
68
|
+
message: "chant search --check-live needs --at <ref>",
|
|
69
|
+
hint: "answer from a snapshot and check the matched rows against a live read: --at latest --check-live --env <name>",
|
|
70
|
+
}));
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
if (args.checkSnapshot && !args.live) {
|
|
74
|
+
console.error(formatError({
|
|
75
|
+
message: "chant search --check-snapshot needs --live",
|
|
76
|
+
hint: "answer live and check the matched rows against the recorded snapshot: --live --check-snapshot --env <name>",
|
|
77
|
+
}));
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
if (args.failOnDrift && !args.checkLive && !args.checkSnapshot) {
|
|
81
|
+
console.error(formatError({
|
|
82
|
+
message: "chant search --fail-on-drift needs --check-live or --check-snapshot",
|
|
83
|
+
hint: "it fails the check those flags run, so it is meaningless without one",
|
|
84
|
+
}));
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
59
88
|
const projectPath = resolve(".");
|
|
60
89
|
const { config } = await loadChantConfig(projectPath);
|
|
61
90
|
|
|
@@ -73,6 +102,14 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
73
102
|
let ambientKinds: string[] = [];
|
|
74
103
|
// Set only on a replay: whether the recording itself holds ambient resources.
|
|
75
104
|
let replayAmbient: { recordedAmbient: boolean } | undefined;
|
|
105
|
+
// Query-scoped drift (#1268): the OTHER observation, read only when
|
|
106
|
+
// --check-live/--check-snapshot asked for one — the declared canvas to
|
|
107
|
+
// classify against, and whether the exit code should reflect what it found.
|
|
108
|
+
let checkObservations: LiveObservation[] | undefined;
|
|
109
|
+
let primaryObservations: LiveObservation[] | undefined;
|
|
110
|
+
let declaredForDrift: GraphIR | undefined;
|
|
111
|
+
let snapshotDepth: ObservationDepth | undefined;
|
|
112
|
+
let driftFailure = false;
|
|
76
113
|
if (args.live || args.at) {
|
|
77
114
|
const environment = args.env;
|
|
78
115
|
if (!environment) {
|
|
@@ -126,6 +163,21 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
126
163
|
),
|
|
127
164
|
};
|
|
128
165
|
source = { kind: "snapshot", commit: replay.commit, timestamp: replay.timestamp };
|
|
166
|
+
snapshotDepth = replay.depth;
|
|
167
|
+
if (args.checkLive) {
|
|
168
|
+
// A fresh live read, additional to the snapshot the answer itself came
|
|
169
|
+
// from — this is what the matched rows get checked against.
|
|
170
|
+
const liveCheck = await observeResources(environment, observing, buildResult, {
|
|
171
|
+
owned: true,
|
|
172
|
+
stacks,
|
|
173
|
+
ambient: args.ambient === true,
|
|
174
|
+
});
|
|
175
|
+
for (const e of liveCheck.errors) {
|
|
176
|
+
liveFailures.push(e);
|
|
177
|
+
console.error(formatError({ message: `live read failed — ${e}` }));
|
|
178
|
+
}
|
|
179
|
+
checkObservations = liveCheck.observations;
|
|
180
|
+
}
|
|
129
181
|
} else {
|
|
130
182
|
const observed = await observeResources(environment, observing, buildResult, {
|
|
131
183
|
owned: true,
|
|
@@ -142,7 +194,22 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
142
194
|
observations = observed.observations;
|
|
143
195
|
liveNotes = observed.notes ?? [];
|
|
144
196
|
source = { kind: "live" };
|
|
197
|
+
if (args.checkSnapshot) {
|
|
198
|
+
// The reverse direction: answer live, check the matched rows against
|
|
199
|
+
// the most recently recorded snapshot. Missing entirely is not a
|
|
200
|
+
// failure of THIS command — the live answer already stands — so it is
|
|
201
|
+
// a note, not an error.
|
|
202
|
+
const scoped = new Set(stacks.filter((st) => st.src).map((st) => st.name));
|
|
203
|
+
const checkReplay = await replaySnapshots(environment, "latest", scoped);
|
|
204
|
+
if ("error" in checkReplay) {
|
|
205
|
+
console.error(formatWarning({ message: `--check-snapshot: ${checkReplay.error}` }));
|
|
206
|
+
} else {
|
|
207
|
+
checkObservations = checkReplay.observations;
|
|
208
|
+
snapshotDepth = checkReplay.depth;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
145
211
|
}
|
|
212
|
+
primaryObservations = observations;
|
|
146
213
|
let live = buildLiveGraphIr(observations);
|
|
147
214
|
// Containment edges, kept aside until after the overlay (see below).
|
|
148
215
|
let containmentEdges: IREdge[] = [];
|
|
@@ -206,6 +273,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
206
273
|
stacks.length > 0
|
|
207
274
|
? await buildDeclaredPerStack(stacks, projectPath)
|
|
208
275
|
: buildGraphIr((await discover(resolve(args.src ?? config.sourceDir ?? "."))).entities, projectPath);
|
|
276
|
+
declaredForDrift = declared;
|
|
209
277
|
// Carry the NOT-OBSERVED half of the tri-state (#1089) onto the rows, so a
|
|
210
278
|
// declared entity nobody could read is painted `_unobserved` and a row can
|
|
211
279
|
// say so instead of printing blank where a physical id would go (#1263).
|
|
@@ -279,6 +347,29 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
279
347
|
// Qualifies the provenance line, so it sits with it: one line per distinct
|
|
280
348
|
// note for the whole run, not one per stack, and after the rows (#1265).
|
|
281
349
|
for (const n of liveNotes) console.error(formatWarning({ message: n }));
|
|
350
|
+
// Query-scoped drift (#1268): the matched rows, and only the matched rows,
|
|
351
|
+
// checked against the observation the primary answer did NOT use. Scoping
|
|
352
|
+
// both sides of diffLive() to the matched ids is what keeps a query-scoped-
|
|
353
|
+
// out resource from reading as `missing` or `unobserved` — it was never
|
|
354
|
+
// asked about, which is a third thing from both.
|
|
355
|
+
if (checkObservations && declaredForDrift && primaryObservations) {
|
|
356
|
+
const declaredIds = new Set(declaredForDrift.nodes.map((n) => n.id));
|
|
357
|
+
const matchedIds = new Set(matches.map((n) => n.id));
|
|
358
|
+
const nowObservations = args.checkLive ? checkObservations : primaryObservations;
|
|
359
|
+
const thenObservations = args.checkLive ? primaryObservations : checkObservations;
|
|
360
|
+
const driftCount = renderDrift(
|
|
361
|
+
diffLive({
|
|
362
|
+
declared: new Set([...matchedIds].filter((id) => declaredIds.has(id))),
|
|
363
|
+
observedNow: pickResources(mergeResources(nowObservations), matchedIds),
|
|
364
|
+
observedThen: pickResources(mergeResources(thenObservations), matchedIds),
|
|
365
|
+
unobserved: pickResources(collectUnobserved(nowObservations), matchedIds),
|
|
366
|
+
}),
|
|
367
|
+
matches.length,
|
|
368
|
+
args.checkLive ? "live" : "snapshot",
|
|
369
|
+
snapshotDepth,
|
|
370
|
+
);
|
|
371
|
+
if (args.failOnDrift && driftCount > 0) driftFailure = true;
|
|
372
|
+
}
|
|
282
373
|
ambientHint(matches, ambientKinds, args.ambient === true, replayAmbient);
|
|
283
374
|
showMiss(matches, show);
|
|
284
375
|
regionSpread(terms, matches, show);
|
|
@@ -297,6 +388,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
|
|
|
297
388
|
}));
|
|
298
389
|
return 1;
|
|
299
390
|
}
|
|
391
|
+
if (driftFailure) return 1;
|
|
300
392
|
return 0;
|
|
301
393
|
}
|
|
302
394
|
|
|
@@ -463,6 +555,63 @@ function provenance(matches: IRNode[], source: AnswerSource, recorded?: string,
|
|
|
463
555
|
console.log(`— observed from snapshot${at}${taken} · bound ${bound}/${matches.length}`);
|
|
464
556
|
}
|
|
465
557
|
|
|
558
|
+
/** Union `LiveObservation.resources` across lexicons into one name-keyed map. */
|
|
559
|
+
function mergeResources(observations: LiveObservation[]): Record<string, ResourceMetadata> {
|
|
560
|
+
const out: Record<string, ResourceMetadata> = {};
|
|
561
|
+
for (const o of observations) Object.assign(out, o.resources);
|
|
562
|
+
return out;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Restrict a name-keyed map to the matched ids — the whole of "query-scoped". */
|
|
566
|
+
function pickResources<T>(map: Record<string, T>, ids: Set<string>): Record<string, T> {
|
|
567
|
+
const out: Record<string, T> = {};
|
|
568
|
+
for (const id of ids) if (id in map) out[id] = map[id];
|
|
569
|
+
return out;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Render the query-scoped drift check (#1268) — one line per matched resource
|
|
574
|
+
* whose {@link diffLive} verdict is not `unchanged`, then a summary.
|
|
575
|
+
*
|
|
576
|
+
* Reuses `diffLive` unmodified, so every category means exactly what it means
|
|
577
|
+
* in `lifecycle diff --live`: `missing`/`orphan`/`disappeared`/`drifted` count
|
|
578
|
+
* as drift, the same set `lifecycle diff` totals; `newlyObserved` and runtime
|
|
579
|
+
* children are reported but do not, and `unobserved` — a read that could not
|
|
580
|
+
* look — stays distinct from both, the same #1089 tri-state everywhere else.
|
|
581
|
+
*/
|
|
582
|
+
function renderDrift(
|
|
583
|
+
diff: LiveDiffResult,
|
|
584
|
+
checked: number,
|
|
585
|
+
direction: "live" | "snapshot",
|
|
586
|
+
depth?: ObservationDepth,
|
|
587
|
+
): number {
|
|
588
|
+
for (const name of diff.missing) console.log(`⚠ ${name} — missing (declared, not found by this check)`);
|
|
589
|
+
for (const name of diff.orphan) console.log(`⚠ ${name} — orphan (observed, not declared)`);
|
|
590
|
+
for (const name of diff.disappeared) console.log(`⚠ ${name} — disappeared since the recorded snapshot`);
|
|
591
|
+
for (const drift of diff.driftedSinceSnapshot) {
|
|
592
|
+
for (const change of drift.changes) {
|
|
593
|
+
console.log(`⚠ ${drift.name} ${change.path}: ${formatValue(change.oldValue)} → ${formatValue(change.newValue)} — drifted`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
for (const name of diff.newlyObserved) console.log(` · ${name} — newly observed since the recorded snapshot`);
|
|
597
|
+
for (const r of diff.runtimeChildren) console.log(` · ${r.name} (${r.type}) — runtime, owned by ${r.owner}`);
|
|
598
|
+
for (const u of diff.unobserved) console.log(` ? ${formatUnobserved(u.name, u)}`);
|
|
599
|
+
const driftCount = diff.missing.length + diff.orphan.length + diff.disappeared.length + diff.driftedSinceSnapshot.length;
|
|
600
|
+
const label = direction === "live" ? "a live read" : "the recorded snapshot";
|
|
601
|
+
const depthNote = depth === "deep" ? " · snapshot recorded at deep depth, compared here at identity" : "";
|
|
602
|
+
console.log(
|
|
603
|
+
`— checked against ${label} · ${driftCount > 0 ? `${driftCount} of ${checked} matched drifted` : `no drift across ${checked} matched`}${depthNote}`,
|
|
604
|
+
);
|
|
605
|
+
return driftCount;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function formatValue(v: unknown): string {
|
|
609
|
+
if (v === undefined) return "<unset>";
|
|
610
|
+
if (typeof v === "string") return v.length > 60 ? v.slice(0, 57) + "..." : v;
|
|
611
|
+
const json = JSON.stringify(v);
|
|
612
|
+
return json.length > 60 ? json.slice(0, 57) + "..." : json;
|
|
613
|
+
}
|
|
614
|
+
|
|
466
615
|
/**
|
|
467
616
|
* Name the facts chant computed for the kinds in this result that the query did not use.
|
|
468
617
|
*
|
|
@@ -815,4 +964,4 @@ function formatRow(n: IRNode, show: string[]): string {
|
|
|
815
964
|
}
|
|
816
965
|
|
|
817
966
|
/** Internals exposed for unit tests. */
|
|
818
|
-
export const __searchInternals = { parseQuery, matchTerm, formatRow, explain, describeTerm, derivedSurface, availableAttrs, ambientHint, regionSpread, showMiss, provenance };
|
|
967
|
+
export const __searchInternals = { parseQuery, matchTerm, formatRow, explain, describeTerm, derivedSurface, availableAttrs, ambientHint, regionSpread, showMiss, provenance, renderDrift, mergeResources, pickResources };
|
package/src/cli/main.test.ts
CHANGED
|
@@ -383,6 +383,29 @@ describe("parseArgs", () => {
|
|
|
383
383
|
expect(() => parseArgs(["run", "myop", "--json=1"])).toThrow(/--json is a boolean flag/);
|
|
384
384
|
});
|
|
385
385
|
|
|
386
|
+
test("--fold-rank has the same context-sensitive bare-vs-path behavior as --report (#1083)", () => {
|
|
387
|
+
// Bare --fold-rank is the boolean (print the ranked report); --fold-rank
|
|
388
|
+
// <path> is the collapsed-format export destination.
|
|
389
|
+
const bare = parseArgs(["build", "src", "--fold", "--fold-rank"]);
|
|
390
|
+
expect(bare.foldRank).toBe(true);
|
|
391
|
+
expect(bare.foldRankCollapsedFile).toBeUndefined();
|
|
392
|
+
|
|
393
|
+
const withPath = parseArgs(["build", "src", "--fold", "--fold-rank", "out.collapsed"]);
|
|
394
|
+
expect(withPath.foldRankCollapsedFile).toBe("out.collapsed");
|
|
395
|
+
expect(withPath.foldRank).toBeUndefined();
|
|
396
|
+
|
|
397
|
+
// A following flag (not a path) keeps the bare-boolean reading.
|
|
398
|
+
const beforeFlag = parseArgs(["build", "src", "--fold-rank", "--verbose"]);
|
|
399
|
+
expect(beforeFlag.foldRank).toBe(true);
|
|
400
|
+
expect(beforeFlag.verbose).toBe(true);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("--fold-rank=<path> (joined form) resolves the same as the space-separated one", () => {
|
|
404
|
+
const result = parseArgs(["build", "src", "--fold-rank=out.collapsed"]);
|
|
405
|
+
expect(result.foldRankCollapsedFile).toBe("out.collapsed");
|
|
406
|
+
expect(result.foldRank).toBeUndefined();
|
|
407
|
+
});
|
|
408
|
+
|
|
386
409
|
test("--report keeps its context-sensitive bare-vs-value behavior when joined", () => {
|
|
387
410
|
// --report is deliberately not in the boolean-reject set: bare --report is
|
|
388
411
|
// a boolean (`run`), but --report <path> is a SARIF destination (migrate).
|
package/src/cli/main.ts
CHANGED
|
@@ -24,11 +24,13 @@ import { runCarveEmit } from "./handlers/carve-emit";
|
|
|
24
24
|
import { runCarveBridge } from "./handlers/carve-bridge";
|
|
25
25
|
import { runCarveApply } from "./handlers/carve-apply";
|
|
26
26
|
import { runLifecycleSnapshot, runLifecycleShow, runLifecycleDiff, runLifecycleRollback, runLifecyclePlan, runLifecycleAffected, runLifecycleLog, runLifecycleTeardown, runLifecycleUnknown } from "./handlers/lifecycle";
|
|
27
|
-
import { runComponentsStatus, runComponentsReleaseRecord, runComponentsUnknown } from "./handlers/components";
|
|
27
|
+
import { runComponentsStatus, runComponentsReleaseRecord, runComponentsExport, runComponentsUnknown } from "./handlers/components";
|
|
28
|
+
import { runScenarioCheck, runScenarioUnknown } from "./handlers/scenario";
|
|
28
29
|
import { runGraph } from "./handlers/graph";
|
|
29
30
|
import { runExplain } from "./handlers/explain";
|
|
30
31
|
import { runSearch } from "./handlers/search";
|
|
31
32
|
import { runOp, runOpList, runOpStatus, runOpSignal, runOpCancel, runOpLog } from "./handlers/run";
|
|
33
|
+
import { runOperator, runOperatorStatus, runApprove } from "./handlers/operator";
|
|
32
34
|
import { runEmulator } from "./handlers/emulator";
|
|
33
35
|
import { splitJoinedFlags, dispatchCommandGroup, collectCommandGroups, formatCommandGroupsHelp, type CommandGroup } from "./command-group";
|
|
34
36
|
import type { LexiconPlugin } from "../lexicon";
|
|
@@ -80,6 +82,10 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
80
82
|
"--sandbox",
|
|
81
83
|
"--yes",
|
|
82
84
|
"--confirm-prod",
|
|
85
|
+
"--once",
|
|
86
|
+
"--check-live",
|
|
87
|
+
"--check-snapshot",
|
|
88
|
+
"--fail-on-drift",
|
|
83
89
|
]);
|
|
84
90
|
|
|
85
91
|
/**
|
|
@@ -302,6 +308,12 @@ export function parseArgs(args: string[]): ParsedArgs {
|
|
|
302
308
|
result.at = args[++i];
|
|
303
309
|
} else if (arg === "--ambient") {
|
|
304
310
|
result.ambient = true;
|
|
311
|
+
} else if (arg === "--check-live") {
|
|
312
|
+
result.checkLive = true;
|
|
313
|
+
} else if (arg === "--check-snapshot") {
|
|
314
|
+
result.checkSnapshot = true;
|
|
315
|
+
} else if (arg === "--fail-on-drift") {
|
|
316
|
+
result.failOnDrift = true;
|
|
305
317
|
} else if (arg === "--run-examples") {
|
|
306
318
|
result.runExamples = true;
|
|
307
319
|
} else if (arg === "--pinned-digest") {
|
|
@@ -334,6 +346,17 @@ export function parseArgs(args: string[]): ParsedArgs {
|
|
|
334
346
|
result.fold = false;
|
|
335
347
|
} else if (arg === "--sandbox") {
|
|
336
348
|
result.sandbox = true;
|
|
349
|
+
} else if (arg === "--fold-rank") {
|
|
350
|
+
// chant #1083 — same context-sensitive shape as --report above:
|
|
351
|
+
// `--fold-rank` alone prints the ranked-blocker report; `--fold-rank
|
|
352
|
+
// <path>` ALSO writes the Brendan Gregg collapsed-format export there.
|
|
353
|
+
const next = args[i + 1];
|
|
354
|
+
if (next && !next.startsWith("-")) {
|
|
355
|
+
result.foldRankCollapsedFile = next;
|
|
356
|
+
i++;
|
|
357
|
+
} else {
|
|
358
|
+
result.foldRank = true;
|
|
359
|
+
}
|
|
337
360
|
} else if (arg === "--param") {
|
|
338
361
|
// chant #1118/#1127 — `--param name=value` (space-separated) and
|
|
339
362
|
// `--param=name=value` (joined, split above at its first `=` into flag
|
|
@@ -347,6 +370,14 @@ export function parseArgs(args: string[]): ParsedArgs {
|
|
|
347
370
|
result.paramsFile = args[++i];
|
|
348
371
|
} else if (arg === "--projection") {
|
|
349
372
|
result.projection = args[++i];
|
|
373
|
+
} else if (arg === "--interval") {
|
|
374
|
+
result.interval = args[++i];
|
|
375
|
+
} else if (arg === "--lease-ttl") {
|
|
376
|
+
result.leaseTtl = args[++i];
|
|
377
|
+
} else if (arg === "--once") {
|
|
378
|
+
result.once = true;
|
|
379
|
+
} else if (arg === "--note") {
|
|
380
|
+
result.note = args[++i];
|
|
350
381
|
} else if (arg.startsWith("--")) {
|
|
351
382
|
// chant #1127 — every recognized flag is matched above; anything left
|
|
352
383
|
// starting with `--` is unrecognized, whether it arrived bare
|
|
@@ -462,6 +493,24 @@ Ops:
|
|
|
462
493
|
consumer to render live wave/component/phase/step
|
|
463
494
|
progress instead of tailing raw logs (additive; run
|
|
464
495
|
semantics/exit code unchanged)
|
|
496
|
+
operator Run scheduled ticks for discovered ConvergeOps
|
|
497
|
+
locally, no Temporal (#1485): acquire/renew a per-op
|
|
498
|
+
lease (git ref CAS), tick on --interval, record every
|
|
499
|
+
result as a ledger fact. --env <env> scopes to one
|
|
500
|
+
environment; --interval <dur> (default 60s) and
|
|
501
|
+
--lease-ttl <dur> (default 5m) tune cadence; --once
|
|
502
|
+
runs a single round and exits (cron/systemd-timer/
|
|
503
|
+
CronJob invokers use this instead of the daemon)
|
|
504
|
+
operator status Last tick, outcomes, and pending gates per
|
|
505
|
+
ConvergeOp, read from the chant/lifecycle orphan
|
|
506
|
+
branch alone — no daemon needs to be running
|
|
507
|
+
(--env <env>, --json)
|
|
508
|
+
approve <op> <gate> Record a gate's out-of-band resolution fact
|
|
509
|
+
(--actor <name>, --note <text>) — the durable
|
|
510
|
+
counterpart to a converge tick's gate-as-fact
|
|
511
|
+
outcome; see the pending-gates list in operator
|
|
512
|
+
status. Does not itself unblock the gated op's local
|
|
513
|
+
dispatch (re-run --temporal, or merge its PR)
|
|
465
514
|
|
|
466
515
|
graph Show Op dependency graph (--stacks for cross-stack order,
|
|
467
516
|
--format ir|mermaid|dot|layout for the lint-gated graph IR,
|
|
@@ -496,6 +545,12 @@ Lifecycle (alias: lc):
|
|
|
496
545
|
--confirm-prod, or an interactive confirmation)
|
|
497
546
|
lifecycle log [env] History of lifecycle snapshots
|
|
498
547
|
|
|
548
|
+
Plan scenarios (#1292):
|
|
549
|
+
scenario check Evaluate every declared Scenario's expect clause
|
|
550
|
+
offline, against its given fixture (no cloud, no
|
|
551
|
+
credentials); --json: emit verdicts as JSON.
|
|
552
|
+
Nonzero exit on any failing scenario.
|
|
553
|
+
|
|
499
554
|
Component release ledger + status:
|
|
500
555
|
components status [env] What's built vs what's deployed where, joined by
|
|
501
556
|
digest (--live: reconcile against live+ownership;
|
|
@@ -505,6 +560,11 @@ Component release ledger + status:
|
|
|
505
560
|
components release <env> Append one immutable release record
|
|
506
561
|
(--component <name> --digest <sha256:...>
|
|
507
562
|
[--git-sha <sha>] [--run-id <id>] [--actor <name>])
|
|
563
|
+
components export <env> Materialize a persisted build archive manifest to
|
|
564
|
+
a portable directory (--component <name>
|
|
565
|
+
[--digest <manifestDigest>] -o <dir> [--json]);
|
|
566
|
+
copies every image/template/asset/sbom entry
|
|
567
|
+
byte-for-byte plus a self-describing manifest.json
|
|
508
568
|
|
|
509
569
|
Lexicon development:
|
|
510
570
|
dev generate Generate lexicon artifacts (+ validate + coverage)
|
|
@@ -590,6 +650,14 @@ Options:
|
|
|
590
650
|
--no-fold (build) Opt out of folding for this invocation: every
|
|
591
651
|
source module is imported and run, the pre-#1134
|
|
592
652
|
behavior. Beats chant.config.ts's build.fold.
|
|
653
|
+
--fold-rank [<path>] (build, with --fold) Rank run-mode files by dominator
|
|
654
|
+
retained-count over the forward import-failure graph
|
|
655
|
+
(#1083) — fixing the top blocker unblocks the most
|
|
656
|
+
files. Files held back only by the reverse rule
|
|
657
|
+
(#1044) are reported separately, never folded into
|
|
658
|
+
the ranking. With a path argument, also writes a
|
|
659
|
+
Brendan Gregg collapsed-format export (weighted by
|
|
660
|
+
retained count) there, for any flame/icicle viewer.
|
|
593
661
|
--sandbox (build) Run run-fallback source files (or every
|
|
594
662
|
file, without --fold) together, isolated, in one
|
|
595
663
|
sandboxed child process instead of in-process
|
|
@@ -620,6 +688,7 @@ Examples:
|
|
|
620
688
|
chant build ./infra/ --components --generate gitlab --output .gitlab-ci.yml
|
|
621
689
|
chant run --components search-service --env staging
|
|
622
690
|
chant run --components all --env production
|
|
691
|
+
chant components export prod --component search-service -o ./dist/search-service
|
|
623
692
|
chant import template.json --output ./infra/
|
|
624
693
|
chant import --from prod --name my-bucket --output src/
|
|
625
694
|
chant lint ./infra/
|
|
@@ -780,6 +849,10 @@ const registry: CommandDef[] = [
|
|
|
780
849
|
{ name: "run log", handler: runOpLog },
|
|
781
850
|
{ name: "run", handler: runOp },
|
|
782
851
|
|
|
852
|
+
{ name: "operator status", handler: runOperatorStatus },
|
|
853
|
+
{ name: "operator", handler: runOperator },
|
|
854
|
+
{ name: "approve", handler: runApprove },
|
|
855
|
+
|
|
783
856
|
{ name: "graph", handler: runGraph },
|
|
784
857
|
{ name: "vendor", handler: runVendor },
|
|
785
858
|
|
|
@@ -793,9 +866,15 @@ const registry: CommandDef[] = [
|
|
|
793
866
|
{ name: "lifecycle teardown", requiresPlugins: true, handler: runLifecycleTeardown },
|
|
794
867
|
{ name: "lifecycle log", handler: runLifecycleLog },
|
|
795
868
|
|
|
869
|
+
// Plan scenarios (#1292) — fully offline, no plugin network calls, but
|
|
870
|
+
// requiresPlugins:true so the build step has serializers to partition
|
|
871
|
+
// against, same as every other build-then-something verb.
|
|
872
|
+
{ name: "scenario check", requiresPlugins: true, handler: runScenarioCheck },
|
|
873
|
+
|
|
796
874
|
// Component release ledger + status surface (#568, epic #551)
|
|
797
875
|
{ name: "components status", requiresPlugins: true, handler: runComponentsStatus },
|
|
798
876
|
{ name: "components release", handler: runComponentsReleaseRecord },
|
|
877
|
+
{ name: "components export", handler: runComponentsExport },
|
|
799
878
|
|
|
800
879
|
// Local emulators of configured lexicons (#920). Compound so the action word
|
|
801
880
|
// lands in args.path (not consumed as a project dir) and projectPath is forced ".".
|
|
@@ -811,6 +890,7 @@ const registry: CommandDef[] = [
|
|
|
811
890
|
{ name: "carve", handler: runCarveUnknown },
|
|
812
891
|
{ name: "emulator", requiresPlugins: true, handler: runEmulator },
|
|
813
892
|
{ name: "lifecycle", handler: runLifecycleUnknown },
|
|
893
|
+
{ name: "scenario", handler: runScenarioUnknown },
|
|
814
894
|
{ name: "dev", handler: runDevUnknown },
|
|
815
895
|
{ name: "serve", handler: runServeUnknown },
|
|
816
896
|
{ name: "components", handler: runComponentsUnknown },
|
package/src/cli/mcp/op-tools.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { discoverOps } from "../../op/discover";
|
|
3
3
|
import { makeTemporalClient } from "../handlers/run";
|
|
4
|
-
import { resolveWorkflowId } from "../handlers/run-client";
|
|
4
|
+
import { resolveWorkflowId, fetchNormalizedHistory } from "../handlers/run-client";
|
|
5
5
|
import { generateReport } from "../handlers/run-report";
|
|
6
|
+
import { extractStepRecords, countActivities, queryGateState } from "../handlers/op-progress";
|
|
6
7
|
import type { ToolRegistration } from "./lifecycle-tools";
|
|
7
8
|
|
|
8
9
|
function workflowFnName(opName: string): string {
|
|
@@ -117,14 +118,22 @@ export function createOpStatusTool(): ToolRegistration {
|
|
|
117
118
|
const name = params.name as string;
|
|
118
119
|
const profile = params.profile as string | undefined;
|
|
119
120
|
|
|
121
|
+
const { ops } = await discoverOps();
|
|
122
|
+
const config = ops.get(name)?.config;
|
|
123
|
+
|
|
120
124
|
const { client } = await makeTemporalClient(profile, resolve("."));
|
|
121
125
|
const handle = client.workflow.getHandle(resolveWorkflowId(name));
|
|
122
126
|
const desc = await handle.describe();
|
|
123
|
-
const history = await handle
|
|
127
|
+
const history = await fetchNormalizedHistory(handle);
|
|
124
128
|
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
const { completed: activitiesCompleted, scheduled: activitiesScheduled } = countActivities(history);
|
|
130
|
+
// Per-phase progress (#1676) — the same StepRecord shape `chant run
|
|
131
|
+
// <name> --json` uses locally, so a consumer renders one way
|
|
132
|
+
// regardless of executor. Only buildable when the Op's config was
|
|
133
|
+
// discoverable (a *.op.ts file on disk); absent otherwise rather than
|
|
134
|
+
// guessed at.
|
|
135
|
+
const progress = config ? extractStepRecords(config, history, { final: Boolean(desc.closeTime) }) : undefined;
|
|
136
|
+
const gate = await queryGateState(handle);
|
|
128
137
|
|
|
129
138
|
return {
|
|
130
139
|
workflowId: desc.workflowId,
|
|
@@ -135,6 +144,8 @@ export function createOpStatusTool(): ToolRegistration {
|
|
|
135
144
|
taskQueue: desc.taskQueue,
|
|
136
145
|
activitiesCompleted,
|
|
137
146
|
activitiesScheduled,
|
|
147
|
+
...(progress ? { progress } : {}),
|
|
148
|
+
gate: gate ?? null,
|
|
138
149
|
};
|
|
139
150
|
},
|
|
140
151
|
};
|
|
@@ -196,7 +207,7 @@ export function createOpReportTool(): ToolRegistration {
|
|
|
196
207
|
const { client } = await makeTemporalClient(profile, resolve("."));
|
|
197
208
|
const handle = client.workflow.getHandle(resolveWorkflowId(name));
|
|
198
209
|
const desc = await handle.describe();
|
|
199
|
-
const history = await handle
|
|
210
|
+
const history = await fetchNormalizedHistory(handle);
|
|
200
211
|
|
|
201
212
|
return generateReport(name, config, desc, history);
|
|
202
213
|
},
|
|
@@ -5,7 +5,8 @@ import { getContext } from "./resources/context";
|
|
|
5
5
|
import { readSnapshot, readEnvironmentSnapshots } from "../../lifecycle/git";
|
|
6
6
|
import { discoverOps } from "../../op/discover";
|
|
7
7
|
import { makeTemporalClient } from "../handlers/run";
|
|
8
|
-
import { resolveWorkflowId } from "../handlers/run-client";
|
|
8
|
+
import { resolveWorkflowId, fetchNormalizedHistory } from "../handlers/run-client";
|
|
9
|
+
import { extractStepRecords, countActivities, queryGateState } from "../handlers/op-progress";
|
|
9
10
|
import { loadOkfBundle } from "../../okf-read";
|
|
10
11
|
import { loadChantConfigUpward, resolveKnowledgeDir } from "../../config";
|
|
11
12
|
|
|
@@ -177,11 +178,16 @@ export async function handleResourcesRead(
|
|
|
177
178
|
if (uri.startsWith("chant://ops/") && uri.endsWith("/runs/latest")) {
|
|
178
179
|
const name = uri.replace("chant://ops/", "").replace("/runs/latest", "");
|
|
179
180
|
try {
|
|
181
|
+
const { ops } = await discoverOps();
|
|
182
|
+
const config = ops.get(name)?.config;
|
|
183
|
+
|
|
180
184
|
const { client } = await makeTemporalClient(undefined, resolve("."));
|
|
181
185
|
const handle = client.workflow.getHandle(resolveWorkflowId(name));
|
|
182
186
|
const desc = await handle.describe();
|
|
183
|
-
const history = await handle
|
|
184
|
-
const
|
|
187
|
+
const history = await fetchNormalizedHistory(handle);
|
|
188
|
+
const { completed: activitiesCompleted, scheduled: activitiesScheduled } = countActivities(history);
|
|
189
|
+
const progress = config ? extractStepRecords(config, history, { final: Boolean(desc.closeTime) }) : undefined;
|
|
190
|
+
const gate = await queryGateState(handle);
|
|
185
191
|
const result = {
|
|
186
192
|
workflowId: desc.workflowId,
|
|
187
193
|
runId: desc.runId,
|
|
@@ -189,8 +195,10 @@ export async function handleResourcesRead(
|
|
|
189
195
|
startTime: desc.startTime,
|
|
190
196
|
closeTime: desc.closeTime ?? null,
|
|
191
197
|
taskQueue: desc.taskQueue,
|
|
192
|
-
activitiesCompleted
|
|
193
|
-
activitiesScheduled
|
|
198
|
+
activitiesCompleted,
|
|
199
|
+
activitiesScheduled,
|
|
200
|
+
...(progress ? { progress } : {}),
|
|
201
|
+
gate: gate ?? null,
|
|
194
202
|
};
|
|
195
203
|
return {
|
|
196
204
|
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(result, null, 2) }],
|