@intentius/chant-lexicon-fly 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/capability-plugin.d.ts +6 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/run-agent.d.ts +92 -0
- package/dist/components/run-agent.d.ts.map +1 -0
- package/dist/composites/fly-deploy.d.ts +4 -4
- package/dist/composites/fly-deploy.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/builders.d.ts +73 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/package.json +7 -2
- package/src/components/capability-plugin.test.ts +30 -0
- package/src/components/capability-plugin.ts +36 -0
- package/src/components/index.ts +14 -0
- package/src/components/run-agent-conformance.test.ts +352 -0
- package/src/components/run-agent.test.ts +302 -0
- package/src/components/run-agent.ts +139 -0
- package/src/composites/fly-deploy.ts +4 -4
- package/src/index.ts +16 -5
- package/src/op/builders.test.ts +73 -0
- package/src/op/builders.ts +102 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `run-agent`'s fly-lexicon adapter (#1942, epic #1564 phase 2) — the real
|
|
3
|
+
* `SpriteActivities` implementation
|
|
4
|
+
* (`@intentius/chant/components/verbs/run-agent`) over this lexicon's own
|
|
5
|
+
* sprite lifecycle activities (`../op/activities/sprites.ts` +
|
|
6
|
+
* `../op/activities/sprite-fs.ts`), and the `run-agent` capability built over
|
|
7
|
+
* it. Registered through this lexicon's own `CapabilityPlugin`
|
|
8
|
+
* (`./capability-plugin.ts`) the same way aws contributes `cfn-deploy` and
|
|
9
|
+
* helm contributes `helm-upgrade` (docs/components/cloud-boundary) — core's
|
|
10
|
+
* `createRunAgentCapability` (the sequencing logic: create-or-reuse,
|
|
11
|
+
* checkpoint, stage, exec, collect, destroy/leave-alive, restore-by-comment)
|
|
12
|
+
* stays cloud-agnostic in `@intentius/chant`, structurally independent of
|
|
13
|
+
* this package; this module is the one piece with the hard dependency on the
|
|
14
|
+
* real sprite wire protocol.
|
|
15
|
+
*
|
|
16
|
+
* **The exec-throw finding (pre-merge review of #1946, recorded on #1942).**
|
|
17
|
+
* The real `spriteExec` (`../op/activities/sprites.ts`) throws on any
|
|
18
|
+
* non-zero exit — by design, so a *scripted Op phase*
|
|
19
|
+
* (`examples/sprites-agent-task/ops/guarded-task.op.ts`) fails and triggers
|
|
20
|
+
* its `onFailure` compensation. But `run-agent`'s `RunAgentOutput.turn.status`
|
|
21
|
+
* includes `"failed"` as a first-class, non-throwing result — an ordinary
|
|
22
|
+
* failed agent turn (the model's diff didn't compile, its tests failed,
|
|
23
|
+
* whatever the exit code means) is not an infrastructure failure and should
|
|
24
|
+
* not by itself unwind the saga (checkpoint restore is for "the sprite
|
|
25
|
+
* backend broke," not "the agent's output wasn't good"). Resolved here as
|
|
26
|
+
* **option (a)** from the review comment: `exec()` below wraps the real
|
|
27
|
+
* `spriteExec` in a try/catch and reclassifies a thrown non-zero-exit error
|
|
28
|
+
* back into a resolved `{ stdout, stderr, exitCode }`
|
|
29
|
+
* (`parseSpriteExecFailure`), so `SpriteActivities.exec` always resolves for
|
|
30
|
+
* an ordinary command outcome — exactly the contract core's `run()`
|
|
31
|
+
* (`packages/core/src/components/verbs/run-agent.ts`) assumes and relies on
|
|
32
|
+
* (it deliberately has *no* try/catch of its own around `sprites.exec`). A
|
|
33
|
+
* genuine transport/infra failure — the WebSocket erroring, connection
|
|
34
|
+
* refused, an aborted signal — does not match the reclassification pattern
|
|
35
|
+
* and still rejects, so core's saga-unwind path is preserved for *real*
|
|
36
|
+
* failures.
|
|
37
|
+
*
|
|
38
|
+
* Option (b) — accept that ordinary failures throw, and drop `"failed"` from
|
|
39
|
+
* `turn.status`'s reachable states — was rejected: it would make every
|
|
40
|
+
* failed agent turn indistinguishable from a genuine sprite outage, forcing
|
|
41
|
+
* a checkpoint-restore rollback for what is often just an unsuccessful
|
|
42
|
+
* attempt, which is not what "the environment is the transaction" is meant
|
|
43
|
+
* to protect against, and it would leave `RunAgentOutput.turn.status:
|
|
44
|
+
* "failed"` a dead, unreachable branch of a type #1941 deliberately shipped
|
|
45
|
+
* as reachable.
|
|
46
|
+
*
|
|
47
|
+
* **Fidelity note.** The real `spriteExec`'s thrown message carries only
|
|
48
|
+
* `stderr || stdout` combined (see its own doc comment in `sprites.ts`), not
|
|
49
|
+
* both streams separately — the reclassified result therefore folds that
|
|
50
|
+
* combined text into `stderr` and leaves `stdout` empty on the failure path.
|
|
51
|
+
* This is a known, documented loss versus a real non-throwing exec; recovering
|
|
52
|
+
* full stream fidelity would mean reimplementing the WebSocket exec framing
|
|
53
|
+
* here rather than reusing `spriteExec`, which is out of this issue's scope
|
|
54
|
+
* (core's module doc calls adapting the existing activities "a thin wrapper,
|
|
55
|
+
* not a rewrite").
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
import type { Capability } from "@intentius/chant/components/capability";
|
|
59
|
+
import {
|
|
60
|
+
createRunAgentCapability,
|
|
61
|
+
type RunAgentInput,
|
|
62
|
+
type RunAgentOutput,
|
|
63
|
+
type SpriteActivities,
|
|
64
|
+
} from "@intentius/chant/components/verbs/run-agent";
|
|
65
|
+
import { spriteCreate, spriteCheckpoint, spriteExec, spriteRestore, spriteDestroy } from "../op/activities/sprites";
|
|
66
|
+
import { spriteWriteFile, spriteReadFile } from "../op/activities/sprite-fs";
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parse the exit code + combined output text out of the real `spriteExec`'s
|
|
70
|
+
* thrown message shape: `sprite <id> exec "<cmd>" exited <code>: <text>`
|
|
71
|
+
* (see `../op/activities/sprites.ts`'s `spriteExec`). Returns `undefined` for
|
|
72
|
+
* any other error shape — a genuine transport/infra failure the caller
|
|
73
|
+
* should let propagate. Exported for direct unit testing of the
|
|
74
|
+
* reclassification the module doc above describes as option (a).
|
|
75
|
+
*
|
|
76
|
+
* The leading `[\s\S]*` is greedy on purpose: `spriteExec`'s message echoes
|
|
77
|
+
* the raw `cmd` verbatim before the real ` exited <code>: ` marker
|
|
78
|
+
* (`exec "<cmd>" exited ...`), so a crafted command whose text itself
|
|
79
|
+
* contains that exact substring must not be mistaken for the marker. A
|
|
80
|
+
* greedy prefix backtracks from the end of the string, so it always anchors
|
|
81
|
+
* to the *last* occurrence — the genuine marker `spriteExec` appended — never
|
|
82
|
+
* a leftmost false match inside the echoed `cmd`.
|
|
83
|
+
*/
|
|
84
|
+
export function parseSpriteExecFailure(err: unknown): { exitCode: number; output: string } | undefined {
|
|
85
|
+
if (!(err instanceof Error)) return undefined;
|
|
86
|
+
const m = err.message.match(/^[\s\S]* exited (\d+): ([\s\S]*)$/);
|
|
87
|
+
if (!m) return undefined;
|
|
88
|
+
const exitCode = Number(m[1]);
|
|
89
|
+
if (!Number.isFinite(exitCode)) return undefined;
|
|
90
|
+
return { exitCode, output: m[2] };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The real `SpriteActivities` implementation: a thin wrapper over this
|
|
95
|
+
* lexicon's own sprite lifecycle + filesystem activities, matching
|
|
96
|
+
* `@intentius/chant/components/verbs/run-agent`'s injectable seam exactly
|
|
97
|
+
* (see that module's doc comment — "adapting them is a thin wrapper, not a
|
|
98
|
+
* rewrite"). `exec()` is the one method that is not a bare pass-through — see
|
|
99
|
+
* this module's doc comment for why.
|
|
100
|
+
*/
|
|
101
|
+
export function createFlySpriteActivities(): SpriteActivities {
|
|
102
|
+
return {
|
|
103
|
+
async create(args, signal) {
|
|
104
|
+
return spriteCreate({ name: args.name, image: args.image }, signal);
|
|
105
|
+
},
|
|
106
|
+
async checkpoint(args, signal) {
|
|
107
|
+
return spriteCheckpoint({ id: args.id, comment: args.comment }, signal);
|
|
108
|
+
},
|
|
109
|
+
async exec(args, signal) {
|
|
110
|
+
try {
|
|
111
|
+
return await spriteExec({ id: args.id, cmd: args.cmd, timeoutMs: args.timeoutMs }, signal);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
const parsed = parseSpriteExecFailure(err);
|
|
114
|
+
if (!parsed) throw err; // a genuine transport/infra failure — propagate it.
|
|
115
|
+
return { stdout: "", stderr: parsed.output, exitCode: parsed.exitCode };
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
async restore(args, signal) {
|
|
119
|
+
await spriteRestore({ id: args.id, checkpoint: args.checkpoint, comment: args.comment }, signal);
|
|
120
|
+
},
|
|
121
|
+
async destroy(args, signal) {
|
|
122
|
+
await spriteDestroy({ id: args.id }, signal);
|
|
123
|
+
},
|
|
124
|
+
async writeFile(args, signal) {
|
|
125
|
+
await spriteWriteFile({ id: args.id, path: args.path, content: args.content, mkdir: args.mkdir }, signal);
|
|
126
|
+
},
|
|
127
|
+
async readFile(args, signal) {
|
|
128
|
+
return spriteReadFile({ id: args.id, path: args.path }, signal);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Build the `run-agent` capability over the real fly sprite backend. */
|
|
134
|
+
export function createFlyRunAgentCapability(): Capability<RunAgentInput, RunAgentOutput> {
|
|
135
|
+
return createRunAgentCapability(createFlySpriteActivities());
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Default `run-agent` capability, backed by the real `SpriteActivities` adapter above — what `flyCapabilityPlugin` (./capability-plugin.ts) registers. */
|
|
139
|
+
export const flyRunAgentCapability: Capability<RunAgentInput, RunAgentOutput> = createFlyRunAgentCapability();
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import { Op, phase, build, activity, httpCheck } from "@intentius/chant/op";
|
|
27
27
|
import type { OpResource } from "@intentius/chant/op";
|
|
28
|
-
import type { ActivityStep } from "@intentius/chant/op";
|
|
28
|
+
import type { ActivityStep, NamedActivityStep } from "@intentius/chant/op";
|
|
29
29
|
|
|
30
30
|
/** The local mudflaps endpoint the deploy Op targets by default. */
|
|
31
31
|
export const LOCAL_FLAPS_ENDPOINT = "http://localhost:4280";
|
|
@@ -52,13 +52,13 @@ export interface FlapsStepOpts {
|
|
|
52
52
|
* `flapsUp` activity (#740). Defaults to the `longInfra` profile (the image may
|
|
53
53
|
* pull); override via `opts.profile`.
|
|
54
54
|
*/
|
|
55
|
-
export const flapsUp = (opts?: FlapsStepOpts):
|
|
55
|
+
export const flapsUp = (opts?: FlapsStepOpts): NamedActivityStep => {
|
|
56
56
|
const { profile, ...args } = opts ?? {};
|
|
57
57
|
return activity("flapsUp", args as Record<string, unknown>, profile ?? "longInfra");
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
/** Stop and remove the local mudflaps container. Resolves to the `flapsDown` activity. Defaults to the `fastIdempotent` profile (override via `opts.profile`). */
|
|
61
|
-
export const flapsDown = (opts?: FlapsStepOpts):
|
|
61
|
+
export const flapsDown = (opts?: FlapsStepOpts): NamedActivityStep => {
|
|
62
62
|
const { profile, ...args } = opts ?? {};
|
|
63
63
|
return activity("flapsDown", args as Record<string, unknown>, profile ?? "fastIdempotent");
|
|
64
64
|
};
|
|
@@ -83,7 +83,7 @@ export interface FlyApplyStepOpts {
|
|
|
83
83
|
* App + Machine, wait each machine to `started`, prune owned-only when asked.
|
|
84
84
|
* Defaults to the `longInfra` profile (override via `opts.profile`).
|
|
85
85
|
*/
|
|
86
|
-
export const flyApplyStep = (planPath: string, opts?: FlyApplyStepOpts):
|
|
86
|
+
export const flyApplyStep = (planPath: string, opts?: FlyApplyStepOpts): NamedActivityStep => {
|
|
87
87
|
const { profile, ...rest } = opts ?? {};
|
|
88
88
|
return activity("flyApply", { planPath, ...(rest as Record<string, unknown>) }, profile ?? "longInfra");
|
|
89
89
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// Plugin
|
|
2
2
|
export { flyPlugin } from "./plugin";
|
|
3
3
|
|
|
4
|
+
// Component/release capabilities — run-agent, the sprite-lifecycle leaf
|
|
5
|
+
// contributed to core's capability-plugin seam (#1942). Core loads
|
|
6
|
+
// `flyCapabilityPlugin` when a project's chant.config lists this lexicon.
|
|
7
|
+
export { flyCapabilityPlugin, FLY_VERB_FAMILIES } from "./components/capability-plugin";
|
|
8
|
+
|
|
4
9
|
// Serializer
|
|
5
10
|
export { flySerializer } from "./serializer";
|
|
6
11
|
|
|
@@ -17,10 +22,16 @@ export { FLY_METADATA_OWNERSHIP_KEYS } from "./ownership";
|
|
|
17
22
|
export { flyDeploy, flapsUp, flapsDown, flyApplyStep, LOCAL_FLAPS_ENDPOINT } from "./composites/fly-deploy";
|
|
18
23
|
export type { FlyDeployOpts, FlyApplyStepOpts, FlapsStepOpts } from "./composites/fly-deploy";
|
|
19
24
|
|
|
20
|
-
// Sprite Op step builders
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
25
|
+
// Sprite Op step builders. chant #1288 Stage 2: these author
|
|
26
|
+
// `activity("spriteCreate", ...)` steps with authoring-time types derived
|
|
27
|
+
// from this lexicon's own `Sprite*Args` interfaces (`./op/builders.ts`),
|
|
28
|
+
// replacing the hand-restated inline types core's same-named builders used
|
|
29
|
+
// to carry — same names, same import path, so an existing
|
|
30
|
+
// `import { spriteCreate } from "@intentius/chant-lexicon-fly"` call site
|
|
31
|
+
// gains real derived types with no change. `loadActivities(["fly"])` binds
|
|
32
|
+
// the `fn` strings to the implementations in `./op/activities/sprites.ts`
|
|
33
|
+
// etc. The `spritesUp`/`spritesDown` builders boot/tear down the spritzer
|
|
34
|
+
// emulator as modeled steps.
|
|
24
35
|
export {
|
|
25
36
|
spriteCreate,
|
|
26
37
|
spriteExec,
|
|
@@ -39,7 +50,7 @@ export {
|
|
|
39
50
|
spriteTaskRelease,
|
|
40
51
|
spritesUp,
|
|
41
52
|
spritesDown,
|
|
42
|
-
} from "
|
|
53
|
+
} from "./op/builders";
|
|
43
54
|
|
|
44
55
|
// Generated resources — export everything from generated index.
|
|
45
56
|
// Provides `App`, `Machine`, `Volume`, and the property types
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed step-builder wrappers (chant #1288 Stage 2) — see
|
|
3
|
+
* `lexicons/k8s/src/op/builders.test.ts`'s module doc for what's asserted
|
|
4
|
+
* and why. Unlike the positional-arg lexicons, the sprite family takes one
|
|
5
|
+
* whole args object (matching core's original inline-typed signature), so
|
|
6
|
+
* only `profile` is extracted from that object — `id` is left alone
|
|
7
|
+
* (verified below): it's a required DOMAIN field on most of these (the
|
|
8
|
+
* target sprite), not step-authoring sugar, so `.out`-by-id is out of scope
|
|
9
|
+
* here (see `./builders.ts`'s module doc).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, test, expect } from "vitest";
|
|
13
|
+
import {
|
|
14
|
+
spriteCreate as spriteCreateOld,
|
|
15
|
+
spriteExec as spriteExecOld,
|
|
16
|
+
spriteWriteFile as spriteWriteFileOld,
|
|
17
|
+
spritesUp as spritesUpOld,
|
|
18
|
+
spritesDown as spritesDownOld,
|
|
19
|
+
stepOutput,
|
|
20
|
+
} from "@intentius/chant/op";
|
|
21
|
+
import { spriteCreate, spriteExec, spriteWriteFile, spritesUp, spritesDown } from "./builders";
|
|
22
|
+
|
|
23
|
+
describe("fly typed sprite step builders (#1288 Stage 2)", () => {
|
|
24
|
+
test("spriteCreate: identical ActivityStep to core's original", () => {
|
|
25
|
+
expect(spriteCreate({ name: "sandbox" })).toEqual(spriteCreateOld({ name: "sandbox" }));
|
|
26
|
+
const args = { name: "sandbox", image: "custom:latest", size: "shared-cpu-1x" };
|
|
27
|
+
expect(spriteCreate(args)).toEqual(spriteCreateOld(args));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("spriteExec: identical ActivityStep to core's original", () => {
|
|
31
|
+
const args = { id: "sandbox", cmd: "npm test", timeoutMs: 60_000 };
|
|
32
|
+
expect(spriteExec(args)).toEqual(spriteExecOld(args));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("spriteWriteFile: identical ActivityStep to core's original", () => {
|
|
36
|
+
const args = { id: "sandbox", path: "/app/config.json", content: "{}" };
|
|
37
|
+
expect(spriteWriteFile(args)).toEqual(spriteWriteFileOld(args));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("spritesUp/spritesDown: identical ActivityStep to core's original, including the no-arg default", () => {
|
|
41
|
+
expect(spritesUp()).toEqual(spritesUpOld());
|
|
42
|
+
expect(spritesUp({ port: 4291 })).toEqual(spritesUpOld({ port: 4291 }));
|
|
43
|
+
expect(spritesDown()).toEqual(spritesDownOld());
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("spriteCreate: accepts a StepOutputRef in a typed slot", () => {
|
|
47
|
+
const ref = stepOutput("resolve-image", "image");
|
|
48
|
+
const step = spriteCreate({ name: "sandbox", image: ref });
|
|
49
|
+
expect(step.args?.image).toBe(ref);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("spriteExec: `id` (the target sprite, a domain field) lands in args, not the step's own id", () => {
|
|
53
|
+
const step = spriteExec({ id: "sandbox", cmd: "npm test" });
|
|
54
|
+
expect(step.args?.id).toBe("sandbox");
|
|
55
|
+
expect(step.id).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// ── Compile-time-only: authoring-time type errors (never executed) ──────────
|
|
60
|
+
function _typeChecksOnly(): void {
|
|
61
|
+
// @ts-expect-error — name is required (the activity fails without it).
|
|
62
|
+
spriteCreate({});
|
|
63
|
+
|
|
64
|
+
// @ts-expect-error — "sandbox_id" is not a key of SpriteExecArgs (the field is `id`).
|
|
65
|
+
spriteExec({ sandbox_id: "sandbox", cmd: "npm test" });
|
|
66
|
+
|
|
67
|
+
// @ts-expect-error — timeoutMs must be a number.
|
|
68
|
+
spriteExec({ id: "sandbox", cmd: "npm test", timeoutMs: "60000" });
|
|
69
|
+
|
|
70
|
+
// @ts-expect-error — spritesUp's port must be a number.
|
|
71
|
+
spritesUp({ port: "4290" });
|
|
72
|
+
}
|
|
73
|
+
void _typeChecksOnly;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed step-builder wrappers for this lexicon's sprite activities (chant
|
|
3
|
+
* #1288 Stage 2 — "regenerate the step builders as fully typed wrappers").
|
|
4
|
+
* Core's own sprite builders (`spriteCreate`, `spriteExec`, ...) already
|
|
5
|
+
* carry an inline object-literal type in `packages/core/src/op/builders.ts`
|
|
6
|
+
* — but that inline type is a hand-restated MIRROR of this lexicon's own
|
|
7
|
+
* `Sprite*Args` interfaces (`./activities/sprites.ts`,
|
|
8
|
+
* `./activities/sprite-fs.ts`, `./activities/sprite-tasks.ts`,
|
|
9
|
+
* `./activities/sprite-config.ts`, `./activities/sprites-emulator.ts`),
|
|
10
|
+
* exactly the duplication Stage 2 exists to eliminate. `opts`'s type in
|
|
11
|
+
* every wrapper below IS the activity's own `*Args` interface (via
|
|
12
|
+
* `WithStepRefs`) — never restated — so it stays in sync with the
|
|
13
|
+
* implementation by construction.
|
|
14
|
+
*
|
|
15
|
+
* There's no cross-package layering problem here (unlike `kubectlApply`/
|
|
16
|
+
* `helmInstall`): this package already owns both the activities and (per
|
|
17
|
+
* `./composites/fly-deploy.ts`'s existing `flapsUp`/`flapsDown`/
|
|
18
|
+
* `flyApplyStep` precedent, #744) the step-builder layer. So — matching how
|
|
19
|
+
* `lexicons/temporal/src/op/builders.ts` handles ITS OWN activities — this
|
|
20
|
+
* module REPLACES (not adds alongside) the sprite builders this package's
|
|
21
|
+
* `src/index.ts` used to re-export from `@intentius/chant/op`: same names,
|
|
22
|
+
* same import path (`@intentius/chant-lexicon-fly`), so an existing
|
|
23
|
+
* `import { spriteCreate } from "@intentius/chant-lexicon-fly"` call site
|
|
24
|
+
* gains authoring-time types and `StepOutputRef`/`.out` support with no
|
|
25
|
+
* change. `core`'s own originals are untouched, for anyone still importing
|
|
26
|
+
* `@intentius/chant/op` directly.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { activity, type NamedActivityStep, type WithStepRefs } from "@intentius/chant/op";
|
|
30
|
+
import type { ActivityStep } from "@intentius/chant/op";
|
|
31
|
+
import type { SpriteCreateArgs, SpriteExecArgs, SpriteCheckpointArgs, SpriteRestoreArgs, ListCheckpointsArgs, SpriteDestroyArgs } from "./activities/sprites";
|
|
32
|
+
import type { SpriteWriteFileArgs, SpriteReadFileArgs, SpriteListDirArgs, SpriteRemoveArgs } from "./activities/sprite-fs";
|
|
33
|
+
import type { SpriteApplyNetworkPolicyArgs, SpriteApplyServicesArgs } from "./activities/sprite-config";
|
|
34
|
+
import type { SpriteTaskCreateArgs, SpriteTaskRefreshArgs, SpriteTaskReleaseArgs } from "./activities/sprite-tasks";
|
|
35
|
+
import type { SpritesUpArgs, SpritesDownArgs } from "./activities/sprites-emulator";
|
|
36
|
+
|
|
37
|
+
type StepOpts = { profile?: ActivityStep["profile"] };
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build one whole-args typed sprite step builder — `args` IS the activity's
|
|
41
|
+
* own `*Args` type, `profile` routed off it, never restated. Only `profile`
|
|
42
|
+
* is extracted, deliberately NOT a step-authoring `id` the way the other
|
|
43
|
+
* lexicons' wrappers offer: `id` is itself a REQUIRED domain field on nearly
|
|
44
|
+
* every `Sprite*Args` here (the target sprite's id — `spriteExec`,
|
|
45
|
+
* `spriteWriteFile`, `spriteTaskCreate`, ...), so stripping an `id` key off
|
|
46
|
+
* the flat args object the way `takeProfileAndId` does elsewhere would
|
|
47
|
+
* silently steal the sprite id into the step's `id` and drop it from `args`
|
|
48
|
+
* — the exact silent-wrong-value failure class chant #1288 exists to catch,
|
|
49
|
+
* not reproduce. `.out`-by-id (#1290) is out of scope for the sprite family
|
|
50
|
+
* through this convenience layer, exactly as it was through core's original
|
|
51
|
+
* builders; an author who needs it authors `activity("spriteExec", args, {
|
|
52
|
+
* id: "..." })` directly. `Args` is deliberately unconstrained: a named
|
|
53
|
+
* interface without an explicit index signature (every `Sprite*Args` here)
|
|
54
|
+
* is not assignable to `Record<string, unknown>` structurally, even though
|
|
55
|
+
* every field it does declare is — the `as Record<string, unknown>` cast
|
|
56
|
+
* below is a type ASSERTION (permissive), not an assignment, so it doesn't
|
|
57
|
+
* need the constraint.
|
|
58
|
+
*/
|
|
59
|
+
function spriteStep<Args>(fn: string, defaultProfile: NonNullable<ActivityStep["profile"]>) {
|
|
60
|
+
return (args: WithStepRefs<Args> & StepOpts): NamedActivityStep => {
|
|
61
|
+
const { profile, ...rest } = args as { profile?: ActivityStep["profile"] } & Record<string, unknown>;
|
|
62
|
+
return activity(fn, rest, profile ?? defaultProfile);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Create a sprite — the fully typed twin of core's `spriteCreate`. Defaults to the `longInfra` profile. */
|
|
67
|
+
export const spriteCreate = spriteStep<SpriteCreateArgs>("spriteCreate", "longInfra");
|
|
68
|
+
/** Run a command in a sprite — the fully typed twin of core's `spriteExec`. Defaults to the `longInfra` profile. */
|
|
69
|
+
export const spriteExec = spriteStep<SpriteExecArgs>("spriteExec", "longInfra");
|
|
70
|
+
/** Checkpoint a sprite — the fully typed twin of core's `spriteCheckpoint`. Defaults to the `longInfra` profile. */
|
|
71
|
+
export const spriteCheckpoint = spriteStep<SpriteCheckpointArgs>("spriteCheckpoint", "longInfra");
|
|
72
|
+
/** Restore a sprite — the fully typed twin of core's `spriteRestore`. Defaults to the `longInfra` profile. */
|
|
73
|
+
export const spriteRestore = spriteStep<SpriteRestoreArgs>("spriteRestore", "longInfra");
|
|
74
|
+
/** List a sprite's checkpoints — the fully typed twin of core's `listCheckpoints`. Defaults to the `fastIdempotent` profile. */
|
|
75
|
+
export const listCheckpoints = spriteStep<ListCheckpointsArgs>("listCheckpoints", "fastIdempotent");
|
|
76
|
+
/** Destroy a sprite — the fully typed twin of core's `spriteDestroy`. Defaults to the `fastIdempotent` profile. */
|
|
77
|
+
export const spriteDestroy = spriteStep<SpriteDestroyArgs>("spriteDestroy", "fastIdempotent");
|
|
78
|
+
/** Write a file into a sprite — the fully typed twin of core's `spriteWriteFile`. Defaults to the `fastIdempotent` profile. */
|
|
79
|
+
export const spriteWriteFile = spriteStep<SpriteWriteFileArgs>("spriteWriteFile", "fastIdempotent");
|
|
80
|
+
/** Read a file from a sprite — the fully typed twin of core's `spriteReadFile`. Defaults to the `fastIdempotent` profile. */
|
|
81
|
+
export const spriteReadFile = spriteStep<SpriteReadFileArgs>("spriteReadFile", "fastIdempotent");
|
|
82
|
+
/** List a directory in a sprite — the fully typed twin of core's `spriteListDir`. Defaults to the `fastIdempotent` profile. */
|
|
83
|
+
export const spriteListDir = spriteStep<SpriteListDirArgs>("spriteListDir", "fastIdempotent");
|
|
84
|
+
/** Remove a path in a sprite — the fully typed twin of core's `spriteRemove`. Defaults to the `fastIdempotent` profile. */
|
|
85
|
+
export const spriteRemove = spriteStep<SpriteRemoveArgs>("spriteRemove", "fastIdempotent");
|
|
86
|
+
/** Reconcile a sprite's outbound network policy — the fully typed twin of core's `spriteApplyNetworkPolicy`. Defaults to the `fastIdempotent` profile. */
|
|
87
|
+
export const spriteApplyNetworkPolicy = spriteStep<SpriteApplyNetworkPolicyArgs>("spriteApplyNetworkPolicy", "fastIdempotent");
|
|
88
|
+
/** Reconcile a sprite's background services — the fully typed twin of core's `spriteApplyServices`. Defaults to the `fastIdempotent` profile. */
|
|
89
|
+
export const spriteApplyServices = spriteStep<SpriteApplyServicesArgs>("spriteApplyServices", "fastIdempotent");
|
|
90
|
+
/** Create a keep-alive task — the fully typed twin of core's `spriteTaskCreate`. Defaults to the `fastIdempotent` profile. */
|
|
91
|
+
export const spriteTaskCreate = spriteStep<SpriteTaskCreateArgs>("spriteTaskCreate", "fastIdempotent");
|
|
92
|
+
/** Refresh a keep-alive task's expiry — the fully typed twin of core's `spriteTaskRefresh`. Defaults to the `fastIdempotent` profile. */
|
|
93
|
+
export const spriteTaskRefresh = spriteStep<SpriteTaskRefreshArgs>("spriteTaskRefresh", "fastIdempotent");
|
|
94
|
+
/** Release a keep-alive task — the fully typed twin of core's `spriteTaskRelease`. Defaults to the `fastIdempotent` profile. */
|
|
95
|
+
export const spriteTaskRelease = spriteStep<SpriteTaskReleaseArgs>("spriteTaskRelease", "fastIdempotent");
|
|
96
|
+
|
|
97
|
+
/** Boot a local spritzer (Fly Sprites API emulator) — the fully typed twin of core's `spritesUp`. Defaults to the `longInfra` profile. */
|
|
98
|
+
export const spritesUp = (args: WithStepRefs<SpritesUpArgs> & StepOpts = {}): NamedActivityStep =>
|
|
99
|
+
spriteStep<SpritesUpArgs>("spritesUp", "longInfra")(args);
|
|
100
|
+
/** Stop and remove the local spritzer container — the fully typed twin of core's `spritesDown`. Defaults to the `fastIdempotent` profile. */
|
|
101
|
+
export const spritesDown = (args: WithStepRefs<SpritesDownArgs> & StepOpts = {}): NamedActivityStep =>
|
|
102
|
+
spriteStep<SpritesDownArgs>("spritesDown", "fastIdempotent")(args);
|