@ansible-flow/core 0.87.0 → 0.88.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 +1 -1
- package/dist/ai/describe.js +5 -5
- package/dist/ai/handlers.js +21 -20
- package/dist/ai/handlers.js.map +1 -1
- package/dist/ai/ops.js +4 -4
- package/dist/ai/reference.js +2 -2
- package/dist/ai/scenarios.js +8 -6
- package/dist/awx/import.js +3 -3
- package/dist/chunks/{chunk-IZJPLWDY.js → chunk-2KB3J3R5.js} +2 -2
- package/dist/chunks/{chunk-EAJFZKPB.js → chunk-37FKZNRN.js} +3 -3
- package/dist/chunks/{chunk-BNMW6KWK.js → chunk-57KJYXWA.js} +3 -3
- package/dist/chunks/{chunk-2P3JEHLH.js → chunk-7ALTNZCI.js} +3 -3
- package/dist/chunks/{chunk-WSARMPYU.js → chunk-APBEHKCF.js} +2 -2
- package/dist/chunks/{chunk-W2CSOAIB.js → chunk-BSX6G7QY.js} +5 -5
- package/dist/chunks/{chunk-3Z4WABFK.js → chunk-CATQHJS6.js} +4 -4
- package/dist/chunks/{chunk-HPRG2672.js → chunk-CCWUUVSG.js} +2 -2
- package/dist/chunks/{chunk-C6SQEXL5.js → chunk-CNQ7M7HA.js} +2 -2
- package/dist/chunks/{chunk-IXW7A4M7.js → chunk-CNYGDBID.js} +2 -2
- package/dist/chunks/{chunk-DL4LYODQ.js → chunk-J5LYSQ3L.js} +2 -2
- package/dist/chunks/{chunk-72LO6GQE.js → chunk-KXD6FX2Z.js} +2 -2
- package/dist/chunks/{chunk-4RMWFRWG.js → chunk-LELKMVJG.js} +45 -7
- package/dist/chunks/chunk-LELKMVJG.js.map +7 -0
- package/dist/chunks/{chunk-QMIXDOU6.js → chunk-OGNFHW5O.js} +4 -10
- package/dist/chunks/chunk-OGNFHW5O.js.map +7 -0
- package/dist/chunks/chunk-OJZSZBHW.js +45 -0
- package/dist/chunks/chunk-OJZSZBHW.js.map +7 -0
- package/dist/chunks/{chunk-R4MW3DRT.js → chunk-OW32YCZ6.js} +2 -2
- package/dist/chunks/{chunk-76T45V37.js → chunk-TBFB7A2Z.js} +5 -1
- package/dist/chunks/{chunk-76T45V37.js.map → chunk-TBFB7A2Z.js.map} +2 -2
- package/dist/chunks/{chunk-BXJOUAXV.js → chunk-TEJARYAE.js} +3 -3
- package/dist/chunks/{chunk-KZALUEFT.js → chunk-TPMACJFA.js} +3 -3
- package/dist/chunks/{chunk-2MJKBPGG.js → chunk-WTVGCMGV.js} +7 -3
- package/dist/chunks/chunk-WTVGCMGV.js.map +7 -0
- package/dist/chunks/{chunk-6MLYGFT6.js → chunk-XJAMBKE3.js} +6 -2
- package/dist/chunks/chunk-XJAMBKE3.js.map +7 -0
- package/dist/chunks/{chunk-FMCBTYUM.js → chunk-ZXUXX3YY.js} +2 -2
- package/dist/engine/binding.js +3 -1
- package/dist/engine/engines.js +5 -3
- package/dist/engine/files.js +5 -3
- package/dist/engine/optionA.js +4 -2
- package/dist/engine/preview.js +5 -3
- package/dist/engine/preview.js.map +1 -1
- package/dist/engine/writePlan.js +7 -5
- package/dist/export/drawio.js +3 -3
- package/dist/export/layoutCheck.js +3 -3
- package/dist/export/scene.js +2 -2
- package/dist/export/svg.js +4 -4
- package/dist/flow/findingCodes.js +1 -1
- package/dist/flow/localFiles.d.ts +17 -0
- package/dist/flow/localFiles.js +14 -0
- package/dist/flow/localFiles.js.map +7 -0
- package/dist/import/outline.js +5 -4
- package/dist/import/playbook.js +2 -2
- package/dist/import/source.js +2 -1
- package/dist/protocol.d.ts +12 -0
- package/dist/run/command.d.ts +13 -4
- package/dist/run/command.js +19 -0
- package/dist/run/command.js.map +3 -3
- package/dist/scenario/live.js +7 -5
- package/dist/scenario/simulate.js +6 -4
- package/dist/view/flowFacts.js +7 -5
- package/dist/view/flowFacts.js.map +1 -1
- package/dist/view/jinjaComplete.js +3 -3
- package/dist/view/route.d.ts +3 -1
- package/dist/view/route.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/chunk-2MJKBPGG.js.map +0 -7
- package/dist/chunks/chunk-4RMWFRWG.js.map +0 -7
- package/dist/chunks/chunk-6MLYGFT6.js.map +0 -7
- package/dist/chunks/chunk-QMIXDOU6.js.map +0 -7
- /package/dist/chunks/{chunk-IZJPLWDY.js.map → chunk-2KB3J3R5.js.map} +0 -0
- /package/dist/chunks/{chunk-EAJFZKPB.js.map → chunk-37FKZNRN.js.map} +0 -0
- /package/dist/chunks/{chunk-BNMW6KWK.js.map → chunk-57KJYXWA.js.map} +0 -0
- /package/dist/chunks/{chunk-2P3JEHLH.js.map → chunk-7ALTNZCI.js.map} +0 -0
- /package/dist/chunks/{chunk-WSARMPYU.js.map → chunk-APBEHKCF.js.map} +0 -0
- /package/dist/chunks/{chunk-W2CSOAIB.js.map → chunk-BSX6G7QY.js.map} +0 -0
- /package/dist/chunks/{chunk-3Z4WABFK.js.map → chunk-CATQHJS6.js.map} +0 -0
- /package/dist/chunks/{chunk-HPRG2672.js.map → chunk-CCWUUVSG.js.map} +0 -0
- /package/dist/chunks/{chunk-C6SQEXL5.js.map → chunk-CNQ7M7HA.js.map} +0 -0
- /package/dist/chunks/{chunk-IXW7A4M7.js.map → chunk-CNYGDBID.js.map} +0 -0
- /package/dist/chunks/{chunk-DL4LYODQ.js.map → chunk-J5LYSQ3L.js.map} +0 -0
- /package/dist/chunks/{chunk-72LO6GQE.js.map → chunk-KXD6FX2Z.js.map} +0 -0
- /package/dist/chunks/{chunk-R4MW3DRT.js.map → chunk-OW32YCZ6.js.map} +0 -0
- /package/dist/chunks/{chunk-BXJOUAXV.js.map → chunk-TEJARYAE.js.map} +0 -0
- /package/dist/chunks/{chunk-KZALUEFT.js.map → chunk-TPMACJFA.js.map} +0 -0
- /package/dist/chunks/{chunk-FMCBTYUM.js.map → chunk-ZXUXX3YY.js.map} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LOCAL_FILES,
|
|
3
|
+
REPO_ROOT_VAR,
|
|
4
|
+
localFileOf,
|
|
5
|
+
rootedParams
|
|
6
|
+
} from "../chunks/chunk-OJZSZBHW.js";
|
|
7
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
8
|
+
export {
|
|
9
|
+
LOCAL_FILES,
|
|
10
|
+
REPO_ROOT_VAR,
|
|
11
|
+
localFileOf,
|
|
12
|
+
rootedParams
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=localFiles.js.map
|
package/dist/import/outline.js
CHANGED
|
@@ -4,14 +4,15 @@ import {
|
|
|
4
4
|
paged,
|
|
5
5
|
sourceOutline,
|
|
6
6
|
taskBinding
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
-
import "../chunks/chunk-
|
|
7
|
+
} from "../chunks/chunk-57KJYXWA.js";
|
|
8
|
+
import "../chunks/chunk-OGNFHW5O.js";
|
|
9
9
|
import "../chunks/chunk-IYVI5MSS.js";
|
|
10
|
-
import "../chunks/chunk-
|
|
10
|
+
import "../chunks/chunk-OJZSZBHW.js";
|
|
11
|
+
import "../chunks/chunk-CATQHJS6.js";
|
|
11
12
|
import "../chunks/chunk-6L43PFIN.js";
|
|
12
|
-
import "../chunks/chunk-LNFMYJUJ.js";
|
|
13
13
|
import "../chunks/chunk-5CD65KH3.js";
|
|
14
14
|
import "../chunks/chunk-PDUQ3KMW.js";
|
|
15
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
15
16
|
import "../chunks/chunk-BAZIS67B.js";
|
|
16
17
|
import "../chunks/chunk-TC7FOG4T.js";
|
|
17
18
|
import "../chunks/chunk-75QLJHZ5.js";
|
package/dist/import/playbook.js
CHANGED
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
flatPlays,
|
|
4
4
|
importPlaybook,
|
|
5
5
|
mainPlay
|
|
6
|
-
} from "../chunks/chunk-
|
|
6
|
+
} from "../chunks/chunk-CATQHJS6.js";
|
|
7
7
|
import "../chunks/chunk-6L43PFIN.js";
|
|
8
|
-
import "../chunks/chunk-LNFMYJUJ.js";
|
|
9
8
|
import "../chunks/chunk-5CD65KH3.js";
|
|
10
9
|
import "../chunks/chunk-PDUQ3KMW.js";
|
|
10
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
11
11
|
import "../chunks/chunk-BAZIS67B.js";
|
|
12
12
|
import "../chunks/chunk-TC7FOG4T.js";
|
|
13
13
|
import "../chunks/chunk-75QLJHZ5.js";
|
package/dist/import/source.js
CHANGED
|
@@ -2,7 +2,8 @@ import {
|
|
|
2
2
|
parseKv,
|
|
3
3
|
readPlaybook,
|
|
4
4
|
scanFolder
|
|
5
|
-
} from "../chunks/chunk-
|
|
5
|
+
} from "../chunks/chunk-OGNFHW5O.js";
|
|
6
|
+
import "../chunks/chunk-OJZSZBHW.js";
|
|
6
7
|
import "../chunks/chunk-6L43PFIN.js";
|
|
7
8
|
import "../chunks/chunk-LNFMYJUJ.js";
|
|
8
9
|
import "../chunks/chunk-TC7FOG4T.js";
|
package/dist/protocol.d.ts
CHANGED
|
@@ -278,6 +278,13 @@ export type HostMessage = {
|
|
|
278
278
|
viewer?: boolean;
|
|
279
279
|
/** AFD-276: an Ansible Flow Server is set up: the run menu offers Run on Server. */
|
|
280
280
|
runner?: boolean;
|
|
281
|
+
/** AFD-294 (`afd.canvas.wireStyle`): how the canvas draws wires. */
|
|
282
|
+
wireStyle?: 'stepped' | 'curved';
|
|
283
|
+
}
|
|
284
|
+
/** AFD-294: the wire style setting changed. */
|
|
285
|
+
| {
|
|
286
|
+
type: 'wireStyle';
|
|
287
|
+
style: 'stepped' | 'curved';
|
|
281
288
|
}
|
|
282
289
|
/** AFD-73: the user's first-flow progress (tour keys reached) and whether the checklist is hidden. */
|
|
283
290
|
| {
|
|
@@ -442,6 +449,11 @@ export type WebviewMessage = {
|
|
|
442
449
|
} | {
|
|
443
450
|
type: 'tidyUp';
|
|
444
451
|
level?: string;
|
|
452
|
+
}
|
|
453
|
+
/** AFD-294: the canvas's wire toggle: keep this style as the user's setting. */
|
|
454
|
+
| {
|
|
455
|
+
type: 'setWireStyle';
|
|
456
|
+
style: 'stepped' | 'curved';
|
|
445
457
|
} | {
|
|
446
458
|
type: 'run';
|
|
447
459
|
mode: 'check' | 'real';
|
package/dist/run/command.d.ts
CHANGED
|
@@ -80,16 +80,25 @@ export interface RunRequest {
|
|
|
80
80
|
* `run_config`, paths as the environment sees them). Ours is added to them instead of replacing
|
|
81
81
|
* them, so an audit callback an organisation requires keeps running.
|
|
82
82
|
*/
|
|
83
|
-
callbacks?:
|
|
84
|
-
enabled: string[];
|
|
85
|
-
paths: string[];
|
|
86
|
-
};
|
|
83
|
+
callbacks?: RepositoryConfig;
|
|
87
84
|
/**
|
|
88
85
|
* AFD-159: a folder inside runDir for events.jsonl, the only one an image's own user writes to
|
|
89
86
|
* (a scenario run keeps the rest of its folder to its owner).
|
|
90
87
|
*/
|
|
91
88
|
eventsDir?: string;
|
|
92
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* What a run keeps of the repository's Ansible config (the probe's `run_config`, paths as the
|
|
92
|
+
* environment sees them): the callbacks it enables (AFD-141) and, AFD-291, its module, module_utils
|
|
93
|
+
* and plugin paths and enabled vars plugins, which the run's own variables would replace.
|
|
94
|
+
*/
|
|
95
|
+
export interface RepositoryConfig {
|
|
96
|
+
enabled: string[];
|
|
97
|
+
paths: string[];
|
|
98
|
+
/** By folder name (`library`, `filter_plugins`, ...): the paths the config gives. */
|
|
99
|
+
plugins?: Record<string, string[]>;
|
|
100
|
+
varsEnabled?: string[];
|
|
101
|
+
}
|
|
93
102
|
/** Run inputs split by name, with the import's rule: secret-looking ones never reach vars.json. */
|
|
94
103
|
export declare function splitInputs(inputs: Record<string, unknown>): {
|
|
95
104
|
plain: Record<string, unknown>;
|
package/dist/run/command.js
CHANGED
|
@@ -152,6 +152,14 @@ function probeProcess(env, paths, name) {
|
|
|
152
152
|
cwd: paths.root
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
|
+
var REPO_FOLDERS = [
|
|
156
|
+
["library", "ANSIBLE_LIBRARY"],
|
|
157
|
+
["module_utils", "ANSIBLE_MODULE_UTILS"],
|
|
158
|
+
["action_plugins", "ANSIBLE_ACTION_PLUGINS"],
|
|
159
|
+
["filter_plugins", "ANSIBLE_FILTER_PLUGINS"],
|
|
160
|
+
["lookup_plugins", "ANSIBLE_LOOKUP_PLUGINS"],
|
|
161
|
+
["test_plugins", "ANSIBLE_TEST_PLUGINS"]
|
|
162
|
+
];
|
|
155
163
|
var CALLBACK_NAME = /^[\w.]+$/;
|
|
156
164
|
var pluginPath = (p) => p !== "" && !/[:\n\r]/.test(p);
|
|
157
165
|
function splitInputs(inputs) {
|
|
@@ -174,6 +182,17 @@ function runEnv(probeDir, runDir, root, config) {
|
|
|
174
182
|
};
|
|
175
183
|
if (config.emptyConfig) env.ANSIBLE_CONFIG = join(runDir, "ansible.cfg");
|
|
176
184
|
else if (config.hasConfig) env.ANSIBLE_CONFIG = join(root, "ansible.cfg");
|
|
185
|
+
if (theirs?.plugins) {
|
|
186
|
+
const list = (paths, own) => [.../* @__PURE__ */ new Set([...(paths ?? []).filter(pluginPath), own])].join(":");
|
|
187
|
+
for (const [folder, variable] of REPO_FOLDERS)
|
|
188
|
+
env[variable] = list(theirs.plugins[folder], join(root, folder));
|
|
189
|
+
env.ANSIBLE_VARS_PLUGINS = list(theirs.plugins.vars_plugins, join(probeDir, "vars_plugins"));
|
|
190
|
+
const enabled2 = (theirs.varsEnabled ?? []).filter((n) => CALLBACK_NAME.test(n));
|
|
191
|
+
env.ANSIBLE_VARS_ENABLED = [
|
|
192
|
+
.../* @__PURE__ */ new Set([...enabled2.length ? enabled2 : ["host_group_vars"], "afd_repo_vars"])
|
|
193
|
+
].join(",");
|
|
194
|
+
env.AFD_REPO_ROOT = root;
|
|
195
|
+
}
|
|
177
196
|
return env;
|
|
178
197
|
}
|
|
179
198
|
function runProcess(env, paths, request, name) {
|
package/dist/run/command.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/core/run/command.ts"],
|
|
4
|
-
"sourcesContent": ["// Command lines for the probe session and for flow runs in an environment (ADR-0005, ADR-0009).\n// Pure: the host supplies paths; container paths are fixed so generated code and events map back,\n// and a WSL distribution sees this machine's drives under /mnt (AFD-75).\nimport { SECRET } from '../import/secrets';\nimport type { Environment } from './environment';\nimport { LOGIN_PROFILE, onHost, readFromInput, remotePaths, rq, shQuote } from './ssh';\n\nexport { shQuote };\n\nexport const CONTAINER = {\n root: '/work',\n probe: '/afd',\n run: '/afd-run',\n /** The catalog cache in global storage, read-write (M5). */\n cache: '/afd-cache',\n} as const;\n\nexport interface ProcessSpec {\n command: string;\n args: string[];\n /** Extra environment for the spawned process (values never appear in args). */\n env: Record<string, string>;\n cwd?: string;\n /**\n * AFD-131: what ends the work this process started beyond itself. Killing the docker or podman\n * client leaves its container running (the shell inside is PID 1 and ignores SIGTERM), so a\n * stopped run, a timed-out scenario or a hung probe call also removes the container by name.\n */\n stop?: { command: string; args: string[] };\n /**\n * AFD-247: variables of `env` that go to the process on its input instead (one base64 line\n * each, in this order): ssh passes no environment to the host, and they are never arguments.\n */\n input?: string[];\n}\n\nconst containerStop = (env: Extract<Environment, { kind: 'container' }>, name: string) => ({\n command: env.engine,\n args: ['rm', '-f', name],\n});\n\n/**\n * AFD-131: ends a WSL run from Windows. Killing wsl.exe leaves ansible-playbook running in the\n * distribution, so the run's shell carries its name as `$0`, and this finds it with pgrep and\n * ends it with every process under it, children first (ansible-playbook and its workers; the\n * shell's EXIT trap then removes the secret files). Not by process group: in WSL 1 the shells of\n * separate `wsl -e` sessions can share one, and this shell or another run would go with it. The\n * name is passed in two parts so the pattern never matches this shell.\n */\nconst WSL_STOP =\n 'k() { for c in $(pgrep -P \"$1\"); do k \"$c\"; done; kill -TERM \"$1\"; }; ' +\n 'for p in $(pgrep -f -- \"$1$2\"); do k \"$p\"; done 2>/dev/null; true';\n\nconst wslStop = (env: Extract<Environment, { kind: 'wsl' }>, name: string) => {\n const half = Math.ceil(name.length / 2);\n return {\n command: 'wsl.exe',\n args: [\n ...(env.distro ? ['-d', env.distro] : []),\n '-e',\n 'sh',\n '-c',\n WSL_STOP,\n 'afd-stop',\n name.slice(0, half),\n name.slice(half),\n ],\n };\n};\n\nexport interface Paths {\n /** Repository root on this machine. */\n root: string;\n /** Folder with afd_probe/ and callback_plugins/. */\n probe: string;\n /** Catalog cache folder; the probe writes collection dumps there (M5). */\n cache?: string;\n}\n\nconst join = (a: string, b: string) => `${a.replace(/[\\\\/]+$/, '')}/${b}`;\n\n/**\n * A Windows path as WSL sees it (AFD-75): `C:\\x` is `/mnt/c/x`, and a path inside a distribution\n * (`\\\\wsl$\\Ubuntu\\home`, `\\\\wsl.localhost\\Ubuntu\\home`) is `/home`. Anything else stays as it is.\n */\nexport function wslPath(path: string): string {\n const p = path.replaceAll('\\\\', '/');\n const drive = /^([A-Za-z]):(\\/.*)?$/.exec(p);\n if (drive) return `/mnt/${drive[1]?.toLowerCase()}${(drive[2] ?? '').replace(/\\/+$/, '')}`;\n const inside = /^\\/\\/(?:wsl\\$|wsl\\.localhost)\\/[^/]+(\\/.*)?$/i.exec(p);\n if (inside) return inside[1] ?? '/';\n return p;\n}\n\n/** The repository, probe, run and cache folders as the environment sees them. */\nexport function insidePaths(\n env: Environment,\n paths: { root: string; probe: string; run?: string; cache?: string },\n): { root: string; probe: string; run?: string; cache?: string } {\n if (env.kind === 'container')\n return {\n root: CONTAINER.root,\n probe: CONTAINER.probe,\n run: CONTAINER.run,\n cache: CONTAINER.cache,\n };\n if (env.kind === 'wsl')\n return {\n root: wslPath(paths.root),\n probe: wslPath(paths.probe),\n run: paths.run && wslPath(paths.run),\n cache: paths.cache && wslPath(paths.cache),\n };\n if (env.kind === 'ssh') {\n // AFD-247: in a container on the host the mounts are the usual ones; else the copies there.\n if (env.container)\n return {\n root: CONTAINER.root,\n probe: CONTAINER.probe,\n run: CONTAINER.run,\n cache: CONTAINER.cache,\n };\n const there = remotePaths(env, paths.run);\n return { root: there.root, probe: there.probe, run: there.run, cache: there.cache };\n }\n return paths;\n}\n\n/**\n * `wsl.exe` up to the command it runs: the distribution, the folder to start in, and `-e`, which\n * passes the words as they are (after `--` the default shell parses them again, so `$x` in our\n * scripts would expand too early).\n */\nfunction wslArgs(env: Extract<Environment, { kind: 'wsl' }>, cwd: string): string[] {\n return [...(env.distro ? ['-d', env.distro] : []), '--cd', cwd, '-e'];\n}\n\n/**\n * The login PATH (pipx puts ansible in ~/.local/bin) without a login shell's output, which would\n * garble the probe's protocol on stdout.\n */\nconst WSL_PROFILE = LOGIN_PROFILE;\n\n/**\n * `$p`: the interpreter on ansible-playbook's #! line, else python3. Used unquoted, so a line like\n * `/usr/bin/env python3` stays two words.\n */\nconst WSL_ANSIBLE_PYTHON = `p=$(sed -n '1s/^#! *//p' \"$(command -v ansible-playbook)\" 2>/dev/null); [ -n \"$p\" ] || p=python3`;\n\n/** AFD-247: the same stop as WSL's, on the host: the run's shell carries its name. */\nconst sshStop = (host: string, name: string) => {\n const half = Math.ceil(name.length / 2);\n return onHost(\n host,\n `sh -c ${shQuote(WSL_STOP)} afd-stop ${shQuote(name.slice(0, half))} ${shQuote(name.slice(half))}`,\n );\n};\n\n/** AFD-247: `docker run` words for a container on the host, over the copies there. */\nfunction remoteContainer(\n env: Extract<Environment, { kind: 'ssh' }>,\n name: string,\n runDir?: string,\n): string[] {\n const there = remotePaths(env, runDir);\n const words = ['run', '--rm', '--name', name, '-v', `${there.root}:${CONTAINER.root}:ro`];\n words.push('-v', `${there.probe}:${CONTAINER.probe}:ro`, '-w', CONTAINER.root);\n return words;\n}\n\nfunction containerBase(\n env: Extract<Environment, { kind: 'container' }>,\n paths: Paths,\n name: string,\n) {\n const args = ['run', '--rm', '--name', name, '-v', `${paths.root}:${CONTAINER.root}:ro`];\n args.push('-v', `${paths.probe}:${CONTAINER.probe}:ro`, '-w', CONTAINER.root);\n for (const m of env.mounts)\n args.push('-v', `${m.src}:${m.dest}${m.options ? `:${m.options}` : ''}`);\n return args;\n}\n\nexport function probeProcess(env: Environment, paths: Paths, name: string): ProcessSpec {\n const tail = ['-m', 'afd_probe', 'serve', '--root'];\n if (env.kind === 'container') {\n const args = containerBase(env, paths, name);\n args.splice(1, 0, '-i');\n if (paths.cache) args.push('-v', `${paths.cache}:${CONTAINER.cache}`);\n args.push('-e', `PYTHONPATH=${CONTAINER.probe}`, '-e', 'PYTHONDONTWRITEBYTECODE=1');\n args.push(...env.options, env.image, 'python3', ...tail, CONTAINER.root);\n return { command: env.engine, args, env: {}, stop: containerStop(env, name) };\n }\n if (env.kind === 'ssh') {\n // AFD-247: the probe over the copies on the host; its input and output are the connection's.\n const there = remotePaths(env);\n if (env.container) {\n const c = env.container;\n const words = remoteContainer(env, name);\n words.splice(1, 0, '-i');\n words.push('-v', `${there.cache}:${CONTAINER.cache}`);\n words.push('-e', `PYTHONPATH=${CONTAINER.probe}`, '-e', 'PYTHONDONTWRITEBYTECODE=1');\n words.push(...c.options, c.image, 'python3', ...tail, CONTAINER.root);\n const script = `mkdir -p ${rq(there.cache)} && exec ${c.engine} ${words.map(rq).join(' ')}`;\n return {\n ...onHost(env.host, script),\n env: {},\n stop: onHost(env.host, `${c.engine} rm -f ${shQuote(name)}`),\n };\n }\n const python = env.python ? rq(env.python) : '$p';\n const vars = `PYTHONPATH=${rq(there.probe)} PYTHONDONTWRITEBYTECODE=1`;\n const serve = `mkdir -p ${rq(there.cache)} && cd ${rq(there.root)} && exec env ${vars} ${python} ${[...tail, there.root].map(rq).join(' ')}`;\n const script = [LOGIN_PROFILE, ...(env.python ? [] : [WSL_ANSIBLE_PYTHON]), serve].join('; ');\n return { ...onHost(env.host, script), env: {} };\n }\n if (env.kind === 'wsl') {\n // The variables are set inside the distribution; WSLENV is only for values from Windows.\n const inside = insidePaths(env, paths);\n const python = env.python ? shQuote(env.python) : '$p';\n const vars = `PYTHONPATH=${shQuote(inside.probe)} PYTHONDONTWRITEBYTECODE=1`;\n const serve = `exec env ${vars} ${python} ${[...tail, inside.root].map(shQuote).join(' ')}`;\n const script = [WSL_PROFILE, ...(env.python ? [] : [WSL_ANSIBLE_PYTHON]), serve].join('; ');\n return {\n command: 'wsl.exe',\n args: [...wslArgs(env, inside.root), 'sh', '-c', script],\n env: {},\n };\n }\n return {\n command: env.python,\n args: [...tail, paths.root],\n env: { PYTHONPATH: paths.probe, PYTHONDONTWRITEBYTECODE: '1' },\n cwd: paths.root,\n };\n}\n\nexport interface RunRequest {\n /** Root playbook, relative to the repository root (forward slashes). */\n playbook: string;\n /** Inventory relative to the repository root; empty = ansible.cfg default. */\n inventory?: string;\n check: boolean;\n /** Folder for vars.json and events.jsonl on this machine. */\n runDir: string;\n /** Ask Ansible for the vault password through AFD_VAULT_PASSWORD (set by the caller). */\n vault: boolean;\n /** Secret inputs travel as JSON in AFD_SECRET_VARS (set by the caller), never in vars.json. */\n secrets?: boolean;\n /** Use <root>/ansible.cfg explicitly (Docker Desktop mounts are world-writable). */\n hasConfig: boolean;\n /**\n * AFD-126: use the empty ansible.cfg the caller wrote in the run folder, so no repository, user\n * or system config applies. Ansible reads ./ansible.cfg from the working directory (the\n * repository) when ANSIBLE_CONFIG names no existing file, and its plugin paths are code.\n */\n emptyConfig?: boolean;\n /**\n * AFD-141: the callbacks the repository's config enables, and where they live (the probe's\n * `run_config`, paths as the environment sees them). Ours is added to them instead of replacing\n * them, so an audit callback an organisation requires keeps running.\n */\n callbacks?: { enabled: string[]; paths: string[] };\n /**\n * AFD-159: a folder inside runDir for events.jsonl, the only one an image's own user writes to\n * (a scenario run keeps the rest of its folder to its owner).\n */\n eventsDir?: string;\n}\n\n/** Callback names and plugin folders that can go into a comma or colon list as they are. */\nconst CALLBACK_NAME = /^[\\w.]+$/;\nconst pluginPath = (p: string) => p !== '' && !/[:\\n\\r]/.test(p);\n\n/** Run inputs split by name, with the import's rule: secret-looking ones never reach vars.json. */\nexport function splitInputs(inputs: Record<string, unknown>): {\n plain: Record<string, unknown>;\n secret: Record<string, unknown>;\n} {\n const plain: Record<string, unknown> = {};\n const secret: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(inputs)) (SECRET.test(k) ? secret : plain)[k] = v;\n return { plain, secret };\n}\n\n/** Environment variables every run gets: our event callback and quiet routing groups. */\nfunction runEnv(\n probeDir: string,\n runDir: string,\n root: string,\n config: Pick<RunRequest, 'hasConfig' | 'emptyConfig' | 'callbacks' | 'eventsDir'>,\n) {\n const ours = join(probeDir, 'callback_plugins');\n // AFD-141: these variables replace ansible.cfg's values, so the repository's go first.\n const theirs = config.emptyConfig ? undefined : config.callbacks;\n const enabled = [...(theirs?.enabled ?? []).filter((n) => CALLBACK_NAME.test(n)), 'afd_events'];\n const plugins = [...(theirs?.paths ?? []).filter(pluginPath), ours];\n const env: Record<string, string> = {\n ANSIBLE_CALLBACK_PLUGINS: [...new Set(plugins)].join(':'),\n ANSIBLE_CALLBACKS_ENABLED: [...new Set(enabled)].join(','),\n AFD_EVENTS: join(config.eventsDir ? join(runDir, config.eventsDir) : runDir, 'events.jsonl'),\n ANSIBLE_HOST_PATTERN_MISMATCH: 'ignore',\n ANSIBLE_FORCE_COLOR: '1',\n };\n if (config.emptyConfig) env.ANSIBLE_CONFIG = join(runDir, 'ansible.cfg');\n else if (config.hasConfig) env.ANSIBLE_CONFIG = join(root, 'ansible.cfg');\n return env;\n}\n\n/**\n * `ansible-playbook` for a run. Secret inputs ($AFD_SECRET_VARS) and the vault password\n * ($AFD_VAULT_PASSWORD) come in variables only (AFD-29) and go into temporary files inside the\n * environment, owner-only, that live as long as the run.\n * AFD-138:\n * - a trap removes the files on every exit, also when the run is stopped or the terminal closed;\n * - both variables are unset once written, so ansible-playbook and what it starts (local tasks,\n * inventory scripts, lookup('env')) never see them;\n * - the vault password file is a script that `cat`s the password file, so the password is never\n * parsed by a shell (dash's echo turned `\\c` and `\\n` in it into other characters).\n * AFD-139: AFD_SECRETS_FILE and AFD_VAULT_FILE name those files for the event callback, which\n * leaves their values out of every event it writes.\n */\nexport function runProcess(\n env: Environment,\n paths: Paths,\n request: RunRequest,\n name: string,\n): ProcessSpec {\n const inContainer = env.kind === 'container';\n const inside = insidePaths(env, { ...paths, run: request.runDir });\n const root = inside.root;\n const runDir = inside.run ?? request.runDir;\n const probeDir = inside.probe;\n const words = ['ansible-playbook'];\n if (request.inventory) words.push('-i', request.inventory);\n words.push('-e', `@${join(runDir, 'vars.json')}`);\n if (request.secrets) words.push('-e', '@\"$sv\"');\n if (request.check) words.push('--check');\n if (request.vault) words.push('--vault-password-file', '\"$vp\"');\n words.push(request.playbook);\n const raw = new Set(['\"$vp\"', '@\"$sv\"']);\n // AFD-247: on an SSH host the paths start at its home folder, expanded there.\n const q = env.kind === 'ssh' && !env.container ? rq : shQuote;\n const line = words.map((w) => (raw.has(w) ? w : q(w))).join(' ');\n const setup: string[] = [];\n const temps: string[] = [];\n if (request.vault) {\n setup.push(\n `pw=$(mktemp) && printf '%s\\\\n' \"$AFD_VAULT_PASSWORD\" > \"$pw\" && unset AFD_VAULT_PASSWORD`,\n `vp=$(mktemp) && printf '#!/bin/sh\\\\ncat \"%s\"\\\\n' \"$pw\" > \"$vp\" && chmod 700 \"$vp\"`,\n 'export AFD_VAULT_FILE=\"$pw\"',\n );\n temps.push('\"$pw\"', '\"$vp\"');\n }\n if (request.secrets) {\n setup.push(\n `sv=$(mktemp) && printf '%s' \"$AFD_SECRET_VARS\" > \"$sv\" && unset AFD_SECRET_VARS`,\n 'export AFD_SECRETS_FILE=\"$sv\"',\n );\n temps.push('\"$sv\"');\n }\n // EXIT runs on every exit; the signal traps turn a stop into an exit, so EXIT runs then too.\n const trap = `trap 'rm -f ${temps.join(' ')}' EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM`;\n const script = setup.length ? `${trap}; ${setup.join(' && ')} && ${line}` : line;\n const variables = runEnv(probeDir, runDir, root, request);\n if (inContainer) {\n const args = containerBase(env, paths, name);\n args.push('-v', `${request.runDir}:${CONTAINER.run}`);\n for (const [k, v] of Object.entries(variables)) args.push('-e', `${k}=${v}`);\n if (request.vault) args.push('-e', 'AFD_VAULT_PASSWORD');\n if (request.secrets) args.push('-e', 'AFD_SECRET_VARS');\n args.push(...env.options, env.image, 'sh', '-c', script);\n return { command: env.engine, args, env: {}, stop: containerStop(env, name) };\n }\n if (env.kind === 'ssh') {\n // AFD-247: ssh passes no environment, so the secrets come on the connection's input.\n const input = [\n ...(request.vault ? ['AFD_VAULT_PASSWORD'] : []),\n ...(request.secrets ? ['AFD_SECRET_VARS'] : []),\n ];\n const first = input.length ? [readFromInput(input)] : [];\n if (env.container) {\n const c = env.container;\n const there = remotePaths(env, request.runDir);\n const dockerWords = remoteContainer(env, name, request.runDir);\n dockerWords.push('-v', `${there.run}:${CONTAINER.run}`);\n for (const [k, v] of Object.entries(variables)) dockerWords.push('-e', `${k}=${v}`);\n for (const n of input) dockerWords.push('-e', n);\n dockerWords.push(...c.options, c.image, 'sh', '-c', script);\n const run = `exec ${c.engine} ${dockerWords.map(rq).join(' ')}`;\n return {\n ...onHost(env.host, [...first, run].join(' && ')),\n env: {},\n stop: onHost(env.host, `${c.engine} rm -f ${shQuote(name)}`),\n ...(input.length ? { input } : {}),\n };\n }\n const vars = Object.entries(variables).map(([k, v]) => rq(`${k}=${v}`));\n // The name is the shell's $0, which the stop finds it by, as for WSL.\n const run = `cd ${rq(root)} && exec env ${vars.join(' ')} sh -c ${shQuote(script)} ${shQuote(name)}`;\n return {\n ...onHost(env.host, `${LOGIN_PROFILE}; ${[...first, run].join(' && ')}`),\n env: {},\n stop: sshStop(env.host, name),\n ...(input.length ? { input } : {}),\n };\n }\n if (env.kind === 'wsl') {\n // The secrets come from Windows in variables only: WSLENV passes just those names (AFD-29).\n const pass = [\n ...(request.vault ? ['AFD_VAULT_PASSWORD/u'] : []),\n ...(request.secrets ? ['AFD_SECRET_VARS/u'] : []),\n ];\n const vars = Object.entries(variables).map(([k, v]) => `${k}=${v}`);\n return {\n command: 'wsl.exe',\n // The name is the shell's $0, which WSL_STOP finds it by (AFD-131).\n args: [...wslArgs(env, root), 'env', ...vars, 'sh', '-c', `${WSL_PROFILE}; ${script}`, name],\n env: pass.length ? { WSLENV: pass.join(':') } : {},\n stop: wslStop(env, name),\n };\n }\n return { command: 'sh', args: ['-c', script], env: variables, cwd: paths.root };\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
6
|
-
"names": ["script", "run"]
|
|
4
|
+
"sourcesContent": ["// Command lines for the probe session and for flow runs in an environment (ADR-0005, ADR-0009).\n// Pure: the host supplies paths; container paths are fixed so generated code and events map back,\n// and a WSL distribution sees this machine's drives under /mnt (AFD-75).\nimport { SECRET } from '../import/secrets';\nimport type { Environment } from './environment';\nimport { LOGIN_PROFILE, onHost, readFromInput, remotePaths, rq, shQuote } from './ssh';\n\nexport { shQuote };\n\nexport const CONTAINER = {\n root: '/work',\n probe: '/afd',\n run: '/afd-run',\n /** The catalog cache in global storage, read-write (M5). */\n cache: '/afd-cache',\n} as const;\n\nexport interface ProcessSpec {\n command: string;\n args: string[];\n /** Extra environment for the spawned process (values never appear in args). */\n env: Record<string, string>;\n cwd?: string;\n /**\n * AFD-131: what ends the work this process started beyond itself. Killing the docker or podman\n * client leaves its container running (the shell inside is PID 1 and ignores SIGTERM), so a\n * stopped run, a timed-out scenario or a hung probe call also removes the container by name.\n */\n stop?: { command: string; args: string[] };\n /**\n * AFD-247: variables of `env` that go to the process on its input instead (one base64 line\n * each, in this order): ssh passes no environment to the host, and they are never arguments.\n */\n input?: string[];\n}\n\nconst containerStop = (env: Extract<Environment, { kind: 'container' }>, name: string) => ({\n command: env.engine,\n args: ['rm', '-f', name],\n});\n\n/**\n * AFD-131: ends a WSL run from Windows. Killing wsl.exe leaves ansible-playbook running in the\n * distribution, so the run's shell carries its name as `$0`, and this finds it with pgrep and\n * ends it with every process under it, children first (ansible-playbook and its workers; the\n * shell's EXIT trap then removes the secret files). Not by process group: in WSL 1 the shells of\n * separate `wsl -e` sessions can share one, and this shell or another run would go with it. The\n * name is passed in two parts so the pattern never matches this shell.\n */\nconst WSL_STOP =\n 'k() { for c in $(pgrep -P \"$1\"); do k \"$c\"; done; kill -TERM \"$1\"; }; ' +\n 'for p in $(pgrep -f -- \"$1$2\"); do k \"$p\"; done 2>/dev/null; true';\n\nconst wslStop = (env: Extract<Environment, { kind: 'wsl' }>, name: string) => {\n const half = Math.ceil(name.length / 2);\n return {\n command: 'wsl.exe',\n args: [\n ...(env.distro ? ['-d', env.distro] : []),\n '-e',\n 'sh',\n '-c',\n WSL_STOP,\n 'afd-stop',\n name.slice(0, half),\n name.slice(half),\n ],\n };\n};\n\nexport interface Paths {\n /** Repository root on this machine. */\n root: string;\n /** Folder with afd_probe/ and callback_plugins/. */\n probe: string;\n /** Catalog cache folder; the probe writes collection dumps there (M5). */\n cache?: string;\n}\n\nconst join = (a: string, b: string) => `${a.replace(/[\\\\/]+$/, '')}/${b}`;\n\n/**\n * A Windows path as WSL sees it (AFD-75): `C:\\x` is `/mnt/c/x`, and a path inside a distribution\n * (`\\\\wsl$\\Ubuntu\\home`, `\\\\wsl.localhost\\Ubuntu\\home`) is `/home`. Anything else stays as it is.\n */\nexport function wslPath(path: string): string {\n const p = path.replaceAll('\\\\', '/');\n const drive = /^([A-Za-z]):(\\/.*)?$/.exec(p);\n if (drive) return `/mnt/${drive[1]?.toLowerCase()}${(drive[2] ?? '').replace(/\\/+$/, '')}`;\n const inside = /^\\/\\/(?:wsl\\$|wsl\\.localhost)\\/[^/]+(\\/.*)?$/i.exec(p);\n if (inside) return inside[1] ?? '/';\n return p;\n}\n\n/** The repository, probe, run and cache folders as the environment sees them. */\nexport function insidePaths(\n env: Environment,\n paths: { root: string; probe: string; run?: string; cache?: string },\n): { root: string; probe: string; run?: string; cache?: string } {\n if (env.kind === 'container')\n return {\n root: CONTAINER.root,\n probe: CONTAINER.probe,\n run: CONTAINER.run,\n cache: CONTAINER.cache,\n };\n if (env.kind === 'wsl')\n return {\n root: wslPath(paths.root),\n probe: wslPath(paths.probe),\n run: paths.run && wslPath(paths.run),\n cache: paths.cache && wslPath(paths.cache),\n };\n if (env.kind === 'ssh') {\n // AFD-247: in a container on the host the mounts are the usual ones; else the copies there.\n if (env.container)\n return {\n root: CONTAINER.root,\n probe: CONTAINER.probe,\n run: CONTAINER.run,\n cache: CONTAINER.cache,\n };\n const there = remotePaths(env, paths.run);\n return { root: there.root, probe: there.probe, run: there.run, cache: there.cache };\n }\n return paths;\n}\n\n/**\n * `wsl.exe` up to the command it runs: the distribution, the folder to start in, and `-e`, which\n * passes the words as they are (after `--` the default shell parses them again, so `$x` in our\n * scripts would expand too early).\n */\nfunction wslArgs(env: Extract<Environment, { kind: 'wsl' }>, cwd: string): string[] {\n return [...(env.distro ? ['-d', env.distro] : []), '--cd', cwd, '-e'];\n}\n\n/**\n * The login PATH (pipx puts ansible in ~/.local/bin) without a login shell's output, which would\n * garble the probe's protocol on stdout.\n */\nconst WSL_PROFILE = LOGIN_PROFILE;\n\n/**\n * `$p`: the interpreter on ansible-playbook's #! line, else python3. Used unquoted, so a line like\n * `/usr/bin/env python3` stays two words.\n */\nconst WSL_ANSIBLE_PYTHON = `p=$(sed -n '1s/^#! *//p' \"$(command -v ansible-playbook)\" 2>/dev/null); [ -n \"$p\" ] || p=python3`;\n\n/** AFD-247: the same stop as WSL's, on the host: the run's shell carries its name. */\nconst sshStop = (host: string, name: string) => {\n const half = Math.ceil(name.length / 2);\n return onHost(\n host,\n `sh -c ${shQuote(WSL_STOP)} afd-stop ${shQuote(name.slice(0, half))} ${shQuote(name.slice(half))}`,\n );\n};\n\n/** AFD-247: `docker run` words for a container on the host, over the copies there. */\nfunction remoteContainer(\n env: Extract<Environment, { kind: 'ssh' }>,\n name: string,\n runDir?: string,\n): string[] {\n const there = remotePaths(env, runDir);\n const words = ['run', '--rm', '--name', name, '-v', `${there.root}:${CONTAINER.root}:ro`];\n words.push('-v', `${there.probe}:${CONTAINER.probe}:ro`, '-w', CONTAINER.root);\n return words;\n}\n\nfunction containerBase(\n env: Extract<Environment, { kind: 'container' }>,\n paths: Paths,\n name: string,\n) {\n const args = ['run', '--rm', '--name', name, '-v', `${paths.root}:${CONTAINER.root}:ro`];\n args.push('-v', `${paths.probe}:${CONTAINER.probe}:ro`, '-w', CONTAINER.root);\n for (const m of env.mounts)\n args.push('-v', `${m.src}:${m.dest}${m.options ? `:${m.options}` : ''}`);\n return args;\n}\n\nexport function probeProcess(env: Environment, paths: Paths, name: string): ProcessSpec {\n const tail = ['-m', 'afd_probe', 'serve', '--root'];\n if (env.kind === 'container') {\n const args = containerBase(env, paths, name);\n args.splice(1, 0, '-i');\n if (paths.cache) args.push('-v', `${paths.cache}:${CONTAINER.cache}`);\n args.push('-e', `PYTHONPATH=${CONTAINER.probe}`, '-e', 'PYTHONDONTWRITEBYTECODE=1');\n args.push(...env.options, env.image, 'python3', ...tail, CONTAINER.root);\n return { command: env.engine, args, env: {}, stop: containerStop(env, name) };\n }\n if (env.kind === 'ssh') {\n // AFD-247: the probe over the copies on the host; its input and output are the connection's.\n const there = remotePaths(env);\n if (env.container) {\n const c = env.container;\n const words = remoteContainer(env, name);\n words.splice(1, 0, '-i');\n words.push('-v', `${there.cache}:${CONTAINER.cache}`);\n words.push('-e', `PYTHONPATH=${CONTAINER.probe}`, '-e', 'PYTHONDONTWRITEBYTECODE=1');\n words.push(...c.options, c.image, 'python3', ...tail, CONTAINER.root);\n const script = `mkdir -p ${rq(there.cache)} && exec ${c.engine} ${words.map(rq).join(' ')}`;\n return {\n ...onHost(env.host, script),\n env: {},\n stop: onHost(env.host, `${c.engine} rm -f ${shQuote(name)}`),\n };\n }\n const python = env.python ? rq(env.python) : '$p';\n const vars = `PYTHONPATH=${rq(there.probe)} PYTHONDONTWRITEBYTECODE=1`;\n const serve = `mkdir -p ${rq(there.cache)} && cd ${rq(there.root)} && exec env ${vars} ${python} ${[...tail, there.root].map(rq).join(' ')}`;\n const script = [LOGIN_PROFILE, ...(env.python ? [] : [WSL_ANSIBLE_PYTHON]), serve].join('; ');\n return { ...onHost(env.host, script), env: {} };\n }\n if (env.kind === 'wsl') {\n // The variables are set inside the distribution; WSLENV is only for values from Windows.\n const inside = insidePaths(env, paths);\n const python = env.python ? shQuote(env.python) : '$p';\n const vars = `PYTHONPATH=${shQuote(inside.probe)} PYTHONDONTWRITEBYTECODE=1`;\n const serve = `exec env ${vars} ${python} ${[...tail, inside.root].map(shQuote).join(' ')}`;\n const script = [WSL_PROFILE, ...(env.python ? [] : [WSL_ANSIBLE_PYTHON]), serve].join('; ');\n return {\n command: 'wsl.exe',\n args: [...wslArgs(env, inside.root), 'sh', '-c', script],\n env: {},\n };\n }\n return {\n command: env.python,\n args: [...tail, paths.root],\n env: { PYTHONPATH: paths.probe, PYTHONDONTWRITEBYTECODE: '1' },\n cwd: paths.root,\n };\n}\n\nexport interface RunRequest {\n /** Root playbook, relative to the repository root (forward slashes). */\n playbook: string;\n /** Inventory relative to the repository root; empty = ansible.cfg default. */\n inventory?: string;\n check: boolean;\n /** Folder for vars.json and events.jsonl on this machine. */\n runDir: string;\n /** Ask Ansible for the vault password through AFD_VAULT_PASSWORD (set by the caller). */\n vault: boolean;\n /** Secret inputs travel as JSON in AFD_SECRET_VARS (set by the caller), never in vars.json. */\n secrets?: boolean;\n /** Use <root>/ansible.cfg explicitly (Docker Desktop mounts are world-writable). */\n hasConfig: boolean;\n /**\n * AFD-126: use the empty ansible.cfg the caller wrote in the run folder, so no repository, user\n * or system config applies. Ansible reads ./ansible.cfg from the working directory (the\n * repository) when ANSIBLE_CONFIG names no existing file, and its plugin paths are code.\n */\n emptyConfig?: boolean;\n /**\n * AFD-141: the callbacks the repository's config enables, and where they live (the probe's\n * `run_config`, paths as the environment sees them). Ours is added to them instead of replacing\n * them, so an audit callback an organisation requires keeps running.\n */\n callbacks?: RepositoryConfig;\n /**\n * AFD-159: a folder inside runDir for events.jsonl, the only one an image's own user writes to\n * (a scenario run keeps the rest of its folder to its owner).\n */\n eventsDir?: string;\n}\n\n/**\n * What a run keeps of the repository's Ansible config (the probe's `run_config`, paths as the\n * environment sees them): the callbacks it enables (AFD-141) and, AFD-291, its module, module_utils\n * and plugin paths and enabled vars plugins, which the run's own variables would replace.\n */\nexport interface RepositoryConfig {\n enabled: string[];\n paths: string[];\n /** By folder name (`library`, `filter_plugins`, ...): the paths the config gives. */\n plugins?: Record<string, string[]>;\n varsEnabled?: string[];\n}\n\n/**\n * AFD-291: the repository's own folders a playbook next to them would get, and the variable that\n * sets each. Generated playbooks run from flows/<key>/generated, so a run adds them by hand.\n */\nconst REPO_FOLDERS: [folder: string, variable: string][] = [\n ['library', 'ANSIBLE_LIBRARY'],\n ['module_utils', 'ANSIBLE_MODULE_UTILS'],\n ['action_plugins', 'ANSIBLE_ACTION_PLUGINS'],\n ['filter_plugins', 'ANSIBLE_FILTER_PLUGINS'],\n ['lookup_plugins', 'ANSIBLE_LOOKUP_PLUGINS'],\n ['test_plugins', 'ANSIBLE_TEST_PLUGINS'],\n];\n\n/** Callback names and plugin folders that can go into a comma or colon list as they are. */\nconst CALLBACK_NAME = /^[\\w.]+$/;\nconst pluginPath = (p: string) => p !== '' && !/[:\\n\\r]/.test(p);\n\n/** Run inputs split by name, with the import's rule: secret-looking ones never reach vars.json. */\nexport function splitInputs(inputs: Record<string, unknown>): {\n plain: Record<string, unknown>;\n secret: Record<string, unknown>;\n} {\n const plain: Record<string, unknown> = {};\n const secret: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(inputs)) (SECRET.test(k) ? secret : plain)[k] = v;\n return { plain, secret };\n}\n\n/** Environment variables every run gets: our event callback and quiet routing groups. */\nfunction runEnv(\n probeDir: string,\n runDir: string,\n root: string,\n config: Pick<RunRequest, 'hasConfig' | 'emptyConfig' | 'callbacks' | 'eventsDir'>,\n) {\n const ours = join(probeDir, 'callback_plugins');\n // AFD-141: these variables replace ansible.cfg's values, so the repository's go first.\n const theirs = config.emptyConfig ? undefined : config.callbacks;\n const enabled = [...(theirs?.enabled ?? []).filter((n) => CALLBACK_NAME.test(n)), 'afd_events'];\n const plugins = [...(theirs?.paths ?? []).filter(pluginPath), ours];\n const env: Record<string, string> = {\n ANSIBLE_CALLBACK_PLUGINS: [...new Set(plugins)].join(':'),\n ANSIBLE_CALLBACKS_ENABLED: [...new Set(enabled)].join(','),\n AFD_EVENTS: join(config.eventsDir ? join(runDir, config.eventsDir) : runDir, 'events.jsonl'),\n ANSIBLE_HOST_PATTERN_MISMATCH: 'ignore',\n ANSIBLE_FORCE_COLOR: '1',\n };\n if (config.emptyConfig) env.ANSIBLE_CONFIG = join(runDir, 'ansible.cfg');\n else if (config.hasConfig) env.ANSIBLE_CONFIG = join(root, 'ansible.cfg');\n // AFD-291: the repository's library/, module_utils/ and plugin folders, after the ones its config\n // gives, and its root group_vars/host_vars through our vars plugin. Only when the config is\n // known: these variables replace its values. Not with the empty config: plugins are code.\n if (theirs?.plugins) {\n const list = (paths: string[] | undefined, own: string) =>\n [...new Set([...(paths ?? []).filter(pluginPath), own])].join(':');\n for (const [folder, variable] of REPO_FOLDERS)\n env[variable] = list(theirs.plugins[folder], join(root, folder));\n env.ANSIBLE_VARS_PLUGINS = list(theirs.plugins.vars_plugins, join(probeDir, 'vars_plugins'));\n const enabled = (theirs.varsEnabled ?? []).filter((n) => CALLBACK_NAME.test(n));\n env.ANSIBLE_VARS_ENABLED = [\n ...new Set([...(enabled.length ? enabled : ['host_group_vars']), 'afd_repo_vars']),\n ].join(',');\n env.AFD_REPO_ROOT = root;\n }\n return env;\n}\n\n/**\n * `ansible-playbook` for a run. Secret inputs ($AFD_SECRET_VARS) and the vault password\n * ($AFD_VAULT_PASSWORD) come in variables only (AFD-29) and go into temporary files inside the\n * environment, owner-only, that live as long as the run.\n * AFD-138:\n * - a trap removes the files on every exit, also when the run is stopped or the terminal closed;\n * - both variables are unset once written, so ansible-playbook and what it starts (local tasks,\n * inventory scripts, lookup('env')) never see them;\n * - the vault password file is a script that `cat`s the password file, so the password is never\n * parsed by a shell (dash's echo turned `\\c` and `\\n` in it into other characters).\n * AFD-139: AFD_SECRETS_FILE and AFD_VAULT_FILE name those files for the event callback, which\n * leaves their values out of every event it writes.\n */\nexport function runProcess(\n env: Environment,\n paths: Paths,\n request: RunRequest,\n name: string,\n): ProcessSpec {\n const inContainer = env.kind === 'container';\n const inside = insidePaths(env, { ...paths, run: request.runDir });\n const root = inside.root;\n const runDir = inside.run ?? request.runDir;\n const probeDir = inside.probe;\n const words = ['ansible-playbook'];\n if (request.inventory) words.push('-i', request.inventory);\n words.push('-e', `@${join(runDir, 'vars.json')}`);\n if (request.secrets) words.push('-e', '@\"$sv\"');\n if (request.check) words.push('--check');\n if (request.vault) words.push('--vault-password-file', '\"$vp\"');\n words.push(request.playbook);\n const raw = new Set(['\"$vp\"', '@\"$sv\"']);\n // AFD-247: on an SSH host the paths start at its home folder, expanded there.\n const q = env.kind === 'ssh' && !env.container ? rq : shQuote;\n const line = words.map((w) => (raw.has(w) ? w : q(w))).join(' ');\n const setup: string[] = [];\n const temps: string[] = [];\n if (request.vault) {\n setup.push(\n `pw=$(mktemp) && printf '%s\\\\n' \"$AFD_VAULT_PASSWORD\" > \"$pw\" && unset AFD_VAULT_PASSWORD`,\n `vp=$(mktemp) && printf '#!/bin/sh\\\\ncat \"%s\"\\\\n' \"$pw\" > \"$vp\" && chmod 700 \"$vp\"`,\n 'export AFD_VAULT_FILE=\"$pw\"',\n );\n temps.push('\"$pw\"', '\"$vp\"');\n }\n if (request.secrets) {\n setup.push(\n `sv=$(mktemp) && printf '%s' \"$AFD_SECRET_VARS\" > \"$sv\" && unset AFD_SECRET_VARS`,\n 'export AFD_SECRETS_FILE=\"$sv\"',\n );\n temps.push('\"$sv\"');\n }\n // EXIT runs on every exit; the signal traps turn a stop into an exit, so EXIT runs then too.\n const trap = `trap 'rm -f ${temps.join(' ')}' EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM`;\n const script = setup.length ? `${trap}; ${setup.join(' && ')} && ${line}` : line;\n const variables = runEnv(probeDir, runDir, root, request);\n if (inContainer) {\n const args = containerBase(env, paths, name);\n args.push('-v', `${request.runDir}:${CONTAINER.run}`);\n for (const [k, v] of Object.entries(variables)) args.push('-e', `${k}=${v}`);\n if (request.vault) args.push('-e', 'AFD_VAULT_PASSWORD');\n if (request.secrets) args.push('-e', 'AFD_SECRET_VARS');\n args.push(...env.options, env.image, 'sh', '-c', script);\n return { command: env.engine, args, env: {}, stop: containerStop(env, name) };\n }\n if (env.kind === 'ssh') {\n // AFD-247: ssh passes no environment, so the secrets come on the connection's input.\n const input = [\n ...(request.vault ? ['AFD_VAULT_PASSWORD'] : []),\n ...(request.secrets ? ['AFD_SECRET_VARS'] : []),\n ];\n const first = input.length ? [readFromInput(input)] : [];\n if (env.container) {\n const c = env.container;\n const there = remotePaths(env, request.runDir);\n const dockerWords = remoteContainer(env, name, request.runDir);\n dockerWords.push('-v', `${there.run}:${CONTAINER.run}`);\n for (const [k, v] of Object.entries(variables)) dockerWords.push('-e', `${k}=${v}`);\n for (const n of input) dockerWords.push('-e', n);\n dockerWords.push(...c.options, c.image, 'sh', '-c', script);\n const run = `exec ${c.engine} ${dockerWords.map(rq).join(' ')}`;\n return {\n ...onHost(env.host, [...first, run].join(' && ')),\n env: {},\n stop: onHost(env.host, `${c.engine} rm -f ${shQuote(name)}`),\n ...(input.length ? { input } : {}),\n };\n }\n const vars = Object.entries(variables).map(([k, v]) => rq(`${k}=${v}`));\n // The name is the shell's $0, which the stop finds it by, as for WSL.\n const run = `cd ${rq(root)} && exec env ${vars.join(' ')} sh -c ${shQuote(script)} ${shQuote(name)}`;\n return {\n ...onHost(env.host, `${LOGIN_PROFILE}; ${[...first, run].join(' && ')}`),\n env: {},\n stop: sshStop(env.host, name),\n ...(input.length ? { input } : {}),\n };\n }\n if (env.kind === 'wsl') {\n // The secrets come from Windows in variables only: WSLENV passes just those names (AFD-29).\n const pass = [\n ...(request.vault ? ['AFD_VAULT_PASSWORD/u'] : []),\n ...(request.secrets ? ['AFD_SECRET_VARS/u'] : []),\n ];\n const vars = Object.entries(variables).map(([k, v]) => `${k}=${v}`);\n return {\n command: 'wsl.exe',\n // The name is the shell's $0, which WSL_STOP finds it by (AFD-131).\n args: [...wslArgs(env, root), 'env', ...vars, 'sh', '-c', `${WSL_PROFILE}; ${script}`, name],\n env: pass.length ? { WSLENV: pass.join(':') } : {},\n stop: wslStop(env, name),\n };\n }\n return { command: 'sh', args: ['-c', script], env: variables, cwd: paths.root };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;AASO,IAAM,YAAY;AAAA,EACvB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA;AAAA,EAEL,OAAO;AACT;AAqBA,IAAM,gBAAgB,CAAC,KAAkD,UAAkB;AAAA,EACzF,SAAS,IAAI;AAAA,EACb,MAAM,CAAC,MAAM,MAAM,IAAI;AACzB;AAUA,IAAM,WACJ;AAGF,IAAM,UAAU,CAAC,KAA4C,SAAiB;AAC5E,QAAM,OAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AACtC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,GAAI,IAAI,SAAS,CAAC,MAAM,IAAI,MAAM,IAAI,CAAC;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,GAAG,IAAI;AAAA,MAClB,KAAK,MAAM,IAAI;AAAA,IACjB;AAAA,EACF;AACF;AAWA,IAAM,OAAO,CAAC,GAAW,MAAc,GAAG,EAAE,QAAQ,WAAW,EAAE,CAAC,IAAI,CAAC;AAMhE,SAAS,QAAQ,MAAsB;AAC5C,QAAM,IAAI,KAAK,WAAW,MAAM,GAAG;AACnC,QAAM,QAAQ,uBAAuB,KAAK,CAAC;AAC3C,MAAI,MAAO,QAAO,QAAQ,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,MAAM,CAAC,KAAK,IAAI,QAAQ,QAAQ,EAAE,CAAC;AACxF,QAAM,SAAS,gDAAgD,KAAK,CAAC;AACrE,MAAI,OAAQ,QAAO,OAAO,CAAC,KAAK;AAChC,SAAO;AACT;AAGO,SAAS,YACd,KACA,OAC+D;AAC/D,MAAI,IAAI,SAAS;AACf,WAAO;AAAA,MACL,MAAM,UAAU;AAAA,MAChB,OAAO,UAAU;AAAA,MACjB,KAAK,UAAU;AAAA,MACf,OAAO,UAAU;AAAA,IACnB;AACF,MAAI,IAAI,SAAS;AACf,WAAO;AAAA,MACL,MAAM,QAAQ,MAAM,IAAI;AAAA,MACxB,OAAO,QAAQ,MAAM,KAAK;AAAA,MAC1B,KAAK,MAAM,OAAO,QAAQ,MAAM,GAAG;AAAA,MACnC,OAAO,MAAM,SAAS,QAAQ,MAAM,KAAK;AAAA,IAC3C;AACF,MAAI,IAAI,SAAS,OAAO;AAEtB,QAAI,IAAI;AACN,aAAO;AAAA,QACL,MAAM,UAAU;AAAA,QAChB,OAAO,UAAU;AAAA,QACjB,KAAK,UAAU;AAAA,QACf,OAAO,UAAU;AAAA,MACnB;AACF,UAAM,QAAQ,YAAY,KAAK,MAAM,GAAG;AACxC,WAAO,EAAE,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM;AAAA,EACpF;AACA,SAAO;AACT;AAOA,SAAS,QAAQ,KAA4C,KAAuB;AAClF,SAAO,CAAC,GAAI,IAAI,SAAS,CAAC,MAAM,IAAI,MAAM,IAAI,CAAC,GAAI,QAAQ,KAAK,IAAI;AACtE;AAMA,IAAM,cAAc;AAMpB,IAAM,qBAAqB;AAG3B,IAAM,UAAU,CAAC,MAAc,SAAiB;AAC9C,QAAM,OAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AACtC,SAAO;AAAA,IACL;AAAA,IACA,SAAS,QAAQ,QAAQ,CAAC,aAAa,QAAQ,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,IAAI,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC;AAAA,EAClG;AACF;AAGA,SAAS,gBACP,KACA,MACA,QACU;AACV,QAAM,QAAQ,YAAY,KAAK,MAAM;AACrC,QAAM,QAAQ,CAAC,OAAO,QAAQ,UAAU,MAAM,MAAM,GAAG,MAAM,IAAI,IAAI,UAAU,IAAI,KAAK;AACxF,QAAM,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,UAAU,KAAK,OAAO,MAAM,UAAU,IAAI;AAC7E,SAAO;AACT;AAEA,SAAS,cACP,KACA,OACA,MACA;AACA,QAAM,OAAO,CAAC,OAAO,QAAQ,UAAU,MAAM,MAAM,GAAG,MAAM,IAAI,IAAI,UAAU,IAAI,KAAK;AACvF,OAAK,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,UAAU,KAAK,OAAO,MAAM,UAAU,IAAI;AAC5E,aAAW,KAAK,IAAI;AAClB,SAAK,KAAK,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,GAAG,EAAE,UAAU,IAAI,EAAE,OAAO,KAAK,EAAE,EAAE;AACzE,SAAO;AACT;AAEO,SAAS,aAAa,KAAkB,OAAc,MAA2B;AACtF,QAAM,OAAO,CAAC,MAAM,aAAa,SAAS,QAAQ;AAClD,MAAI,IAAI,SAAS,aAAa;AAC5B,UAAM,OAAO,cAAc,KAAK,OAAO,IAAI;AAC3C,SAAK,OAAO,GAAG,GAAG,IAAI;AACtB,QAAI,MAAM,MAAO,MAAK,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,UAAU,KAAK,EAAE;AACpE,SAAK,KAAK,MAAM,cAAc,UAAU,KAAK,IAAI,MAAM,2BAA2B;AAClF,SAAK,KAAK,GAAG,IAAI,SAAS,IAAI,OAAO,WAAW,GAAG,MAAM,UAAU,IAAI;AACvE,WAAO,EAAE,SAAS,IAAI,QAAQ,MAAM,KAAK,CAAC,GAAG,MAAM,cAAc,KAAK,IAAI,EAAE;AAAA,EAC9E;AACA,MAAI,IAAI,SAAS,OAAO;AAEtB,UAAM,QAAQ,YAAY,GAAG;AAC7B,QAAI,IAAI,WAAW;AACjB,YAAM,IAAI,IAAI;AACd,YAAM,QAAQ,gBAAgB,KAAK,IAAI;AACvC,YAAM,OAAO,GAAG,GAAG,IAAI;AACvB,YAAM,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,UAAU,KAAK,EAAE;AACpD,YAAM,KAAK,MAAM,cAAc,UAAU,KAAK,IAAI,MAAM,2BAA2B;AACnF,YAAM,KAAK,GAAG,EAAE,SAAS,EAAE,OAAO,WAAW,GAAG,MAAM,UAAU,IAAI;AACpE,YAAMA,UAAS,YAAY,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE,MAAM,IAAI,MAAM,IAAI,EAAE,EAAE,KAAK,GAAG,CAAC;AACzF,aAAO;AAAA,QACL,GAAG,OAAO,IAAI,MAAMA,OAAM;AAAA,QAC1B,KAAK,CAAC;AAAA,QACN,MAAM,OAAO,IAAI,MAAM,GAAG,EAAE,MAAM,UAAU,QAAQ,IAAI,CAAC,EAAE;AAAA,MAC7D;AAAA,IACF;AACA,UAAM,SAAS,IAAI,SAAS,GAAG,IAAI,MAAM,IAAI;AAC7C,UAAM,OAAO,cAAc,GAAG,MAAM,KAAK,CAAC;AAC1C,UAAM,QAAQ,YAAY,GAAG,MAAM,KAAK,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,gBAAgB,IAAI,IAAI,MAAM,IAAI,CAAC,GAAG,MAAM,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,GAAG,CAAC;AAC1I,UAAM,SAAS,CAAC,eAAe,GAAI,IAAI,SAAS,CAAC,IAAI,CAAC,kBAAkB,GAAI,KAAK,EAAE,KAAK,IAAI;AAC5F,WAAO,EAAE,GAAG,OAAO,IAAI,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE;AAAA,EAChD;AACA,MAAI,IAAI,SAAS,OAAO;AAEtB,UAAM,SAAS,YAAY,KAAK,KAAK;AACrC,UAAM,SAAS,IAAI,SAAS,QAAQ,IAAI,MAAM,IAAI;AAClD,UAAM,OAAO,cAAc,QAAQ,OAAO,KAAK,CAAC;AAChD,UAAM,QAAQ,YAAY,IAAI,IAAI,MAAM,IAAI,CAAC,GAAG,MAAM,OAAO,IAAI,EAAE,IAAI,OAAO,EAAE,KAAK,GAAG,CAAC;AACzF,UAAM,SAAS,CAAC,aAAa,GAAI,IAAI,SAAS,CAAC,IAAI,CAAC,kBAAkB,GAAI,KAAK,EAAE,KAAK,IAAI;AAC1F,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,CAAC,GAAG,QAAQ,KAAK,OAAO,IAAI,GAAG,MAAM,MAAM,MAAM;AAAA,MACvD,KAAK,CAAC;AAAA,IACR;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;AAAA,IAC1B,KAAK,EAAE,YAAY,MAAM,OAAO,yBAAyB,IAAI;AAAA,IAC7D,KAAK,MAAM;AAAA,EACb;AACF;AAoDA,IAAM,eAAqD;AAAA,EACzD,CAAC,WAAW,iBAAiB;AAAA,EAC7B,CAAC,gBAAgB,sBAAsB;AAAA,EACvC,CAAC,kBAAkB,wBAAwB;AAAA,EAC3C,CAAC,kBAAkB,wBAAwB;AAAA,EAC3C,CAAC,kBAAkB,wBAAwB;AAAA,EAC3C,CAAC,gBAAgB,sBAAsB;AACzC;AAGA,IAAM,gBAAgB;AACtB,IAAM,aAAa,CAAC,MAAc,MAAM,MAAM,CAAC,UAAU,KAAK,CAAC;AAGxD,SAAS,YAAY,QAG1B;AACA,QAAM,QAAiC,CAAC;AACxC,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,EAAG,EAAC,OAAO,KAAK,CAAC,IAAI,SAAS,OAAO,CAAC,IAAI;AACpF,SAAO,EAAE,OAAO,OAAO;AACzB;AAGA,SAAS,OACP,UACA,QACA,MACA,QACA;AACA,QAAM,OAAO,KAAK,UAAU,kBAAkB;AAE9C,QAAM,SAAS,OAAO,cAAc,SAAY,OAAO;AACvD,QAAM,UAAU,CAAC,IAAI,QAAQ,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,cAAc,KAAK,CAAC,CAAC,GAAG,YAAY;AAC9F,QAAM,UAAU,CAAC,IAAI,QAAQ,SAAS,CAAC,GAAG,OAAO,UAAU,GAAG,IAAI;AAClE,QAAM,MAA8B;AAAA,IAClC,0BAA0B,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,EAAE,KAAK,GAAG;AAAA,IACxD,2BAA2B,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,EAAE,KAAK,GAAG;AAAA,IACzD,YAAY,KAAK,OAAO,YAAY,KAAK,QAAQ,OAAO,SAAS,IAAI,QAAQ,cAAc;AAAA,IAC3F,+BAA+B;AAAA,IAC/B,qBAAqB;AAAA,EACvB;AACA,MAAI,OAAO,YAAa,KAAI,iBAAiB,KAAK,QAAQ,aAAa;AAAA,WAC9D,OAAO,UAAW,KAAI,iBAAiB,KAAK,MAAM,aAAa;AAIxE,MAAI,QAAQ,SAAS;AACnB,UAAM,OAAO,CAAC,OAA6B,QACzC,CAAC,GAAG,oBAAI,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG;AACnE,eAAW,CAAC,QAAQ,QAAQ,KAAK;AAC/B,UAAI,QAAQ,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG,KAAK,MAAM,MAAM,CAAC;AACjE,QAAI,uBAAuB,KAAK,OAAO,QAAQ,cAAc,KAAK,UAAU,cAAc,CAAC;AAC3F,UAAMC,YAAW,OAAO,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,cAAc,KAAK,CAAC,CAAC;AAC9E,QAAI,uBAAuB;AAAA,MACzB,GAAG,oBAAI,IAAI,CAAC,GAAIA,SAAQ,SAASA,WAAU,CAAC,iBAAiB,GAAI,eAAe,CAAC;AAAA,IACnF,EAAE,KAAK,GAAG;AACV,QAAI,gBAAgB;AAAA,EACtB;AACA,SAAO;AACT;AAeO,SAAS,WACd,KACA,OACA,SACA,MACa;AACb,QAAM,cAAc,IAAI,SAAS;AACjC,QAAM,SAAS,YAAY,KAAK,EAAE,GAAG,OAAO,KAAK,QAAQ,OAAO,CAAC;AACjE,QAAM,OAAO,OAAO;AACpB,QAAM,SAAS,OAAO,OAAO,QAAQ;AACrC,QAAM,WAAW,OAAO;AACxB,QAAM,QAAQ,CAAC,kBAAkB;AACjC,MAAI,QAAQ,UAAW,OAAM,KAAK,MAAM,QAAQ,SAAS;AACzD,QAAM,KAAK,MAAM,IAAI,KAAK,QAAQ,WAAW,CAAC,EAAE;AAChD,MAAI,QAAQ,QAAS,OAAM,KAAK,MAAM,QAAQ;AAC9C,MAAI,QAAQ,MAAO,OAAM,KAAK,SAAS;AACvC,MAAI,QAAQ,MAAO,OAAM,KAAK,yBAAyB,OAAO;AAC9D,QAAM,KAAK,QAAQ,QAAQ;AAC3B,QAAM,MAAM,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;AAEvC,QAAM,IAAI,IAAI,SAAS,SAAS,CAAC,IAAI,YAAY,KAAK;AACtD,QAAM,OAAO,MAAM,IAAI,CAAC,MAAO,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAE,EAAE,KAAK,GAAG;AAC/D,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAQ,OAAO;AACjB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,KAAK,SAAS,OAAO;AAAA,EAC7B;AACA,MAAI,QAAQ,SAAS;AACnB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AACA,UAAM,KAAK,OAAO;AAAA,EACpB;AAEA,QAAM,OAAO,eAAe,MAAM,KAAK,GAAG,CAAC;AAC3C,QAAM,SAAS,MAAM,SAAS,GAAG,IAAI,KAAK,MAAM,KAAK,MAAM,CAAC,OAAO,IAAI,KAAK;AAC5E,QAAM,YAAY,OAAO,UAAU,QAAQ,MAAM,OAAO;AACxD,MAAI,aAAa;AACf,UAAM,OAAO,cAAc,KAAK,OAAO,IAAI;AAC3C,SAAK,KAAK,MAAM,GAAG,QAAQ,MAAM,IAAI,UAAU,GAAG,EAAE;AACpD,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,SAAS,EAAG,MAAK,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE;AAC3E,QAAI,QAAQ,MAAO,MAAK,KAAK,MAAM,oBAAoB;AACvD,QAAI,QAAQ,QAAS,MAAK,KAAK,MAAM,iBAAiB;AACtD,SAAK,KAAK,GAAG,IAAI,SAAS,IAAI,OAAO,MAAM,MAAM,MAAM;AACvD,WAAO,EAAE,SAAS,IAAI,QAAQ,MAAM,KAAK,CAAC,GAAG,MAAM,cAAc,KAAK,IAAI,EAAE;AAAA,EAC9E;AACA,MAAI,IAAI,SAAS,OAAO;AAEtB,UAAM,QAAQ;AAAA,MACZ,GAAI,QAAQ,QAAQ,CAAC,oBAAoB,IAAI,CAAC;AAAA,MAC9C,GAAI,QAAQ,UAAU,CAAC,iBAAiB,IAAI,CAAC;AAAA,IAC/C;AACA,UAAM,QAAQ,MAAM,SAAS,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC;AACvD,QAAI,IAAI,WAAW;AACjB,YAAM,IAAI,IAAI;AACd,YAAM,QAAQ,YAAY,KAAK,QAAQ,MAAM;AAC7C,YAAM,cAAc,gBAAgB,KAAK,MAAM,QAAQ,MAAM;AAC7D,kBAAY,KAAK,MAAM,GAAG,MAAM,GAAG,IAAI,UAAU,GAAG,EAAE;AACtD,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,SAAS,EAAG,aAAY,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE;AAClF,iBAAW,KAAK,MAAO,aAAY,KAAK,MAAM,CAAC;AAC/C,kBAAY,KAAK,GAAG,EAAE,SAAS,EAAE,OAAO,MAAM,MAAM,MAAM;AAC1D,YAAMC,OAAM,QAAQ,EAAE,MAAM,IAAI,YAAY,IAAI,EAAE,EAAE,KAAK,GAAG,CAAC;AAC7D,aAAO;AAAA,QACL,GAAG,OAAO,IAAI,MAAM,CAAC,GAAG,OAAOA,IAAG,EAAE,KAAK,MAAM,CAAC;AAAA,QAChD,KAAK,CAAC;AAAA,QACN,MAAM,OAAO,IAAI,MAAM,GAAG,EAAE,MAAM,UAAU,QAAQ,IAAI,CAAC,EAAE;AAAA,QAC3D,GAAI,MAAM,SAAS,EAAE,MAAM,IAAI,CAAC;AAAA,MAClC;AAAA,IACF;AACA,UAAM,OAAO,OAAO,QAAQ,SAAS,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAEtE,UAAM,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,KAAK,KAAK,GAAG,CAAC,UAAU,QAAQ,MAAM,CAAC,IAAI,QAAQ,IAAI,CAAC;AAClG,WAAO;AAAA,MACL,GAAG,OAAO,IAAI,MAAM,GAAG,aAAa,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,KAAK,MAAM,CAAC,EAAE;AAAA,MACvE,KAAK,CAAC;AAAA,MACN,MAAM,QAAQ,IAAI,MAAM,IAAI;AAAA,MAC5B,GAAI,MAAM,SAAS,EAAE,MAAM,IAAI,CAAC;AAAA,IAClC;AAAA,EACF;AACA,MAAI,IAAI,SAAS,OAAO;AAEtB,UAAM,OAAO;AAAA,MACX,GAAI,QAAQ,QAAQ,CAAC,sBAAsB,IAAI,CAAC;AAAA,MAChD,GAAI,QAAQ,UAAU,CAAC,mBAAmB,IAAI,CAAC;AAAA,IACjD;AACA,UAAM,OAAO,OAAO,QAAQ,SAAS,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE;AAClE,WAAO;AAAA,MACL,SAAS;AAAA;AAAA,MAET,MAAM,CAAC,GAAG,QAAQ,KAAK,IAAI,GAAG,OAAO,GAAG,MAAM,MAAM,MAAM,GAAG,WAAW,KAAK,MAAM,IAAI,IAAI;AAAA,MAC3F,KAAK,KAAK,SAAS,EAAE,QAAQ,KAAK,KAAK,GAAG,EAAE,IAAI,CAAC;AAAA,MACjD,MAAM,QAAQ,KAAK,IAAI;AAAA,IACzB;AAAA,EACF;AACA,SAAO,EAAE,SAAS,MAAM,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,WAAW,KAAK,MAAM,KAAK;AAChF;",
|
|
6
|
+
"names": ["script", "enabled", "run"]
|
|
7
7
|
}
|
package/dist/scenario/live.js
CHANGED
|
@@ -4,17 +4,19 @@ import {
|
|
|
4
4
|
scenarioHash,
|
|
5
5
|
simulatedEnds,
|
|
6
6
|
storedVerdict
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
-
import "../chunks/chunk-
|
|
9
|
-
import "../chunks/chunk-23ISDYUS.js";
|
|
7
|
+
} from "../chunks/chunk-J5LYSQ3L.js";
|
|
8
|
+
import "../chunks/chunk-BSX6G7QY.js";
|
|
10
9
|
import "../chunks/chunk-TH6ICGA5.js";
|
|
10
|
+
import "../chunks/chunk-23ISDYUS.js";
|
|
11
11
|
import "../chunks/chunk-KOG6OURH.js";
|
|
12
|
-
import "../chunks/chunk-
|
|
12
|
+
import "../chunks/chunk-WTVGCMGV.js";
|
|
13
13
|
import "../chunks/chunk-OEEHAY5X.js";
|
|
14
14
|
import "../chunks/chunk-LPBLGBDT.js";
|
|
15
|
-
import "../chunks/chunk-
|
|
15
|
+
import "../chunks/chunk-XJAMBKE3.js";
|
|
16
|
+
import "../chunks/chunk-OJZSZBHW.js";
|
|
16
17
|
import "../chunks/chunk-ARA3VJR2.js";
|
|
17
18
|
import "../chunks/chunk-56VTJ6YF.js";
|
|
19
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
18
20
|
import "../chunks/chunk-BAZIS67B.js";
|
|
19
21
|
import "../chunks/chunk-X3DEH47B.js";
|
|
20
22
|
import "../chunks/chunk-TOTSB4HG.js";
|
|
@@ -2,16 +2,18 @@ import {
|
|
|
2
2
|
prepare,
|
|
3
3
|
simulateRun,
|
|
4
4
|
simulateScenario
|
|
5
|
-
} from "../chunks/chunk-
|
|
6
|
-
import "../chunks/chunk-23ISDYUS.js";
|
|
5
|
+
} from "../chunks/chunk-BSX6G7QY.js";
|
|
7
6
|
import "../chunks/chunk-TH6ICGA5.js";
|
|
7
|
+
import "../chunks/chunk-23ISDYUS.js";
|
|
8
8
|
import "../chunks/chunk-KOG6OURH.js";
|
|
9
|
-
import "../chunks/chunk-
|
|
9
|
+
import "../chunks/chunk-WTVGCMGV.js";
|
|
10
10
|
import "../chunks/chunk-OEEHAY5X.js";
|
|
11
11
|
import "../chunks/chunk-LPBLGBDT.js";
|
|
12
|
-
import "../chunks/chunk-
|
|
12
|
+
import "../chunks/chunk-XJAMBKE3.js";
|
|
13
|
+
import "../chunks/chunk-OJZSZBHW.js";
|
|
13
14
|
import "../chunks/chunk-ARA3VJR2.js";
|
|
14
15
|
import "../chunks/chunk-56VTJ6YF.js";
|
|
16
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
15
17
|
import "../chunks/chunk-BAZIS67B.js";
|
|
16
18
|
import "../chunks/chunk-X3DEH47B.js";
|
|
17
19
|
import "../chunks/chunk-TOTSB4HG.js";
|
package/dist/view/flowFacts.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
planGenerated
|
|
3
|
-
} from "../chunks/chunk-
|
|
4
|
-
import "../chunks/chunk-
|
|
5
|
-
import "../chunks/chunk-
|
|
6
|
-
import "../chunks/chunk-
|
|
3
|
+
} from "../chunks/chunk-7ALTNZCI.js";
|
|
4
|
+
import "../chunks/chunk-CCWUUVSG.js";
|
|
5
|
+
import "../chunks/chunk-APBEHKCF.js";
|
|
6
|
+
import "../chunks/chunk-WTVGCMGV.js";
|
|
7
7
|
import "../chunks/chunk-OEEHAY5X.js";
|
|
8
8
|
import "../chunks/chunk-LPBLGBDT.js";
|
|
9
|
-
import "../chunks/chunk-
|
|
9
|
+
import "../chunks/chunk-XJAMBKE3.js";
|
|
10
|
+
import "../chunks/chunk-OJZSZBHW.js";
|
|
10
11
|
import "../chunks/chunk-ARA3VJR2.js";
|
|
11
12
|
import "../chunks/chunk-56VTJ6YF.js";
|
|
13
|
+
import "../chunks/chunk-LNFMYJUJ.js";
|
|
12
14
|
import "../chunks/chunk-BAZIS67B.js";
|
|
13
15
|
import "../chunks/chunk-X3DEH47B.js";
|
|
14
16
|
import "../chunks/chunk-TOTSB4HG.js";
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/core/view/flowFacts.ts"],
|
|
4
4
|
"sourcesContent": ["// What the Flows view says about each flow (AFD-86, wave 8 group D): its problems and the state of\n// its generated code, so a repository's health shows without opening every flow (round 1: P16, T7\n// given up). The code state uses the same write plan a save does (ADR-0009), so \"edited by hand\"\n// here is what a save would leave alone. Pure, with the generated folder read through GeneratedDir.\n// AFD-93 (wave 9): each flow's problems with their places, for the Problems panel of flows that are\n// not open, and the workspace's state in a line for the flow panel (round 2: S8, T7 given up).\n\nimport { type GeneratedDir, planGenerated } from '../engine/writePlan';\nimport { parseFlow, rangeOf } from '../flow/document';\nimport type { SchemaValidator } from '../flow/schema';\nimport { type Finding, validateFlow } from '../flow/validate';\n\nexport type CodeState = 'current' | 'out of date' | 'edited by hand' | 'no code yet' | 'blocked';\n\nexport interface FlowFacts {\n name: string;\n key: string;\n errors: number;\n warnings: number;\n code: CodeState;\n /** Generated files edited by hand (a save leaves them alone). */\n kept: string[];\n /** The flow does not parse. */\n broken?: string;\n /** AFD-93: its errors and warnings with their places (validation only: no catalog, no files). */\n problems: FlowProblem[];\n}\n\n/** A line and character, both from 0, as VS Code counts them (UTF-16, like JS strings). */\nexport interface LinePos {\n line: number;\n character: number;\n}\n\nexport interface FlowProblem {\n start: LinePos;\n end: LinePos;\n message: string;\n severity: Finding['severity'];\n code: string;\n}\n\n/** Where an offset of the text is, as a line and character. */\nexport function lineCol(text: string, offset: number): LinePos {\n const at = Math.max(0, Math.min(offset, text.length));\n const before = text.lastIndexOf('\\n', at - 1);\n let line = 0;\n for (let i = text.indexOf('\\n'); i !== -1 && i < at; i = text.indexOf('\\n', i + 1)) line++;\n return { line, character: at - before - 1 };\n}\n\nexport async function flowFacts(\n text: string,\n schema: SchemaValidator,\n dir: GeneratedDir,\n options: { source: string; root?: string },\n): Promise<FlowFacts> {\n const parsed = parseFlow(text);\n const doc = parsed.doc;\n if (!doc) {\n const broken = parsed.errors[0]?.message ?? 'The file does not parse';\n const at = lineCol(text, parsed.errors[0]?.offset ?? 0);\n return {\n name: options.source.replace(/\\.flow\\.ya?ml$/, ''),\n key: '',\n errors: 1,\n warnings: 0,\n code: 'blocked',\n kept: [],\n broken,\n problems: [\n {\n start: at,\n end: { line: at.line, character: at.character + 1 },\n message: broken,\n severity: 'error',\n code: 'yaml',\n },\n ],\n };\n }\n const findings = validateFlow(doc, schema(doc)).findings;\n const errors = findings.filter((f) => f.severity === 'error').length;\n const warnings = findings.filter((f) => f.severity === 'warning').length;\n const problems = findings.map((f): FlowProblem => {\n const [start, end] = rangeOf(parsed.file, f.path);\n return {\n start: lineCol(text, start),\n end: lineCol(text, end),\n message: f.message,\n severity: f.severity,\n code: f.code,\n };\n });\n const base = { name: doc.flow.name, key: doc.flow.key, errors, warnings, problems };\n if (errors > 0) return { ...base, code: 'blocked', kept: [] };\n const plan = await planGenerated(text, schema, dir, options);\n if (plan.kept.length > 0) return { ...base, code: 'edited by hand', kept: plan.kept };\n if ((await dir.list()).length === 0) return { ...base, code: 'no code yet', kept: [] };\n const stale = plan.write.length > 0 || plan.remove.length > 0;\n return { ...base, code: stale ? 'out of date' : 'current', kept: [] };\n}\n\n/** The view's description of a flow: problems first, then the code when it needs a look. */\nexport function factsLine(f: FlowFacts): string {\n const n = (count: number, one: string) => `${count} ${one}${count === 1 ? '' : 's'}`;\n const parts = [\n f.broken ? 'does not parse' : f.errors ? n(f.errors, 'error') : '',\n !f.broken && f.warnings ? n(f.warnings, 'warning') : '',\n f.code === 'out of date'\n ? 'code out of date'\n : f.code === 'edited by hand'\n ? 'code edited by hand'\n : f.code === 'no code yet'\n ? 'no code yet'\n : '',\n ].filter(Boolean);\n return parts.join(' \u00B7 ');\n}\n\n/** What each state means, for the view's tooltip (round 1: \"edited by hand\" was not understood). */\nexport const CODE_MEANING: Record<CodeState, string> = {\n current: 'The generated playbooks match the flow.',\n 'out of date':\n 'The generated playbooks do not match the flow yet: saving the flow (or Generate Code) writes them.',\n 'edited by hand':\n 'A generated playbook was changed in a text editor, so saving the flow leaves it alone. Generate Code asks before it writes over the change.',\n 'no code yet': 'No playbook was generated for this flow yet: saving it writes them.',\n blocked: 'The flow has errors, so no code is generated until they are fixed.',\n};\n\n/** A folder of the Flows view: its subfolders and the flows in it. */\nexport interface FlowFolder {\n name: string;\n /** Path relative to the workspace folder, `/`-separated; empty at the top. */\n path: string;\n folders: FlowFolder[];\n /** Relative paths of the flow files. */\n flows: string[];\n}\n\n/**\n * The flows by folder. A folder that only holds its own flow (`flows/hello/hello.flow.yaml`, the\n * New Flow layout) does not make a level of its own: the flow sits in the folder above.\n */\nexport function flowTree(paths: readonly string[]): FlowFolder {\n const root: FlowFolder = { name: '', path: '', folders: [], flows: [] };\n for (const path of [...paths].sort((a, b) => a.localeCompare(b))) {\n const parts = path.split('/');\n const file = parts.pop() ?? path;\n const key = file.replace(/\\.flow\\.ya?ml$/, '');\n if (parts.at(-1) === key) parts.pop();\n let at = root;\n for (const name of parts) {\n let next = at.folders.find((f) => f.name === name);\n if (!next) {\n next = { name, path: at.path ? `${at.path}/${name}` : name, folders: [], flows: [] };\n at.folders.push(next);\n }\n at = next;\n }\n at.flows.push(path);\n }\n return root;\n}\n\n/** AFD-93: the workspace's flows at a glance, for the flow panel. */\nexport interface RepoState {\n /** Flows found in the workspace. */\n flows: number;\n withErrors: number;\n editedByHand: number;\n outOfDate: number;\n}\n\nexport function repoState(all: readonly FlowFacts[], flows = all.length): RepoState {\n return {\n flows,\n withErrors: all.filter((f) => f.broken || f.errors > 0).length,\n editedByHand: all.filter((f) => f.code === 'edited by hand').length,\n outOfDate: all.filter((f) => f.code === 'out of date').length,\n };\n}\n\n/** Some flow needs a look: errors, or generated code changed by hand (out of date is routine). */\nexport const needsLook = (s: RepoState) => s.withErrors + s.editedByHand > 0;\n\n/** \"In this workspace: 1 flow with errors, 1 with code edited by hand\", or that all is well. */\nexport function repoLine(s: RepoState): string {\n const parts: string[] = [];\n const add = (count: number, what: string) => {\n if (!count) return;\n const noun = parts.length ? '' : count === 1 ? 'flow ' : 'flows ';\n parts.push(`${count} ${noun}${what}`);\n };\n add(s.withErrors, 'with errors');\n add(s.editedByHand, 'with code edited by hand');\n add(s.outOfDate, 'with code out of date');\n if (parts.length) return `In this workspace: ${parts.join(', ')}`;\n return s.flows > 1\n ? 'Other flows of this workspace have no problems'\n : 'No other flows in this workspace';\n}\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
scanJinja
|
|
3
|
+
} from "../chunks/chunk-FIVVDND6.js";
|
|
1
4
|
import {
|
|
2
5
|
CONSTANTS,
|
|
3
6
|
FIELD_TYPES,
|
|
@@ -14,9 +17,6 @@ import {
|
|
|
14
17
|
TESTS,
|
|
15
18
|
strftime
|
|
16
19
|
} from "../chunks/chunk-S2ZRU4A6.js";
|
|
17
|
-
import {
|
|
18
|
-
scanJinja
|
|
19
|
-
} from "../chunks/chunk-FIVVDND6.js";
|
|
20
20
|
|
|
21
21
|
// src/core/view/jinjaComplete.ts
|
|
22
22
|
var IDENT_KINDS = /* @__PURE__ */ new Set([
|
package/dist/view/route.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface Route {
|
|
|
14
14
|
/** A route round boxes: its corners between the two ends (draw.io waypoints). */
|
|
15
15
|
bends?: Position[];
|
|
16
16
|
}
|
|
17
|
+
/** AFD-294: how a wire is drawn: stepped (right angles, small round corners) or curved. */
|
|
18
|
+
export type WireStyle = 'stepped' | 'curved';
|
|
17
19
|
/** A wire that only grazes a box edge is not through it: boxes shrink by this much first. */
|
|
18
20
|
export declare const INSET = 2;
|
|
19
21
|
/** The corners a stepped path passes: its M, L and Q points in order (Q's control is a corner). */
|
|
@@ -31,4 +33,4 @@ export declare function labelBox(text: string, at: Position): Box;
|
|
|
31
33
|
* The wire from `a` (leaving by side `from`) to `b` (entered by side `to`) among the node boxes of
|
|
32
34
|
* its level, its own two included. `label` is the text it shows, kept off the boxes on a route.
|
|
33
35
|
*/
|
|
34
|
-
export declare function routeWire(a: Position, from: Side, b: Position, to: Side, boxes: readonly Box[], label?: string): Route;
|
|
36
|
+
export declare function routeWire(a: Position, from: Side, b: Position, to: Side, boxes: readonly Box[], label?: string, style?: WireStyle): Route;
|
package/dist/view/route.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ansible-flow/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.0",
|
|
4
4
|
"description": "Ansible Flow Designer core: the flow model, commands, validation and playbook generation, for any JavaScript host.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/ChistokhinSV/ansible-flow-designer/blob/main/docs/packages.md",
|