@cad0p/pi-steering 0.1.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 +36 -0
- package/LICENSE +29 -0
- package/README.md +920 -0
- package/dist/__test-helpers__.d.ts +95 -0
- package/dist/__test-helpers__.d.ts.map +1 -0
- package/dist/__test-helpers__.js +174 -0
- package/dist/__test-helpers__.js.map +1 -0
- package/dist/bin/pi-steering.d.ts +9 -0
- package/dist/bin/pi-steering.d.ts.map +1 -0
- package/dist/bin/pi-steering.js +506 -0
- package/dist/bin/pi-steering.js.map +1 -0
- package/dist/compat.d.ts +50 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +180 -0
- package/dist/compat.js.map +1 -0
- package/dist/defaults.d.ts +61 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +106 -0
- package/dist/defaults.js.map +1 -0
- package/dist/define-config.d.ts +235 -0
- package/dist/define-config.d.ts.map +1 -0
- package/dist/define-config.js +118 -0
- package/dist/define-config.js.map +1 -0
- package/dist/define-predicate.d.ts +49 -0
- package/dist/define-predicate.d.ts.map +1 -0
- package/dist/define-predicate.js +35 -0
- package/dist/define-predicate.js.map +1 -0
- package/dist/evaluator-internals/context.d.ts +186 -0
- package/dist/evaluator-internals/context.d.ts.map +1 -0
- package/dist/evaluator-internals/context.js +219 -0
- package/dist/evaluator-internals/context.js.map +1 -0
- package/dist/evaluator-internals/override.d.ts +19 -0
- package/dist/evaluator-internals/override.d.ts.map +1 -0
- package/dist/evaluator-internals/override.js +79 -0
- package/dist/evaluator-internals/override.js.map +1 -0
- package/dist/evaluator-internals/predicates.d.ts +152 -0
- package/dist/evaluator-internals/predicates.d.ts.map +1 -0
- package/dist/evaluator-internals/predicates.js +849 -0
- package/dist/evaluator-internals/predicates.js.map +1 -0
- package/dist/evaluator-internals/speculative-synthesis.d.ts +102 -0
- package/dist/evaluator-internals/speculative-synthesis.d.ts.map +1 -0
- package/dist/evaluator-internals/speculative-synthesis.js +101 -0
- package/dist/evaluator-internals/speculative-synthesis.js.map +1 -0
- package/dist/evaluator.d.ts +101 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +714 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/helpers/walker-unknown-cwd-reason.d.ts +68 -0
- package/dist/helpers/walker-unknown-cwd-reason.d.ts.map +1 -0
- package/dist/helpers/walker-unknown-cwd-reason.js +73 -0
- package/dist/helpers/walker-unknown-cwd-reason.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/drop-unused-observers.d.ts +43 -0
- package/dist/internal/drop-unused-observers.d.ts.map +1 -0
- package/dist/internal/drop-unused-observers.js +50 -0
- package/dist/internal/drop-unused-observers.js.map +1 -0
- package/dist/internal/finalize-plugin-state.d.ts +22 -0
- package/dist/internal/finalize-plugin-state.d.ts.map +1 -0
- package/dist/internal/finalize-plugin-state.js +14 -0
- package/dist/internal/finalize-plugin-state.js.map +1 -0
- package/dist/internal/merge-observers.d.ts +30 -0
- package/dist/internal/merge-observers.d.ts.map +1 -0
- package/dist/internal/merge-observers.js +27 -0
- package/dist/internal/merge-observers.js.map +1 -0
- package/dist/internal/pattern-utils.d.ts +33 -0
- package/dist/internal/pattern-utils.d.ts.map +1 -0
- package/dist/internal/pattern-utils.js +20 -0
- package/dist/internal/pattern-utils.js.map +1 -0
- package/dist/internal/ref-text.d.ts +11 -0
- package/dist/internal/ref-text.d.ts.map +1 -0
- package/dist/internal/ref-text.js +15 -0
- package/dist/internal/ref-text.js.map +1 -0
- package/dist/internal/session-runtime.d.ts +44 -0
- package/dist/internal/session-runtime.d.ts.map +1 -0
- package/dist/internal/session-runtime.js +143 -0
- package/dist/internal/session-runtime.js.map +1 -0
- package/dist/internal/watch-matcher.d.ts +56 -0
- package/dist/internal/watch-matcher.d.ts.map +1 -0
- package/dist/internal/watch-matcher.js +179 -0
- package/dist/internal/watch-matcher.js.map +1 -0
- package/dist/loader.d.ts +97 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +527 -0
- package/dist/loader.js.map +1 -0
- package/dist/observer-dispatcher.d.ts +69 -0
- package/dist/observer-dispatcher.d.ts.map +1 -0
- package/dist/observer-dispatcher.js +184 -0
- package/dist/observer-dispatcher.js.map +1 -0
- package/dist/plugin-merger.d.ts +175 -0
- package/dist/plugin-merger.d.ts.map +1 -0
- package/dist/plugin-merger.js +450 -0
- package/dist/plugin-merger.js.map +1 -0
- package/dist/plugins/git/branch-tracker.d.ts +85 -0
- package/dist/plugins/git/branch-tracker.d.ts.map +1 -0
- package/dist/plugins/git/branch-tracker.js +181 -0
- package/dist/plugins/git/branch-tracker.js.map +1 -0
- package/dist/plugins/git/cwd-extensions.d.ts +10 -0
- package/dist/plugins/git/cwd-extensions.d.ts.map +1 -0
- package/dist/plugins/git/cwd-extensions.js +155 -0
- package/dist/plugins/git/cwd-extensions.js.map +1 -0
- package/dist/plugins/git/git-ops.d.ts +89 -0
- package/dist/plugins/git/git-ops.d.ts.map +1 -0
- package/dist/plugins/git/git-ops.js +107 -0
- package/dist/plugins/git/git-ops.js.map +1 -0
- package/dist/plugins/git/index.d.ts +225 -0
- package/dist/plugins/git/index.d.ts.map +1 -0
- package/dist/plugins/git/index.js +52 -0
- package/dist/plugins/git/index.js.map +1 -0
- package/dist/plugins/git/predicates.d.ts +312 -0
- package/dist/plugins/git/predicates.d.ts.map +1 -0
- package/dist/plugins/git/predicates.js +580 -0
- package/dist/plugins/git/predicates.js.map +1 -0
- package/dist/plugins/git/rules.d.ts +209 -0
- package/dist/plugins/git/rules.d.ts.map +1 -0
- package/dist/plugins/git/rules.js +267 -0
- package/dist/plugins/git/rules.js.map +1 -0
- package/dist/schema.d.ts +1799 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +4 -0
- package/dist/schema.js.map +1 -0
- package/dist/testing/index.d.ts +621 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +747 -0
- package/dist/testing/index.js.map +1 -0
- package/examples/README.md +83 -0
- package/examples/combined-git-discipline/README.md +52 -0
- package/examples/combined-git-discipline/node_modules/.bin/pi-steering +43 -0
- package/examples/combined-git-discipline/package.json +18 -0
- package/examples/combined-git-discipline/steering.json +27 -0
- package/examples/combined-git-discipline/steering.test.ts +42 -0
- package/examples/combined-git-discipline/steering.ts +64 -0
- package/examples/combined-git-discipline/tsconfig.json +7 -0
- package/examples/draft-prs-only/README.md +42 -0
- package/examples/draft-prs-only/node_modules/.bin/pi-steering +43 -0
- package/examples/draft-prs-only/package.json +18 -0
- package/examples/draft-prs-only/steering.json +12 -0
- package/examples/draft-prs-only/steering.test.ts +48 -0
- package/examples/draft-prs-only/steering.ts +36 -0
- package/examples/draft-prs-only/tsconfig.json +7 -0
- package/examples/dynamic-reason-runtime-cwd/README.md +148 -0
- package/examples/dynamic-reason-runtime-cwd/node_modules/.bin/pi-steering +43 -0
- package/examples/dynamic-reason-runtime-cwd/package.json +18 -0
- package/examples/dynamic-reason-runtime-cwd/steering.test.ts +130 -0
- package/examples/dynamic-reason-runtime-cwd/steering.ts +82 -0
- package/examples/dynamic-reason-runtime-cwd/tsconfig.json +7 -0
- package/examples/force-push-strict/README.md +75 -0
- package/examples/force-push-strict/node_modules/.bin/pi-steering +43 -0
- package/examples/force-push-strict/package.json +18 -0
- package/examples/force-push-strict/steering.json +12 -0
- package/examples/force-push-strict/steering.test.ts +51 -0
- package/examples/force-push-strict/steering.ts +54 -0
- package/examples/force-push-strict/tsconfig.json +7 -0
- package/examples/no-amend/README.md +52 -0
- package/examples/no-amend/node_modules/.bin/pi-steering +43 -0
- package/examples/no-amend/package.json +18 -0
- package/examples/no-amend/steering.cwd-scoped.json +12 -0
- package/examples/no-amend/steering.json +11 -0
- package/examples/no-amend/steering.test.ts +49 -0
- package/examples/no-amend/steering.ts +38 -0
- package/examples/no-amend/tsconfig.json +7 -0
- package/examples/work-item-plugin/README.md +103 -0
- package/examples/work-item-plugin/node_modules/.bin/pi-steering +43 -0
- package/examples/work-item-plugin/package.json +19 -0
- package/examples/work-item-plugin/src/index.test.ts +168 -0
- package/examples/work-item-plugin/src/index.ts +122 -0
- package/examples/work-item-plugin/src/observers/npm-test-tracker.test.ts +95 -0
- package/examples/work-item-plugin/src/observers/npm-test-tracker.ts +88 -0
- package/examples/work-item-plugin/src/observers/retest-required-tracker.test.ts +81 -0
- package/examples/work-item-plugin/src/observers/retest-required-tracker.ts +81 -0
- package/examples/work-item-plugin/src/predicates/work-item-format.test.ts +157 -0
- package/examples/work-item-plugin/src/predicates/work-item-format.ts +99 -0
- package/examples/work-item-plugin/src/rules/commit-description-check.test.ts +107 -0
- package/examples/work-item-plugin/src/rules/commit-description-check.ts +83 -0
- package/examples/work-item-plugin/src/rules/commit-requires-work-item.test.ts +79 -0
- package/examples/work-item-plugin/src/rules/commit-requires-work-item.ts +56 -0
- package/examples/work-item-plugin/src/rules/push-requires-tests.test.ts +245 -0
- package/examples/work-item-plugin/src/rules/push-requires-tests.ts +62 -0
- package/examples/work-item-plugin/tsconfig.json +8 -0
- package/package.json +88 -0
- package/skills/steering-authoring/SKILL.md +102 -0
- package/src/INVARIANTS.md +116 -0
- package/src/__test-helpers__.ts +243 -0
- package/src/bin/pi-steering.test.ts +920 -0
- package/src/bin/pi-steering.ts +584 -0
- package/src/compat.test.ts +431 -0
- package/src/compat.ts +282 -0
- package/src/defaults.test.ts +585 -0
- package/src/defaults.ts +148 -0
- package/src/define-config.test.ts +888 -0
- package/src/define-config.ts +375 -0
- package/src/define-predicate.test.ts +70 -0
- package/src/define-predicate.ts +57 -0
- package/src/evaluator-internals/context.ts +290 -0
- package/src/evaluator-internals/override.test.ts +99 -0
- package/src/evaluator-internals/override.ts +83 -0
- package/src/evaluator-internals/predicates.ts +1037 -0
- package/src/evaluator-internals/speculative-synthesis.test.ts +411 -0
- package/src/evaluator-internals/speculative-synthesis.ts +199 -0
- package/src/evaluator.test.ts +6296 -0
- package/src/evaluator.ts +1106 -0
- package/src/factory-time-load.test.ts +630 -0
- package/src/helpers/walker-unknown-cwd-reason.test.ts +73 -0
- package/src/helpers/walker-unknown-cwd-reason.ts +83 -0
- package/src/index.test.ts +836 -0
- package/src/index.ts +229 -0
- package/src/internal/drop-unused-observers.test.ts +141 -0
- package/src/internal/drop-unused-observers.ts +81 -0
- package/src/internal/finalize-plugin-state.ts +43 -0
- package/src/internal/merge-observers.ts +51 -0
- package/src/internal/pattern-utils.test.ts +52 -0
- package/src/internal/pattern-utils.ts +38 -0
- package/src/internal/ref-text.test.ts +54 -0
- package/src/internal/ref-text.ts +17 -0
- package/src/internal/session-runtime.test.ts +629 -0
- package/src/internal/session-runtime.ts +201 -0
- package/src/internal/watch-matcher.test.ts +326 -0
- package/src/internal/watch-matcher.ts +200 -0
- package/src/jsdoc-propagation.test.ts +277 -0
- package/src/loader.test.ts +1098 -0
- package/src/loader.ts +581 -0
- package/src/not-block-onunknown.test.ts +554 -0
- package/src/observer-dispatcher.test.ts +939 -0
- package/src/observer-dispatcher.ts +290 -0
- package/src/per-predicate-typing.test.ts +361 -0
- package/src/plugin-merger.test.ts +790 -0
- package/src/plugin-merger.ts +598 -0
- package/src/plugins/git/README.md +485 -0
- package/src/plugins/git/branch-tracker.test.ts +281 -0
- package/src/plugins/git/branch-tracker.ts +187 -0
- package/src/plugins/git/cwd-extensions.test.ts +230 -0
- package/src/plugins/git/cwd-extensions.ts +160 -0
- package/src/plugins/git/git-ops.test.ts +397 -0
- package/src/plugins/git/git-ops.ts +173 -0
- package/src/plugins/git/index.ts +253 -0
- package/src/plugins/git/integration.test.ts +705 -0
- package/src/plugins/git/predicates.test.ts +1401 -0
- package/src/plugins/git/predicates.ts +693 -0
- package/src/plugins/git/rules.test.ts +1001 -0
- package/src/plugins/git/rules.ts +307 -0
- package/src/schema.test.ts +259 -0
- package/src/schema.ts +1963 -0
- package/src/testing/index.test.ts +1696 -0
- package/src/testing/index.ts +1472 -0
package/dist/loader.js
ADDED
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Part of pi-steering.
|
|
3
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
4
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
5
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
6
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
return path;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* TS config loader. Walk up cwd → `$HOME`, find `.pi/steering/index.ts`
|
|
13
|
+
* or `.pi/steering.ts` per layer, dynamic-import each, merge
|
|
14
|
+
* inner-first. Per-symbol JSDoc carries the contract; see also the
|
|
15
|
+
* {@link SteeringDiagnostic} / {@link SteeringDiagnosticKind} JSDoc
|
|
16
|
+
* for the diagnostic stream.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
19
|
+
import { dirname, join, resolve } from "node:path";
|
|
20
|
+
import { pathToFileURL } from "node:url";
|
|
21
|
+
import { EVALUATOR_BUILTIN_TRACKERS } from "./evaluator.js";
|
|
22
|
+
import { runMergerPipeline } from "./internal/session-runtime.js";
|
|
23
|
+
import { formatTrackerNameCollisionMessage } from "./plugin-merger.js";
|
|
24
|
+
/**
|
|
25
|
+
* Minimum Node version that supports native `.ts` import via type
|
|
26
|
+
* stripping (without a `--experimental-strip-types` flag). Shipped
|
|
27
|
+
* stable in Node 22.6+. We require 22.x outright to keep the error
|
|
28
|
+
* message simple.
|
|
29
|
+
*/
|
|
30
|
+
const MIN_NODE_MAJOR = 22;
|
|
31
|
+
/**
|
|
32
|
+
* Runtime check: throws when Node is older than the minimum required
|
|
33
|
+
* for native `.ts` import. See README §Install for the supported
|
|
34
|
+
* Node range.
|
|
35
|
+
*/
|
|
36
|
+
function assertNodeVersion() {
|
|
37
|
+
const raw = process.versions.node;
|
|
38
|
+
const major = Number.parseInt(raw.split(".")[0] ?? "0", 10);
|
|
39
|
+
if (Number.isNaN(major) || major < MIN_NODE_MAJOR) {
|
|
40
|
+
throw new Error(`pi-steering requires Node >= ${MIN_NODE_MAJOR} ` +
|
|
41
|
+
`for native .ts loading (found ${raw}). ` +
|
|
42
|
+
`Upgrade Node, or stay on v1 JSON configs (\`.pi/steering.json\`).`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Discovery
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
/**
|
|
49
|
+
* Candidate file paths for a given directory's `.pi/steering/...` slot,
|
|
50
|
+
* in priority order. First existing file wins.
|
|
51
|
+
*
|
|
52
|
+
* Exported for tests — not part of the library's public API.
|
|
53
|
+
*/
|
|
54
|
+
export function configCandidates(dir) {
|
|
55
|
+
return [
|
|
56
|
+
join(dir, ".pi", "steering", "index.ts"),
|
|
57
|
+
join(dir, ".pi", "steering.ts"),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Return the non-`.ts` files that exist under `<dir>/.pi/steering/` so
|
|
62
|
+
* callers can warn about them. Uses a best-effort fs read: a missing
|
|
63
|
+
* directory returns an empty list.
|
|
64
|
+
*/
|
|
65
|
+
function unexpectedFilesUnderSteering(dir) {
|
|
66
|
+
const steeringDir = join(dir, ".pi", "steering");
|
|
67
|
+
if (!existsSync(steeringDir))
|
|
68
|
+
return [];
|
|
69
|
+
try {
|
|
70
|
+
const entries = readdirSync(steeringDir);
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const name of entries) {
|
|
73
|
+
const full = join(steeringDir, name);
|
|
74
|
+
try {
|
|
75
|
+
const st = statSync(full);
|
|
76
|
+
if (!st.isFile())
|
|
77
|
+
continue;
|
|
78
|
+
if (name === "index.ts")
|
|
79
|
+
continue;
|
|
80
|
+
if (name.endsWith(".ts"))
|
|
81
|
+
continue; // allow helpers like `rules.ts`
|
|
82
|
+
out.push(full);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// skip unreadable entry
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Walk up from `cwd` to `$HOME` (inclusive, or to the filesystem root
|
|
96
|
+
* if HOME is unset / outside the cwd's ancestry), returning the list
|
|
97
|
+
* of directories INNER-FIRST — so `[cwd, cwd/parent, ..., HOME]`.
|
|
98
|
+
*
|
|
99
|
+
* Exported for tests.
|
|
100
|
+
*/
|
|
101
|
+
export function ancestorChain(cwd) {
|
|
102
|
+
const home = process.env["HOME"] ?? "";
|
|
103
|
+
const out = [];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
let current = resolve(cwd);
|
|
106
|
+
while (true) {
|
|
107
|
+
if (seen.has(current))
|
|
108
|
+
break; // symlink-loop guard
|
|
109
|
+
seen.add(current);
|
|
110
|
+
out.push(current);
|
|
111
|
+
if (current === home || current === "/")
|
|
112
|
+
break;
|
|
113
|
+
const parent = dirname(current);
|
|
114
|
+
if (parent === current)
|
|
115
|
+
break; // filesystem root
|
|
116
|
+
current = parent;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Find the config file (if any) for a single layer. Returns the
|
|
122
|
+
* resolved file path and a `layer-form-coexistence` diagnostic when
|
|
123
|
+
* both `.pi/steering/index.ts` and `.pi/steering.ts` coexist in the
|
|
124
|
+
* same directory (the directory form wins).
|
|
125
|
+
*
|
|
126
|
+
* Exported for tests.
|
|
127
|
+
*/
|
|
128
|
+
export function findConfigFile(dir) {
|
|
129
|
+
const [indexForm, flatForm] = configCandidates(dir);
|
|
130
|
+
const indexExists = indexForm !== undefined && existsSync(indexForm);
|
|
131
|
+
const flatExists = flatForm !== undefined && existsSync(flatForm);
|
|
132
|
+
let diagnostic = null;
|
|
133
|
+
if (indexExists && flatExists && indexForm !== undefined) {
|
|
134
|
+
// `path` points at the directory holding the conflict so the
|
|
135
|
+
// renderer's `${path}: ${message}` prefix surfaces the parent
|
|
136
|
+
// once and the message names which two forms coexist. The winning
|
|
137
|
+
// file path is implicit (the directory form always wins).
|
|
138
|
+
diagnostic = {
|
|
139
|
+
type: "warning",
|
|
140
|
+
kind: "layer-form-coexistence",
|
|
141
|
+
path: dir,
|
|
142
|
+
message: "both .pi/steering.ts and .pi/steering/index.ts exist; using " +
|
|
143
|
+
"directory form. Delete .pi/steering.ts to remove this warning.",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (indexExists)
|
|
147
|
+
return { file: indexForm ?? null, diagnostic };
|
|
148
|
+
if (flatExists)
|
|
149
|
+
return { file: flatForm ?? null, diagnostic };
|
|
150
|
+
return { file: null, diagnostic };
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Loading
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
/**
|
|
156
|
+
* Dynamic-import a single config file and return its default export.
|
|
157
|
+
* The module MUST `export default` a {@link SteeringConfig} object —
|
|
158
|
+
* the loader does not accept module-namespace imports as a fallback,
|
|
159
|
+
* to keep the authoring contract unambiguous.
|
|
160
|
+
*
|
|
161
|
+
* Throws a scoped error when the import fails, when the module has no
|
|
162
|
+
* default export, or when the default export isn't a plain object —
|
|
163
|
+
* the caller surfaces these per-layer without bringing the whole
|
|
164
|
+
* session down (a single bad layer shouldn't nuke the engine).
|
|
165
|
+
*
|
|
166
|
+
* Each call appends a unique `?t=<timestamp>` query string to the
|
|
167
|
+
* import URL. Node's ESM module map is keyed on URL and persists for
|
|
168
|
+
* the lifetime of the process, so a plain `await import(url)` returns
|
|
169
|
+
* the cached module forever — even after `/reload` and even after
|
|
170
|
+
* the file's content has changed (or, worse, after a previous load
|
|
171
|
+
* threw, since failed loads are also cached). The cache-bust forces
|
|
172
|
+
* Node to re-fetch and re-evaluate the file each call. See the
|
|
173
|
+
* "Hot-reload" section in the README for the limits of this approach
|
|
174
|
+
* (it does NOT bust transitively-imported plugin packages, which the
|
|
175
|
+
* user config reaches via static `import` of bare specifiers like
|
|
176
|
+
* `"pi-steering"` — those still require a full pi restart).
|
|
177
|
+
*/
|
|
178
|
+
async function importConfigFile(path) {
|
|
179
|
+
const url = pathToFileURL(path).href;
|
|
180
|
+
/**
|
|
181
|
+
* Cache-bust query string. `process.hrtime.bigint()` returns
|
|
182
|
+
* monotonic nanoseconds since an arbitrary process-relative
|
|
183
|
+
* origin — each call returns a strictly greater value, even
|
|
184
|
+
* back-to-back within the same millisecond, so no two
|
|
185
|
+
* `importConfigFile` invocations ever share a URL. If a future
|
|
186
|
+
* Node version changes the cache-bust contract (e.g. ignores
|
|
187
|
+
* query strings on `file:` URLs), this will silently revert to
|
|
188
|
+
* the cached-forever behavior, and the integration tests in
|
|
189
|
+
* `loader.test.ts` will fail.
|
|
190
|
+
*/
|
|
191
|
+
const bust = `${url.includes("?") ? "&" : "?"}t=${process.hrtime.bigint()}`;
|
|
192
|
+
const mod = (await import(__rewriteRelativeImportExtension(url + bust)));
|
|
193
|
+
if (mod.default === undefined) {
|
|
194
|
+
// Path is intentionally omitted from the message; the caller wraps
|
|
195
|
+
// this throw in a `layer-import-failed` diagnostic whose own `path`
|
|
196
|
+
// field is the single source of truth for the file location.
|
|
197
|
+
throw new Error("config file must have a default export. Use " +
|
|
198
|
+
"`export default { ... } satisfies SteeringConfig` or " +
|
|
199
|
+
"`export default defineConfig({ ... })`.");
|
|
200
|
+
}
|
|
201
|
+
const candidate = mod.default;
|
|
202
|
+
if (candidate === null ||
|
|
203
|
+
typeof candidate !== "object" ||
|
|
204
|
+
Array.isArray(candidate)) {
|
|
205
|
+
throw new Error(`config file default export must be a SteeringConfig object, ` +
|
|
206
|
+
`got ${Array.isArray(candidate) ? "array" : typeof candidate}.`);
|
|
207
|
+
}
|
|
208
|
+
return candidate;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Walk up from `cwd` collecting config layers. Returns INNER-FIRST
|
|
212
|
+
* (caller passes to {@link buildConfig}, which expects inner-first so
|
|
213
|
+
* early entries take precedence on collisions).
|
|
214
|
+
*
|
|
215
|
+
* Issues encountered along the way (per-layer import failure, dual
|
|
216
|
+
* form coexistence, stray non-`.ts` file under `.pi/steering/`)
|
|
217
|
+
* surface as structured {@link SteeringDiagnostic} entries on the
|
|
218
|
+
* returned object. The loader does not log to `console.warn` directly
|
|
219
|
+
* — the bridge runtime owns the policy decision (throw vs. log) once
|
|
220
|
+
* it has collected diagnostics from every source.
|
|
221
|
+
*
|
|
222
|
+
* @throws when Node is older than {@link MIN_NODE_MAJOR}.
|
|
223
|
+
*/
|
|
224
|
+
export async function loadConfigs(cwd) {
|
|
225
|
+
assertNodeVersion();
|
|
226
|
+
const dirs = ancestorChain(cwd);
|
|
227
|
+
const layers = [];
|
|
228
|
+
const diagnostics = [];
|
|
229
|
+
for (const dir of dirs) {
|
|
230
|
+
const { file, diagnostic } = findConfigFile(dir);
|
|
231
|
+
if (diagnostic !== null)
|
|
232
|
+
diagnostics.push(diagnostic);
|
|
233
|
+
if (file === null) {
|
|
234
|
+
// Surface stray files under `.pi/steering/` that the loader
|
|
235
|
+
// won't pick up. Only check when the directory exists but has
|
|
236
|
+
// no `index.ts` — otherwise a project without any steering
|
|
237
|
+
// directory would emit noise.
|
|
238
|
+
const steeringDir = join(dir, ".pi", "steering");
|
|
239
|
+
if (existsSync(steeringDir)) {
|
|
240
|
+
for (const stray of unexpectedFilesUnderSteering(dir)) {
|
|
241
|
+
diagnostics.push({
|
|
242
|
+
type: "warning",
|
|
243
|
+
kind: "layer-stray-file",
|
|
244
|
+
path: stray,
|
|
245
|
+
message: "ignoring non-.ts file under .pi/steering/",
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
layers.push(await importConfigFile(file));
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
// Use err.message to drop the `Error: ` class prefix; native
|
|
256
|
+
// runtime errors (jiti syntax errors) may embed their path inside
|
|
257
|
+
// the message and we accept that duplication.
|
|
258
|
+
const body = err instanceof Error ? err.message : String(err);
|
|
259
|
+
diagnostics.push({
|
|
260
|
+
type: "warning",
|
|
261
|
+
kind: "layer-import-failed",
|
|
262
|
+
path: file,
|
|
263
|
+
message: `failed to import: ${body}`,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return { layers, diagnostics };
|
|
268
|
+
}
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
// Merging
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
/**
|
|
273
|
+
* Collect plugins across layers, recording a diagnostic for each
|
|
274
|
+
* cross-layer duplicate plugin name. First-registered wins (inner
|
|
275
|
+
* layer is first — matches pi's project-local → global convention).
|
|
276
|
+
*
|
|
277
|
+
* The caller is responsible for unioning `config.disabledPlugins`
|
|
278
|
+
* across layers and passing the result as `disabledPlugins` (see
|
|
279
|
+
* `buildConfig`). Plugins whose name appears in the supplied set are
|
|
280
|
+
* still merged into the output (so downstream surfaces like
|
|
281
|
+
* `pi-steering list` can render them tagged as disabled), but they're
|
|
282
|
+
* EXEMPT from collision detection. A user resolving a duplicate-plugin
|
|
283
|
+
* warning by adding the plugin to `disabledPlugins` should see the
|
|
284
|
+
* warning go away in the same config edit; detect-then-disable would
|
|
285
|
+
* still surface the warning even though the disable already settled
|
|
286
|
+
* the conflict.
|
|
287
|
+
*/
|
|
288
|
+
function mergePlugins(layers, disabledPlugins, diagnostics) {
|
|
289
|
+
const seen = new Set();
|
|
290
|
+
const out = [];
|
|
291
|
+
for (const layer of layers) {
|
|
292
|
+
if (!layer.plugins)
|
|
293
|
+
continue;
|
|
294
|
+
for (const plugin of layer.plugins) {
|
|
295
|
+
if (seen.has(plugin.name)) {
|
|
296
|
+
if (!disabledPlugins.has(plugin.name)) {
|
|
297
|
+
diagnostics.push({
|
|
298
|
+
type: "warning",
|
|
299
|
+
kind: "plugin-name-collision",
|
|
300
|
+
message: `duplicate plugin "${plugin.name}"; keeping first-registered entry.`,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
seen.add(plugin.name);
|
|
306
|
+
out.push(plugin);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return out;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Merge rules across layers — inner layer's rule name overrides outer.
|
|
313
|
+
* Declaration order within a layer is preserved; cross-layer order is
|
|
314
|
+
* "first layer that mentions a given rule name wins for its slot".
|
|
315
|
+
*
|
|
316
|
+
* Records a diagnostic on duplicate names WITHIN a single layer
|
|
317
|
+
* (authoring mistake) — mirrors {@link mergeObservers}. Cross-layer
|
|
318
|
+
* collisions stay silent: overriding a rule by name is the documented
|
|
319
|
+
* customization path.
|
|
320
|
+
*
|
|
321
|
+
* Disabled rules are merged but exempt from collision detection (see
|
|
322
|
+
* {@link mergePlugins} for rationale).
|
|
323
|
+
*/
|
|
324
|
+
function mergeRules(layers, disabledRules, diagnostics) {
|
|
325
|
+
const byName = new Map();
|
|
326
|
+
for (const layer of layers) {
|
|
327
|
+
if (!layer.rules)
|
|
328
|
+
continue;
|
|
329
|
+
const seenInLayer = new Set();
|
|
330
|
+
for (const rule of layer.rules) {
|
|
331
|
+
if (seenInLayer.has(rule.name)) {
|
|
332
|
+
if (!disabledRules.has(rule.name)) {
|
|
333
|
+
diagnostics.push({
|
|
334
|
+
type: "warning",
|
|
335
|
+
kind: "rule-name-collision",
|
|
336
|
+
message: `duplicate rule "${rule.name}" within single config layer; ` +
|
|
337
|
+
"keeping first, dropping subsequent",
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
seenInLayer.add(rule.name);
|
|
343
|
+
if (!byName.has(rule.name)) {
|
|
344
|
+
byName.set(rule.name, rule);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return [...byName.values()];
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Merge observers across layers — inner layer's observer name
|
|
352
|
+
* overrides outer. Records a diagnostic on duplicate names WITHIN a
|
|
353
|
+
* single layer (authoring mistake); cross-layer overrides are silent
|
|
354
|
+
* (intentional customization).
|
|
355
|
+
*/
|
|
356
|
+
function mergeObservers(layers, diagnostics) {
|
|
357
|
+
const byName = new Map();
|
|
358
|
+
for (const layer of layers) {
|
|
359
|
+
if (!layer.observers)
|
|
360
|
+
continue;
|
|
361
|
+
const seenInLayer = new Set();
|
|
362
|
+
for (const obs of layer.observers) {
|
|
363
|
+
if (seenInLayer.has(obs.name)) {
|
|
364
|
+
diagnostics.push({
|
|
365
|
+
type: "warning",
|
|
366
|
+
kind: "observer-name-collision",
|
|
367
|
+
message: `duplicate observer "${obs.name}"; keeping first-registered entry.`,
|
|
368
|
+
});
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
seenInLayer.add(obs.name);
|
|
372
|
+
if (!byName.has(obs.name)) {
|
|
373
|
+
byName.set(obs.name, obs);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return [...byName.values()];
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Merge simple string-list fields (`disabledRules`, `disabledPlugins`)
|
|
381
|
+
* as a union across layers. Preserves first-seen order for deterministic
|
|
382
|
+
* output in tests.
|
|
383
|
+
*/
|
|
384
|
+
function mergeStringUnion(layers, key) {
|
|
385
|
+
const seen = new Set();
|
|
386
|
+
let any = false;
|
|
387
|
+
for (const layer of layers) {
|
|
388
|
+
const list = layer[key];
|
|
389
|
+
if (list === undefined)
|
|
390
|
+
continue;
|
|
391
|
+
any = true;
|
|
392
|
+
for (const item of list)
|
|
393
|
+
seen.add(item);
|
|
394
|
+
}
|
|
395
|
+
return any ? [...seen] : undefined;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Inner-wins boolean merge over walked-up layers. Walks left-to-right
|
|
399
|
+
* (inner-first); returns the first explicit boolean or `undefined`.
|
|
400
|
+
* Used by `buildConfig` and the session runtime for the inner-wins
|
|
401
|
+
* boolean fields. Internal — not in the package's `exports` surface.
|
|
402
|
+
*/
|
|
403
|
+
export function mergeBool(layers, key) {
|
|
404
|
+
for (const layer of layers) {
|
|
405
|
+
const v = layer[key];
|
|
406
|
+
if (typeof v === "boolean")
|
|
407
|
+
return v;
|
|
408
|
+
}
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Detect plugins registering a tracker under the same name and push
|
|
413
|
+
* an error-class diagnostic for each collision. Two plugins claiming
|
|
414
|
+
* the same state dimension is always a bug; the runtime escalates
|
|
415
|
+
* these to a thrown error regardless of the user's strict-mode
|
|
416
|
+
* preference.
|
|
417
|
+
*
|
|
418
|
+
* Plugins whose name appears in `disabledPlugins` are skipped before
|
|
419
|
+
* collision detection (mirrors {@link mergePlugins}).
|
|
420
|
+
*/
|
|
421
|
+
function detectTrackerNameCollisions(plugins, disabledPlugins, diagnostics) {
|
|
422
|
+
const seen = new Map(); // trackerName -> pluginName
|
|
423
|
+
for (const plugin of plugins) {
|
|
424
|
+
if (disabledPlugins.has(plugin.name))
|
|
425
|
+
continue;
|
|
426
|
+
if (!plugin.trackers)
|
|
427
|
+
continue;
|
|
428
|
+
for (const trackerName of Object.keys(plugin.trackers)) {
|
|
429
|
+
const prior = seen.get(trackerName);
|
|
430
|
+
if (prior !== undefined) {
|
|
431
|
+
diagnostics.push({
|
|
432
|
+
type: "error",
|
|
433
|
+
kind: "tracker-name-collision",
|
|
434
|
+
message: formatTrackerNameCollisionMessage(prior, plugin.name, trackerName),
|
|
435
|
+
});
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
seen.set(trackerName, plugin.name);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Merge `layers` (inner-first) into a single effective
|
|
444
|
+
* {@link SteeringConfig}. An optional `defaults` config is treated as
|
|
445
|
+
* the OUTERMOST layer — its fields apply when no real layer specifies
|
|
446
|
+
* them, otherwise real layers override.
|
|
447
|
+
*
|
|
448
|
+
* Cross-layer plugin name collisions, within-layer rule + observer
|
|
449
|
+
* name collisions, and cross-layer tracker name collisions surface
|
|
450
|
+
* as structured {@link SteeringDiagnostic} entries on the returned
|
|
451
|
+
* object. Predicate-key + tracker-extension collisions are detected
|
|
452
|
+
* in `resolvePlugins`, not here — buildConfig handles cross-layer and
|
|
453
|
+
* within-layer name-collision shapes only.
|
|
454
|
+
*/
|
|
455
|
+
export function buildConfig(layers, defaults) {
|
|
456
|
+
// Build the effective inner-first layer list. `defaults` goes at
|
|
457
|
+
// the END (outermost position) so inner real layers override it.
|
|
458
|
+
const effective = [...layers];
|
|
459
|
+
if (defaults !== undefined)
|
|
460
|
+
effective.push(defaults);
|
|
461
|
+
const diagnostics = [];
|
|
462
|
+
const disabledPluginsList = mergeStringUnion(effective, "disabledPlugins");
|
|
463
|
+
const disabledRulesList = mergeStringUnion(effective, "disabledRules");
|
|
464
|
+
const disabledPluginsSet = new Set(disabledPluginsList ?? []);
|
|
465
|
+
const disabledRulesSet = new Set(disabledRulesList ?? []);
|
|
466
|
+
// Predicate + tracker-extension collisions are detected in
|
|
467
|
+
// resolvePlugins, not here. buildConfig handles cross-layer and
|
|
468
|
+
// within-layer name-collision shapes only.
|
|
469
|
+
const plugins = mergePlugins(effective, disabledPluginsSet, diagnostics);
|
|
470
|
+
detectTrackerNameCollisions(plugins, disabledPluginsSet, diagnostics);
|
|
471
|
+
const rules = mergeRules(effective, disabledRulesSet, diagnostics);
|
|
472
|
+
const observers = mergeObservers(effective, diagnostics);
|
|
473
|
+
const out = {};
|
|
474
|
+
if (plugins.length > 0)
|
|
475
|
+
out.plugins = plugins;
|
|
476
|
+
if (rules.length > 0)
|
|
477
|
+
out.rules = rules;
|
|
478
|
+
if (observers.length > 0)
|
|
479
|
+
out.observers = observers;
|
|
480
|
+
if (disabledRulesList !== undefined)
|
|
481
|
+
out.disabledRules = disabledRulesList;
|
|
482
|
+
if (disabledPluginsList !== undefined) {
|
|
483
|
+
out.disabledPlugins = disabledPluginsList;
|
|
484
|
+
}
|
|
485
|
+
const defaultNoOverride = mergeBool(effective, "defaultNoOverride");
|
|
486
|
+
if (defaultNoOverride !== undefined) {
|
|
487
|
+
out.defaultNoOverride = defaultNoOverride;
|
|
488
|
+
}
|
|
489
|
+
const disableDefaults = mergeBool(effective, "disableDefaults");
|
|
490
|
+
if (disableDefaults !== undefined)
|
|
491
|
+
out.disableDefaults = disableDefaults;
|
|
492
|
+
const failOnWarnings = mergeBool(effective, "failOnWarnings");
|
|
493
|
+
if (failOnWarnings !== undefined)
|
|
494
|
+
out.failOnWarnings = failOnWarnings;
|
|
495
|
+
return { config: out, diagnostics };
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Convenience: load all layers for `cwd`, run the loader-side merge
|
|
499
|
+
* (`buildConfig`), then the plugin merger (`resolvePlugins`) with
|
|
500
|
+
* user-config rule + observer name validation between the two passes.
|
|
501
|
+
* Diagnostics from every surface flow into a single returned array,
|
|
502
|
+
* so an external embedder writing their own bridge or pre-flight
|
|
503
|
+
* check sees the SAME diagnostic stream the production runtime sees
|
|
504
|
+
* — no surface is silently skipped.
|
|
505
|
+
*
|
|
506
|
+
* Diagnostics return in declaration order; merge-side errors
|
|
507
|
+
* short-circuit `resolvePlugins` before its diagnostics are added.
|
|
508
|
+
*
|
|
509
|
+
* Production-strictness divergence: `loadSteeringConfig` does NOT
|
|
510
|
+
* apply the strict-mode `failOnWarnings` throw policy that
|
|
511
|
+
* `buildSessionRuntime` does. The function never throws on
|
|
512
|
+
* diagnostics; embedders apply their own throw + warning policy.
|
|
513
|
+
* See `failOnWarnings` on {@link SteeringConfig} for production-
|
|
514
|
+
* faithful pre-flight semantics.
|
|
515
|
+
*
|
|
516
|
+
* @throws when Node < {@link MIN_NODE_MAJOR} (propagated from
|
|
517
|
+
* `loadConfigs`).
|
|
518
|
+
*/
|
|
519
|
+
export async function loadSteeringConfig(cwd, defaults) {
|
|
520
|
+
const { layers, diagnostics: loaderDiagnostics } = await loadConfigs(cwd);
|
|
521
|
+
const { merged, diagnostics: mergeAndResolveDiagnostics } = runMergerPipeline(layers, defaults, EVALUATOR_BUILTIN_TRACKERS);
|
|
522
|
+
return {
|
|
523
|
+
config: merged,
|
|
524
|
+
diagnostics: [...loaderDiagnostics, ...mergeAndResolveDiagnostics],
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,uBAAuB;;;;;;;;;AAEvB;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AASvE;;;;;GAKG;AACH,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B;;;;GAIG;AACH,SAAS,iBAAiB;IACxB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,cAAc,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,gCAAgC,cAAc,GAAG;YAC/C,iCAAiC,GAAG,KAAK;YACzC,mEAAmE,CACtE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO;QACL,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC;QACxC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,aAAa,CAAC;KAChC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,4BAA4B,CAAC,GAAW;IAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;oBAAE,SAAS;gBAC3B,IAAI,IAAI,KAAK,UAAU;oBAAE,SAAS;gBAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAAE,SAAS,CAAC,gCAAgC;gBACpE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,MAAM,CAAC,qBAAqB;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,GAAG;YAAE,MAAM;QAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM,CAAC,kBAAkB;QACjD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IAIxC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,SAAS,KAAK,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClE,IAAI,UAAU,GAA8B,IAAI,CAAC;IACjD,IAAI,WAAW,IAAI,UAAU,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QACzD,6DAA6D;QAC7D,8DAA8D;QAC9D,kEAAkE;QAClE,0DAA0D;QAC1D,UAAU,GAAG;YACX,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,wBAAwB;YAC9B,IAAI,EAAE,GAAG;YACT,OAAO,EACL,8DAA8D;gBAC9D,gEAAgE;SACnE,CAAC;IACJ,CAAC;IACD,IAAI,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;IAChE,IAAI,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;IAC9D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IACrC;;;;;;;;;;OAUG;IACH,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IAC5E,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,kCAAC,GAAG,GAAG,IAAI,EAAC,CAEV,CAAC;IAE5B,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9B,mEAAmE;QACnE,oEAAoE;QACpE,6DAA6D;QAC7D,MAAM,IAAI,KAAK,CACb,8CAA8C;YAC5C,uDAAuD;YACvD,yCAAyC,CAC5C,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC;IAC9B,IACE,SAAS,KAAK,IAAI;QAClB,OAAO,SAAS,KAAK,QAAQ;QAC7B,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,8DAA8D;YAC5D,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,SAAS,GAAG,CAClE,CAAC;IACJ,CAAC;IACD,OAAO,SAA2B,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAI3C,iBAAiB,EAAE,CAAC;IAEpB,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,MAAM,WAAW,GAAyB,EAAE,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACjD,IAAI,UAAU,KAAK,IAAI;YAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,4DAA4D;YAC5D,8DAA8D;YAC9D,2DAA2D;YAC3D,8BAA8B;YAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;YACjD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC5B,KAAK,MAAM,KAAK,IAAI,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtD,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,SAAS;wBACf,IAAI,EAAE,kBAAkB;wBACxB,IAAI,EAAE,KAAK;wBACX,OAAO,EAAE,2CAA2C;qBACrD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,6DAA6D;YAC7D,kEAAkE;YAClE,8CAA8C;YAC9C,MAAM,IAAI,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9D,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,qBAAqB;gBAC3B,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,qBAAqB,IAAI,EAAE;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;GAeG;AACH,SAAS,YAAY,CACnB,MAAiC,EACjC,eAAoC,EACpC,WAAiC;IAEjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,SAAS;QAC7B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtC,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,SAAS;wBACf,IAAI,EAAE,uBAAuB;wBAC7B,OAAO,EAAE,qBAAqB,MAAM,CAAC,IAAI,oCAAoC;qBAC9E,CAAC,CAAC;gBACL,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACtB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,UAAU,CACjB,MAAiC,EACjC,aAAkC,EAClC,WAAiC;IAEjC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgB,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,SAAS;QAC3B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QACtC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClC,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,SAAS;wBACf,IAAI,EAAE,qBAAqB;wBAC3B,OAAO,EACL,mBAAmB,IAAI,CAAC,IAAI,gCAAgC;4BAC5D,oCAAoC;qBACvC,CAAC,CAAC;gBACL,CAAC;gBACD,SAAS;YACX,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CACrB,MAAiC,EACjC,WAAiC;IAEjC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,SAAS;YAAE,SAAS;QAC/B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QACtC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClC,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,WAAW,CAAC,IAAI,CAAC;oBACf,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,yBAAyB;oBAC/B,OAAO,EAAE,uBAAuB,GAAG,CAAC,IAAI,oCAAoC;iBAC7E,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,MAAiC,EACjC,GAAwC;IAExC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,GAAG,GAAG,IAAI,CAAC;QACX,KAAK,MAAM,IAAI,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CACvB,MAAiC,EACjC,GAA+D;IAE/D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,OAAO,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,2BAA2B,CAClC,OAA0B,EAC1B,eAAoC,EACpC,WAAiC;IAEjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAC,4BAA4B;IACpE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,SAAS;QAC/C,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,SAAS;QAC/B,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,WAAW,CAAC,IAAI,CAAC;oBACf,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,wBAAwB;oBAC9B,OAAO,EAAE,iCAAiC,CACxC,KAAK,EACL,MAAM,CAAC,IAAI,EACX,WAAW,CACZ;iBACF,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,MAAiC,EACjC,QAAyB;IAEzB,iEAAiE;IACjE,iEAAiE;IACjE,MAAM,SAAS,GAAqB,CAAC,GAAG,MAAM,CAAC,CAAC;IAChD,IAAI,QAAQ,KAAK,SAAS;QAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAErD,MAAM,WAAW,GAAyB,EAAE,CAAC;IAE7C,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAC3E,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACvE,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IAE1D,2DAA2D;IAC3D,gEAAgE;IAChE,2CAA2C;IAC3C,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,kBAAkB,EAAE,WAAW,CAAC,CAAC;IACzE,2BAA2B,CAAC,OAAO,EAAE,kBAAkB,EAAE,WAAW,CAAC,CAAC;IAEtE,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAEzD,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IAC9C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IACxC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;IAEpD,IAAI,iBAAiB,KAAK,SAAS;QAAE,GAAG,CAAC,aAAa,GAAG,iBAAiB,CAAC;IAC3E,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,GAAG,CAAC,eAAe,GAAG,mBAAmB,CAAC;IAC5C,CAAC;IAED,MAAM,iBAAiB,GAAG,SAAS,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACpE,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC5C,CAAC;IACD,MAAM,eAAe,GAAG,SAAS,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAChE,IAAI,eAAe,KAAK,SAAS;QAAE,GAAG,CAAC,eAAe,GAAG,eAAe,CAAC;IACzE,MAAM,cAAc,GAAG,SAAS,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC9D,IAAI,cAAc,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;IAEtE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAW,EACX,QAAyB;IAEzB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1E,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,0BAA0B,EAAE,GAAG,iBAAiB,CAC3E,MAAM,EACN,QAAQ,EACR,0BAA0B,CAC3B,CAAC;IACF,OAAO;QACL,MAAM,EAAE,MAAM;QACd,WAAW,EAAE,CAAC,GAAG,iBAAiB,EAAE,GAAG,0BAA0B,CAAC;KACnE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2 observer dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Observers are the `tool_result` side of the steering engine: rules
|
|
5
|
+
* decide "can this run" pre-execution; observers record "what happened"
|
|
6
|
+
* post-execution. Typical use is to `appendEntry` into pi's session
|
|
7
|
+
* JSONL so later predicates can gate on prior turn state (the
|
|
8
|
+
* "description was read in a PRIOR turn" idiom from the ADR).
|
|
9
|
+
*
|
|
10
|
+
* This module merges user-declared observers (from
|
|
11
|
+
* {@link SteeringConfig.observers}) with plugin-shipped ones (from
|
|
12
|
+
* {@link ResolvedPluginState.observers}), then on every `tool_result`:
|
|
13
|
+
*
|
|
14
|
+
* 1. Applies the observer's `watch` filter (toolName + inputMatches
|
|
15
|
+
* + exitCode). No `watch` means "fire on every tool_result".
|
|
16
|
+
* 2. Calls `observer.onResult(event, observerCtx)`. Awaits if it
|
|
17
|
+
* returns a promise.
|
|
18
|
+
* 3. Catches thrown errors per-observer — one buggy observer does
|
|
19
|
+
* NOT prevent the rest from running.
|
|
20
|
+
*
|
|
21
|
+
* Observer context (`ObserverContext`) is built fresh per event, using
|
|
22
|
+
* `appendEntry` and `findEntries` closures shared with the evaluator.
|
|
23
|
+
* `exec` is deliberately NOT exposed — observers are expected to be
|
|
24
|
+
* lightweight state-recording hooks. Complex tool_result analysis that
|
|
25
|
+
* needs to shell out belongs in a separate pi extension hook or in a
|
|
26
|
+
* rule's `when.condition` pre-execution, not in an observer.
|
|
27
|
+
*
|
|
28
|
+
* Wiring (Phase 3c): the extension runtime subscribes to `tool_result`
|
|
29
|
+
* and forwards the event + current `agentLoopIndex` into `dispatch`.
|
|
30
|
+
*/
|
|
31
|
+
import type { ExtensionContext, ToolResultEvent as PiToolResultEvent } from "@earendil-works/pi-coding-agent";
|
|
32
|
+
import { type EvaluatorHost } from "./evaluator-internals/context.ts";
|
|
33
|
+
import type { ResolvedPluginState } from "./plugin-merger.ts";
|
|
34
|
+
import type { Observer } from "./schema.ts";
|
|
35
|
+
export { matchesWatch } from "./internal/watch-matcher.ts";
|
|
36
|
+
/**
|
|
37
|
+
* Runtime-facing dispatcher handle. Phase 3c holds an instance per
|
|
38
|
+
* session and calls {@link dispatch} from the pi `tool_result` listener.
|
|
39
|
+
*/
|
|
40
|
+
export interface ObserverDispatcher {
|
|
41
|
+
/**
|
|
42
|
+
* Dispatch a single `tool_result` to every matching observer.
|
|
43
|
+
*
|
|
44
|
+
* Resolves when all observer handlers have settled. Handlers that
|
|
45
|
+
* throw are caught + logged via `console.warn` and do not prevent
|
|
46
|
+
* subsequent observers from running.
|
|
47
|
+
*/
|
|
48
|
+
dispatch(event: PiToolResultEvent, ctx: ExtensionContext, agentLoopIndex: number): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Construct an {@link ObserverDispatcher}.
|
|
52
|
+
*
|
|
53
|
+
* Arguments:
|
|
54
|
+
* - `resolved` — merged plugin state from {@link resolvePlugins}.
|
|
55
|
+
* Source of plugin-shipped observers and the
|
|
56
|
+
* registry used by the evaluator at the same
|
|
57
|
+
* level.
|
|
58
|
+
* - `userObservers` — the user's `config.observers` list (already
|
|
59
|
+
* deduped at the loader level in Phase 2). User
|
|
60
|
+
* observers fire BEFORE plugin observers on the
|
|
61
|
+
* same event; within each group, registration
|
|
62
|
+
* order decides.
|
|
63
|
+
* - `host` — narrow surface exposing pi's `exec` +
|
|
64
|
+
* `appendEntry`. Passed straight through to the
|
|
65
|
+
* per-event observer context.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildObserverDispatcher(resolved: ResolvedPluginState, userObservers: readonly Observer[], host: EvaluatorHost): ObserverDispatcher;
|
|
68
|
+
export type { EvaluatorHost } from "./evaluator-internals/context.ts";
|
|
69
|
+
//# sourceMappingURL=observer-dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-dispatcher.d.ts","sourceRoot":"","sources":["../src/observer-dispatcher.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,IAAI,iBAAiB,EACrC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAM1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,aAAa,CAAC;AAOrB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAM3D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,QAAQ,CACN,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,gBAAgB,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mBAAmB,EAC7B,aAAa,EAAE,SAAS,QAAQ,EAAE,EAClC,IAAI,EAAE,aAAa,GAClB,kBAAkB,CAwBpB;AA6JD,YAAY,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC"}
|