skillscript-runtime 0.19.16 → 0.20.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/README.md +11 -1
- package/dist/approval.d.ts +80 -54
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +156 -120
- package/dist/approval.js.map +1 -1
- package/dist/bootstrap.d.ts +41 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +59 -2
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli.js +245 -24
- package/dist/cli.js.map +1 -1
- package/dist/compile.js +7 -0
- package/dist/compile.js.map +1 -1
- package/dist/composition.d.ts.map +1 -1
- package/dist/composition.js +13 -1
- package/dist/composition.js.map +1 -1
- package/dist/connectors/skill-store.d.ts.map +1 -1
- package/dist/connectors/skill-store.js +41 -13
- package/dist/connectors/skill-store.js.map +1 -1
- package/dist/connectors/sqlite-skill-store.d.ts.map +1 -1
- package/dist/connectors/sqlite-skill-store.js +21 -12
- package/dist/connectors/sqlite-skill-store.js.map +1 -1
- package/dist/dashboard/spa/app.js +186 -8
- package/dist/dashboard/spa/index.html +2 -0
- package/dist/dashboard/spa/styles.css +42 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +49 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +24 -7
- package/dist/lint.js.map +1 -1
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +19 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/parser.js +2 -2
- package/dist/parser.js.map +1 -1
- package/dist/runtime-config.d.ts +6 -0
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +8 -0
- package/dist/runtime-config.js.map +1 -1
- package/dist/runtime-env-resolver.d.ts +4 -0
- package/dist/runtime-env-resolver.d.ts.map +1 -1
- package/dist/runtime-env-resolver.js +27 -0
- package/dist/runtime-env-resolver.js.map +1 -1
- package/dist/runtime.d.ts +18 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +84 -17
- package/dist/runtime.js.map +1 -1
- package/dist/safe-path.d.ts +22 -0
- package/dist/safe-path.d.ts.map +1 -1
- package/dist/safe-path.js +72 -1
- package/dist/safe-path.js.map +1 -1
- package/dist/scheduler.d.ts +3 -0
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +8 -0
- package/dist/scheduler.js.map +1 -1
- package/docs/adopter-playbook.md +75 -25
- package/docs/configuration.md +5 -1
- package/docs/connector-contract-reference.md +5 -1
- package/docs/language-reference.md +83 -130
- package/docs/sqlite-skill-store.md +5 -1
- package/examples/skillscripts/classify-support-ticket.skill.md +1 -1
- package/examples/skillscripts/data-store-roundtrip.skill.md +1 -1
- package/examples/skillscripts/doc-qa-with-citations.skill.md +1 -1
- package/examples/skillscripts/feedback-sentiment-scan.skill.md +1 -1
- package/examples/skillscripts/hello-world.skill.md +1 -1
- package/examples/skillscripts/hello-world.skill.provenance.json +1 -1
- package/examples/skillscripts/morning-brief.skill.md +1 -1
- package/examples/skillscripts/queue-length-monitor.skill.md +1 -1
- package/examples/skillscripts/service-health-watch.skill.md +1 -1
- package/examples/skillscripts/skill-store-roundtrip.skill.md +1 -1
- package/examples/skillscripts/youtrack-morning-sweep.skill.md +1 -1
- package/package.json +1 -1
- package/scaffold/skills/data-store-roundtrip.skill.md +1 -1
- package/scaffold/skills/hello-world.skill.md +1 -1
- package/scaffold/skills/skill-store-roundtrip.skill.md +1 -1
|
@@ -39,8 +39,12 @@ export interface RuntimeEnvConfig {
|
|
|
39
39
|
absoluteTimeoutMs?: number;
|
|
40
40
|
maxRecursionDepth?: number;
|
|
41
41
|
shellAllowlist?: string[];
|
|
42
|
+
fsAllowlist?: string[];
|
|
42
43
|
eventIngressEnabled?: boolean;
|
|
43
44
|
eventIngressAuthToken?: string;
|
|
45
|
+
securedMode?: boolean;
|
|
46
|
+
approvalKeyFile?: string;
|
|
47
|
+
approvalPublicKeyFile?: string;
|
|
44
48
|
}
|
|
45
49
|
/**
|
|
46
50
|
* Read all `SKILLSCRIPT_*` env vars from the supplied env (defaults to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-env-resolver.d.ts","sourceRoot":"","sources":["../src/runtime-env-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,WAAW,gBAAgB;IAE/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"runtime-env-resolver.d.ts","sourceRoot":"","sources":["../src/runtime-env-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,WAAW,gBAAgB;IAE/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAEvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAkGlG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAIhG;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAGvG"}
|
|
@@ -99,6 +99,16 @@ export function resolveRuntimeConfigFromEnv(env = process.env) {
|
|
|
99
99
|
.map((b) => b.trim())
|
|
100
100
|
.filter((b) => b.length > 0);
|
|
101
101
|
}
|
|
102
|
+
// SKILLSCRIPT_FS_ALLOWLIST — comma-separated filesystem roots that file_read /
|
|
103
|
+
// file_write may touch (Gate #7 third allowlist). Same parse + default-deny
|
|
104
|
+
// semantics as the shell allowlist.
|
|
105
|
+
const fsAllowlistRaw = env["SKILLSCRIPT_FS_ALLOWLIST"];
|
|
106
|
+
if (fsAllowlistRaw !== undefined) {
|
|
107
|
+
config.fsAllowlist = fsAllowlistRaw
|
|
108
|
+
.split(",")
|
|
109
|
+
.map((p) => p.trim())
|
|
110
|
+
.filter((p) => p.length > 0);
|
|
111
|
+
}
|
|
102
112
|
// SKILLSCRIPT_EVENT_INGRESS_ENABLED — boolean
|
|
103
113
|
const ingressRaw = env["SKILLSCRIPT_EVENT_INGRESS_ENABLED"];
|
|
104
114
|
if (ingressRaw === "true")
|
|
@@ -109,6 +119,23 @@ export function resolveRuntimeConfigFromEnv(env = process.env) {
|
|
|
109
119
|
const tokenRaw = env["SKILLSCRIPT_EVENT_INGRESS_AUTH_TOKEN"];
|
|
110
120
|
if (typeof tokenRaw === "string" && tokenRaw !== "")
|
|
111
121
|
config.eventIngressAuthToken = tokenRaw;
|
|
122
|
+
// SKILLSCRIPT_SECURED_MODE — boolean. The Gate #7 approval boundary: when on,
|
|
123
|
+
// only v3-signed skills execute effectfully.
|
|
124
|
+
const securedRaw = env["SKILLSCRIPT_SECURED_MODE"];
|
|
125
|
+
if (securedRaw === "true")
|
|
126
|
+
config.securedMode = true;
|
|
127
|
+
else if (securedRaw === "false")
|
|
128
|
+
config.securedMode = false;
|
|
129
|
+
// SKILLSCRIPT_APPROVAL_KEY_FILE — path to the operator's Ed25519 PRIVATE key
|
|
130
|
+
// (read only by the approve flow; the runtime never loads it).
|
|
131
|
+
const keyFileRaw = env["SKILLSCRIPT_APPROVAL_KEY_FILE"];
|
|
132
|
+
if (typeof keyFileRaw === "string" && keyFileRaw !== "")
|
|
133
|
+
config.approvalKeyFile = keyFileRaw;
|
|
134
|
+
// SKILLSCRIPT_APPROVAL_PUBLIC_KEY_FILE — path to the Ed25519 PUBLIC key
|
|
135
|
+
// (non-secret; the runtime reads it to verify v3 tokens).
|
|
136
|
+
const pubFileRaw = env["SKILLSCRIPT_APPROVAL_PUBLIC_KEY_FILE"];
|
|
137
|
+
if (typeof pubFileRaw === "string" && pubFileRaw !== "")
|
|
138
|
+
config.approvalPublicKeyFile = pubFileRaw;
|
|
112
139
|
return config;
|
|
113
140
|
}
|
|
114
141
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-env-resolver.js","sourceRoot":"","sources":["../src/runtime-env-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;
|
|
1
|
+
{"version":3,"file":"runtime-env-resolver.js","sourceRoot":"","sources":["../src/runtime-env-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -54,6 +54,24 @@ export interface ExecuteContext {
|
|
|
54
54
|
fallbackSkillExecutor?: (skillName: string, vars: Record<string, unknown>) => Promise<ExecuteResult>;
|
|
55
55
|
/** Mechanical-only preview: `$` ops skip real dispatch and bind a placeholder. */
|
|
56
56
|
mechanical?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* v1.0 Gate #7 — the effect capability. In SECURED mode, effectful ops
|
|
59
|
+
* (egress/mutation: `$`, shell, file_write, notify) and output-routing
|
|
60
|
+
* delivery dispatch ONLY when this is true. Minted exclusively by a verified
|
|
61
|
+
* approval at load time (or set unconditionally when the boundary is OFF).
|
|
62
|
+
* Source-mode / unapproved bodies run without it → effects refused at the
|
|
63
|
+
* dispatch choke, regardless of mechanical's (incomplete) suppression.
|
|
64
|
+
* Read alongside `isSecuredMode()`; in unsecured mode it is ignored entirely
|
|
65
|
+
* (zero behavior change when the boundary is off).
|
|
66
|
+
*/
|
|
67
|
+
effectsAuthorized?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* v1.0 Gate #7 — the filesystem path allowlist (third allowlist; mirrors
|
|
70
|
+
* shellAllowlist). file_read/file_write may only touch paths under one of
|
|
71
|
+
* these operator-owned roots. DEFAULT-DENY: undefined → all file ops refused.
|
|
72
|
+
* Independent of the approval gate — even an approved skill is path-bounded.
|
|
73
|
+
*/
|
|
74
|
+
fsAllowlist?: string[];
|
|
57
75
|
/**
|
|
58
76
|
* Runtime absolute timeout (milliseconds) — the built-in fallback when no
|
|
59
77
|
* per-op, skill, or connector default applies. Per ERD §6 decision 7,
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,aAAa,CAAC;AACpE,OAAO,KAAK,EAAgB,eAAe,EAAE,WAAW,EAAY,MAAM,uBAAuB,CAAC;AAKlG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.js
CHANGED
|
@@ -6,7 +6,9 @@ import { validateQualifiedDispatch } from "./dispatch-validate.js";
|
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { readFile as fsReadFile, writeFile as fsWriteFile, mkdir as fsMkdir } from "node:fs/promises";
|
|
8
8
|
import { dirname as pathDirname } from "node:path";
|
|
9
|
-
import { OpError, ConnectorNotFoundError, OpTimeoutError, UnsafeShellDisabledError, ShellBinaryNotAllowedError, UnresolvedVariableError, TypeMismatchError, MissingSkillReferenceError, UnconfirmedMutationError, messageOf, } from "./errors.js";
|
|
9
|
+
import { OpError, ConnectorNotFoundError, OpTimeoutError, UnsafeShellDisabledError, ShellBinaryNotAllowedError, UnresolvedVariableError, TypeMismatchError, MissingSkillReferenceError, UnconfirmedMutationError, SecuredModeEffectError, FilePathNotAllowedError, messageOf, } from "./errors.js";
|
|
10
|
+
import { isPathUnderAllowedRoot } from "./safe-path.js";
|
|
11
|
+
import { isSecuredMode } from "./approval.js";
|
|
10
12
|
import { classifyMutation, authorizationGranted, buildAuthorizationSuggestion, } from "./mutation-gate.js";
|
|
11
13
|
import { TraceBuilder, shouldTraceFire } from "./trace.js";
|
|
12
14
|
/**
|
|
@@ -277,7 +279,11 @@ export async function execute(parsed, initialVars, order, ctx) {
|
|
|
277
279
|
// `wake_skipped`.
|
|
278
280
|
const agentDeliveryReceipts = [];
|
|
279
281
|
const agentWakeReceipts = [];
|
|
280
|
-
|
|
282
|
+
// v1.0 Gate #7 — output-routing is an effectful egress; gate it with the same
|
|
283
|
+
// capability as the op-level choke. In secured mode an unapproved body cannot
|
|
284
|
+
// deliver to an agent/template, even though its emit-to-transcript ran.
|
|
285
|
+
const deliveryAuthorized = !(isSecuredMode() && ctx.effectsAuthorized !== true);
|
|
286
|
+
if (ctx.mechanical !== true && deliveryAuthorized) {
|
|
281
287
|
for (const decl of outputDecls) {
|
|
282
288
|
if (decl.target === undefined)
|
|
283
289
|
continue;
|
|
@@ -423,7 +429,37 @@ function extractOpConnector(op) {
|
|
|
423
429
|
return op.mcpConnector ?? "primary";
|
|
424
430
|
return undefined;
|
|
425
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* v1.0 Gate #7 — the complete effectful op set the capability gate covers. The
|
|
434
|
+
* principle: an unapproved skill must not touch EXTERNAL STATE at all — neither
|
|
435
|
+
* egress/mutation NOR ingress (a read it can then `emit` back to the caller is an
|
|
436
|
+
* exfiltration channel; the file_read-then-emit of the operator's private key is
|
|
437
|
+
* the canonical attack). So every op that crosses the process boundary is gated:
|
|
438
|
+
* `$` — all external MCP dispatch (connector / data_read / data_write / llm)
|
|
439
|
+
* `shell` — process spawn
|
|
440
|
+
* `file_read` — reads any host file the runtime can (exfil source) [v1.0 add]
|
|
441
|
+
* `file_write`— local mutation
|
|
442
|
+
* `notify` — agent delivery
|
|
443
|
+
* Output-routing delivery is gated separately at the execute() tail.
|
|
444
|
+
* Excluded (pure compute / transcript, no boundary crossing): `$set`/`$append`
|
|
445
|
+
* (local vars), `?`/`emit` (transcript of already-known values), `foreach`/`if`
|
|
446
|
+
* (control flow — nested ops each traverse this check), `inline` (compile-resolved
|
|
447
|
+
* + gated at compile). Note `emit` stays ungated: emitting a COMPUTED value is
|
|
448
|
+
* harmless; the exfil risk was the READ feeding it, which is now gated.
|
|
449
|
+
*/
|
|
450
|
+
function isEffectfulOpKind(kind) {
|
|
451
|
+
return kind === "$" || kind === "shell" || kind === "file_read" || kind === "file_write" || kind === "notify";
|
|
452
|
+
}
|
|
426
453
|
async function execOpInner(op, vars, emissions, fallbacks, ctx, targetName, skillTimeoutSec, absoluteTimeoutMs, traceBuilder, authState = { skillAutonomous: false }) {
|
|
454
|
+
// v1.0 Gate #7 — complete-mediation choke. Every effectful op (egress/mutation)
|
|
455
|
+
// physically traverses this point; in secured mode it may dispatch ONLY when
|
|
456
|
+
// the execution was authorized by a verified approval. Source-mode/Draft/forged
|
|
457
|
+
// bodies arrive with effectsAuthorized unset → refused here, regardless of
|
|
458
|
+
// mechanical's (incomplete) suppression. Non-effectful ops ($set/$append/?/emit/
|
|
459
|
+
// foreach/if/inline/file_read) pass through. No-op when the boundary is OFF.
|
|
460
|
+
if (isEffectfulOpKind(op.kind) && isSecuredMode() && ctx.effectsAuthorized !== true) {
|
|
461
|
+
throw new SecuredModeEffectError(op.kind, targetName);
|
|
462
|
+
}
|
|
427
463
|
switch (op.kind) {
|
|
428
464
|
case "$set": {
|
|
429
465
|
// v0.5.0 item 3 — `$set X = "...$(REF)..."` now resolves $(REF) at
|
|
@@ -648,6 +684,12 @@ async function execOpInner(op, vars, emissions, fallbacks, ctx, targetName, skil
|
|
|
648
684
|
vars.set(op.outputVar, placeholder);
|
|
649
685
|
return { lastBoundVar: op.outputVar ?? flatKey, lastValue: placeholder };
|
|
650
686
|
}
|
|
687
|
+
// v1.0 Gate #7 — filesystem path allowlist (operator boundary, default-deny).
|
|
688
|
+
// Canonicalizes (realpath) before the under-root check so `..`/symlinks can't
|
|
689
|
+
// evade. Independent of the approval gate — even an approved skill is bounded.
|
|
690
|
+
if (!isPathUnderAllowedRoot(path, ctx.fsAllowlist)) {
|
|
691
|
+
throw new FilePathNotAllowedError("file_read", path, ctx.fsAllowlist, targetName);
|
|
692
|
+
}
|
|
651
693
|
let content;
|
|
652
694
|
try {
|
|
653
695
|
content = await fsReadFile(path, "utf8");
|
|
@@ -696,6 +738,11 @@ async function execOpInner(op, vars, emissions, fallbacks, ctx, targetName, skil
|
|
|
696
738
|
emissions.push(`Would write file: ${path} (${content.length} chars; mechanical: true preview).`);
|
|
697
739
|
return { lastBoundVar: null, lastValue: undefined };
|
|
698
740
|
}
|
|
741
|
+
// v1.0 Gate #7 — filesystem path allowlist (operator boundary, default-deny).
|
|
742
|
+
// Checked BEFORE mkdir/write so a denied path never even creates a directory.
|
|
743
|
+
if (!isPathUnderAllowedRoot(path, ctx.fsAllowlist)) {
|
|
744
|
+
throw new FilePathNotAllowedError("file_write", path, ctx.fsAllowlist, targetName);
|
|
745
|
+
}
|
|
699
746
|
try {
|
|
700
747
|
await fsMkdir(pathDirname(path), { recursive: true });
|
|
701
748
|
await fsWriteFile(path, content, "utf8");
|
|
@@ -1482,6 +1529,7 @@ export function substituteRuntime(text, vars) {
|
|
|
1482
1529
|
let value = resolveRef(ref, vars);
|
|
1483
1530
|
const specs = parseFilterChain(filterChain);
|
|
1484
1531
|
for (const spec of specs) {
|
|
1532
|
+
const arg = interpolateFilterArg(spec.arg, vars);
|
|
1485
1533
|
if (spec.name === "fallback") {
|
|
1486
1534
|
// v0.19.12 — empty-aware. Matches the $-op trailer's
|
|
1487
1535
|
// emptiness predicate (closes Perry's `9d8ff1b1`).
|
|
@@ -1489,14 +1537,14 @@ export function substituteRuntime(text, vars) {
|
|
|
1489
1537
|
const isEmptyArray = Array.isArray(value) && value.length === 0;
|
|
1490
1538
|
const isNullish = value === null || value === undefined;
|
|
1491
1539
|
if (isNullish || isEmptyString || isEmptyArray) {
|
|
1492
|
-
value =
|
|
1540
|
+
value = arg ?? "";
|
|
1493
1541
|
}
|
|
1494
1542
|
continue;
|
|
1495
1543
|
}
|
|
1496
1544
|
if (value === undefined) {
|
|
1497
1545
|
throw new UnresolvedVariableError(ref, "?");
|
|
1498
1546
|
}
|
|
1499
|
-
value = applyFilter(stringifyValue(value), spec.name,
|
|
1547
|
+
value = applyFilter(stringifyValue(value), spec.name, arg);
|
|
1500
1548
|
}
|
|
1501
1549
|
if (value === undefined) {
|
|
1502
1550
|
throw new UnresolvedVariableError(ref, "?");
|
|
@@ -1575,6 +1623,24 @@ export function stringifyValue(v) {
|
|
|
1575
1623
|
return v[MECHANICAL_PLACEHOLDER];
|
|
1576
1624
|
return JSON.stringify(v);
|
|
1577
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* v1.0 (fix list 33bf53d3 P1.1): interpolate `${VAR}` / `$(VAR)` refs inside a
|
|
1628
|
+
* filter argument before the filter runs, so `|contains:"${KW}"` tests the
|
|
1629
|
+
* value of KW rather than the literal string "${KW}". Pre-fix the arg was taken
|
|
1630
|
+
* verbatim and silently failed to match (round-1 cold-author finding — broke
|
|
1631
|
+
* `cold-feed-filter`'s KEYWORD parameterization). Bounded recursion: the arg is
|
|
1632
|
+
* a small literal, so one `substituteRuntime` pass resolves the inner ref (the
|
|
1633
|
+
* result is not re-scanned). No-op when the arg has no ref, or when no `vars`
|
|
1634
|
+
* scope is in play. Unresolved refs inside the arg fail loud (UnresolvedVariableError),
|
|
1635
|
+
* consistent with every other substitution site.
|
|
1636
|
+
*/
|
|
1637
|
+
function interpolateFilterArg(arg, vars) {
|
|
1638
|
+
if (arg === undefined || vars === undefined)
|
|
1639
|
+
return arg;
|
|
1640
|
+
if (!arg.includes("$"))
|
|
1641
|
+
return arg; // fast path: no ref possible
|
|
1642
|
+
return substituteRuntime(arg, vars);
|
|
1643
|
+
}
|
|
1578
1644
|
// v0.3.4 — filter chain support in conditions. Each `(REF)(|filter)?`
|
|
1579
1645
|
// becomes `(REF)(|filter)*` matching substituteRuntime's chain pattern.
|
|
1580
1646
|
// v0.7.0 — loose-bracket form `\$[({]...[)}]` accepts both `$(REF)` and
|
|
@@ -1598,7 +1664,7 @@ const IN = /^\s*\$[({]([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)((?:\s*\|\s*[A-Za-z_]\w*(
|
|
|
1598
1664
|
* the recurring "filter chain works in substitution but not conditions"
|
|
1599
1665
|
* gap named in dev-log §14.
|
|
1600
1666
|
*/
|
|
1601
|
-
function applyFilterChain(value, chain) {
|
|
1667
|
+
function applyFilterChain(value, chain, vars) {
|
|
1602
1668
|
if (chain === undefined || chain === "")
|
|
1603
1669
|
return value;
|
|
1604
1670
|
const specs = parseFilterChain(chain);
|
|
@@ -1606,7 +1672,7 @@ function applyFilterChain(value, chain) {
|
|
|
1606
1672
|
for (const spec of specs) {
|
|
1607
1673
|
if (spec.name === "fallback")
|
|
1608
1674
|
continue;
|
|
1609
|
-
s = applyFilter(s, spec.name, spec.arg);
|
|
1675
|
+
s = applyFilter(s, spec.name, interpolateFilterArg(spec.arg, vars));
|
|
1610
1676
|
}
|
|
1611
1677
|
return s;
|
|
1612
1678
|
}
|
|
@@ -1615,18 +1681,19 @@ function applyFilterChain(value, chain) {
|
|
|
1615
1681
|
* undefined-ness through so `|fallback:"X"` can consume an unresolved ref.
|
|
1616
1682
|
* Used by EQ / CMP / IN paths in evalSimpleCondition. v0.5.0 item 4.
|
|
1617
1683
|
*/
|
|
1618
|
-
function applyFilterChainCondition(value, chain) {
|
|
1684
|
+
function applyFilterChainCondition(value, chain, vars) {
|
|
1619
1685
|
const specs = parseFilterChain(chain);
|
|
1620
1686
|
let current = value;
|
|
1621
1687
|
for (const spec of specs) {
|
|
1688
|
+
const arg = interpolateFilterArg(spec.arg, vars);
|
|
1622
1689
|
if (spec.name === "fallback") {
|
|
1623
1690
|
if (current === undefined)
|
|
1624
|
-
current =
|
|
1691
|
+
current = arg ?? "";
|
|
1625
1692
|
continue;
|
|
1626
1693
|
}
|
|
1627
1694
|
if (current === undefined)
|
|
1628
1695
|
current = "";
|
|
1629
|
-
current = applyFilter(stringifyValue(current), spec.name,
|
|
1696
|
+
current = applyFilter(stringifyValue(current), spec.name, arg);
|
|
1630
1697
|
}
|
|
1631
1698
|
if (current === undefined)
|
|
1632
1699
|
current = "";
|
|
@@ -1745,7 +1812,7 @@ function evalSimpleCondition(cond, vars) {
|
|
|
1745
1812
|
if (t) {
|
|
1746
1813
|
const val = resolveRef(t[1], vars);
|
|
1747
1814
|
const chain = t[2];
|
|
1748
|
-
const filtered = chain && val !== undefined ? applyFilterChain(stringifyValue(val), chain) : val;
|
|
1815
|
+
const filtered = chain && val !== undefined ? applyFilterChain(stringifyValue(val), chain, vars) : val;
|
|
1749
1816
|
return isTruthy(filtered);
|
|
1750
1817
|
}
|
|
1751
1818
|
const e = EQ.exec(cond);
|
|
@@ -1754,7 +1821,7 @@ function evalSimpleCondition(cond, vars) {
|
|
|
1754
1821
|
const val = resolveRef(ref, vars);
|
|
1755
1822
|
// v0.5.0 item 4: condition-aware chain threading so `|default:"X"`
|
|
1756
1823
|
// consumes undefined refs in conditional context too.
|
|
1757
|
-
const final = applyFilterChainCondition(val, chain);
|
|
1824
|
+
const final = applyFilterChainCondition(val, chain, vars);
|
|
1758
1825
|
return op === "==" ? final === lit : final !== lit;
|
|
1759
1826
|
}
|
|
1760
1827
|
const eRef = EQ_REF.exec(cond);
|
|
@@ -1762,15 +1829,15 @@ function evalSimpleCondition(cond, vars) {
|
|
|
1762
1829
|
const [, lhsRef, lhsChain, op, rhsRef, rhsChain] = eRef;
|
|
1763
1830
|
const lhsVal = resolveRef(lhsRef, vars);
|
|
1764
1831
|
const rhsVal = resolveRef(rhsRef, vars);
|
|
1765
|
-
const lhsFinal = applyFilterChainCondition(lhsVal, lhsChain);
|
|
1766
|
-
const rhsFinal = applyFilterChainCondition(rhsVal, rhsChain);
|
|
1832
|
+
const lhsFinal = applyFilterChainCondition(lhsVal, lhsChain, vars);
|
|
1833
|
+
const rhsFinal = applyFilterChainCondition(rhsVal, rhsChain, vars);
|
|
1767
1834
|
return op === "==" ? lhsFinal === rhsFinal : lhsFinal !== rhsFinal;
|
|
1768
1835
|
}
|
|
1769
1836
|
const cmp = CMP.exec(cond);
|
|
1770
1837
|
if (cmp) {
|
|
1771
1838
|
const [, ref, chain, op, lit] = cmp;
|
|
1772
1839
|
const val = resolveRef(ref, vars);
|
|
1773
|
-
const final = applyFilterChainCondition(val, chain);
|
|
1840
|
+
const final = applyFilterChainCondition(val, chain, vars);
|
|
1774
1841
|
return compareNumeric(final, op, lit, `$(${ref}${chain ? chain : ""})`);
|
|
1775
1842
|
}
|
|
1776
1843
|
const cmpRef = CMP_REF.exec(cond);
|
|
@@ -1778,8 +1845,8 @@ function evalSimpleCondition(cond, vars) {
|
|
|
1778
1845
|
const [, lhsRef, lhsChain, op, rhsRef, rhsChain] = cmpRef;
|
|
1779
1846
|
const lhsVal = resolveRef(lhsRef, vars);
|
|
1780
1847
|
const rhsVal = resolveRef(rhsRef, vars);
|
|
1781
|
-
const lhsFinal = applyFilterChainCondition(lhsVal, lhsChain);
|
|
1782
|
-
const rhsFinal = applyFilterChainCondition(rhsVal, rhsChain);
|
|
1848
|
+
const lhsFinal = applyFilterChainCondition(lhsVal, lhsChain, vars);
|
|
1849
|
+
const rhsFinal = applyFilterChainCondition(rhsVal, rhsChain, vars);
|
|
1783
1850
|
const refDesc = `$(${lhsRef}) ${op} $(${rhsRef})`;
|
|
1784
1851
|
return compareNumeric(lhsFinal, op, rhsFinal, refDesc);
|
|
1785
1852
|
}
|
|
@@ -1829,7 +1896,7 @@ function evalSimpleCondition(cond, vars) {
|
|
|
1829
1896
|
const lhsVal = resolveRef(lhsRef, vars);
|
|
1830
1897
|
if (lhsVal === undefined)
|
|
1831
1898
|
return false;
|
|
1832
|
-
const lhsStr = applyFilterChain(stringifyValue(lhsVal), lhsChain);
|
|
1899
|
+
const lhsStr = applyFilterChain(stringifyValue(lhsVal), lhsChain, vars);
|
|
1833
1900
|
const found = rhsVal.some((item) => stringifyValue(item) === lhsStr);
|
|
1834
1901
|
return notKey !== undefined ? !found : found;
|
|
1835
1902
|
}
|