@intentius/chant-lexicon-fly 0.18.6 → 0.18.8

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.
Files changed (30) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/op/activities/emulator-images.d.ts +1 -1
  4. package/dist/op/activities/index.d.ts +6 -0
  5. package/dist/op/activities/index.d.ts.map +1 -1
  6. package/dist/op/activities/sprite-config.d.ts +91 -0
  7. package/dist/op/activities/sprite-config.d.ts.map +1 -0
  8. package/dist/op/activities/sprite-fs.d.ts +96 -0
  9. package/dist/op/activities/sprite-fs.d.ts.map +1 -0
  10. package/dist/op/activities/sprite-tasks.d.ts +54 -0
  11. package/dist/op/activities/sprite-tasks.d.ts.map +1 -0
  12. package/dist/op/activities/sprites-contract.d.ts +10 -6
  13. package/dist/op/activities/sprites-contract.d.ts.map +1 -1
  14. package/dist/op/activities/sprites-fake.d.ts +37 -0
  15. package/dist/op/activities/sprites-fake.d.ts.map +1 -1
  16. package/package.json +2 -2
  17. package/src/index.ts +9 -0
  18. package/src/op/activities/emulator-images.ts +1 -1
  19. package/src/op/activities/index.ts +56 -0
  20. package/src/op/activities/sprite-config.docker.integration.test.ts +98 -0
  21. package/src/op/activities/sprite-config.test.ts +159 -0
  22. package/src/op/activities/sprite-config.ts +246 -0
  23. package/src/op/activities/sprite-fs.test.ts +136 -0
  24. package/src/op/activities/sprite-fs.ts +217 -0
  25. package/src/op/activities/sprite-tasks.test.ts +165 -0
  26. package/src/op/activities/sprite-tasks.ts +91 -0
  27. package/src/op/activities/sprites-contract.test.ts +24 -6
  28. package/src/op/activities/sprites-contract.ts +27 -6
  29. package/src/op/activities/sprites-fake.ts +201 -2
  30. package/src/skills/chant-fly-sprites.md +14 -0
package/dist/index.d.ts CHANGED
@@ -4,6 +4,6 @@ export { Fly, Region, OrgSlug, AppName, PseudoParameter } from "./pseudo.js";
4
4
  export { FLY_METADATA_OWNERSHIP_KEYS } from "./ownership.js";
5
5
  export { flyDeploy, flapsUp, flapsDown, flyApplyStep, LOCAL_FLAPS_ENDPOINT } from "./composites/fly-deploy.js";
6
6
  export type { FlyDeployOpts, FlyApplyStepOpts, FlapsStepOpts } from "./composites/fly-deploy.js";
7
- export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, spritesUp, spritesDown, } from "@intentius/chant/op";
7
+ export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove, spriteApplyNetworkPolicy, spriteApplyServices, spriteTaskCreate, spriteTaskRefresh, spriteTaskRelease, spritesUp, spritesDown, } from "@intentius/chant/op";
8
8
  export * from "./generated/index.js";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAK1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM9F,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAK7B,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAK1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM9F,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAK7B,cAAc,mBAAmB,CAAC"}
@@ -16,5 +16,5 @@
16
16
  /** Pinned mudflaps (Fly Machines / flaps emulator) image. */
17
17
  export declare const MUDFLAPS_IMAGE = "ghcr.io/intentius/mudflaps:0.4.0";
18
18
  /** Pinned spritzer (Fly Sprites emulator) image. */
19
- export declare const SPRITZER_IMAGE = "ghcr.io/intentius/spritzer:0.3.1";
19
+ export declare const SPRITZER_IMAGE = "ghcr.io/intentius/spritzer:0.4.0";
20
20
  //# sourceMappingURL=emulator-images.d.ts.map
@@ -11,6 +11,12 @@ export { flapsUp, flapsDown, flapsRunCommand, flapsRmCommand, flapsExistsCommand
11
11
  export type { FlapsUpArgs, FlapsDownArgs } from "./flaps.js";
12
12
  export { spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, resolveSpritesEndpoint, defaultSpritesHttp, spriteCreateBody, parseCreateResponse, accumulateExecFrames, parseCheckpointNdjson, pickCheckpointByComment, splitCommand, spriteExecWsUrl, DEFAULT_SPRITES_BASE_URL, } from "./sprites.js";
13
13
  export type { SpritesHttp, SpriteCreateArgs, SpriteCreateResult, SpriteExecArgs, SpriteExecResult, SpriteCheckpointArgs, SpriteCheckpointResult, SpriteRestoreArgs, ListCheckpointsArgs, Checkpoint, SpriteDestroyArgs, } from "./sprites.js";
14
+ export { spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove, spriteFsUrl, defaultSpritesRawHttp, } from "./sprite-fs.js";
15
+ export type { SpritesRawHttp, SpriteWriteFileArgs, SpriteReadFileArgs, SpriteReadFileResult, SpriteListDirArgs, SpriteDirEntry, SpriteRemoveArgs, } from "./sprite-fs.js";
16
+ export { spriteApplyNetworkPolicy, spriteApplyServices, validateNetworkRules, networkRulesEqual, validateServices, serviceConfigEqual, } from "./sprite-config.js";
17
+ export type { NetworkRule, SpriteApplyNetworkPolicyArgs, SpriteApplyNetworkPolicyResult, ServiceSpec, SpriteApplyServicesArgs, SpriteApplyServicesResult, } from "./sprite-config.js";
18
+ export { spriteTaskCreate, spriteTaskRefresh, spriteTaskRelease, spriteTasksUrl, spriteTaskUrl, } from "./sprite-tasks.js";
19
+ export type { SpriteTaskCreateArgs, SpriteTaskRefreshArgs, SpriteTaskReleaseArgs, } from "./sprite-tasks.js";
14
20
  export { spritesUp, spritesDown, spritesRunCommand, spritesRmCommand, spritesExistsCommand, spritesHealthUrl, spritesEndpoint, } from "./sprites-emulator.js";
15
21
  export type { SpritesUpArgs, SpritesDownArgs } from "./sprites-emulator.js";
16
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIlH,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ1D,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,eAAe,EACf,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAMnB,OAAO,EACL,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIlH,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ1D,OAAO,EACL,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,eAAe,EACf,wBAAwB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAInB,OAAO,EACL,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAMrB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,EACX,4BAA4B,EAC5B,8BAA8B,EAC9B,WAAW,EACX,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Sprite config reconcile activities (#849) — the two pieces of genuine
3
+ * desired-state a Sprite carries: its outbound network policy and its background
4
+ * services. Unlike the sprite itself (an Op primitive with no reconcilable
5
+ * create body), these are set after create and persist across cold boots, so
6
+ * chant reconciles typed config against the live Sprite — the `flyApply`
7
+ * plan→CRUD pattern scoped to one Sprite, not a declarable resource.
8
+ *
9
+ * Both use the JSON `SpritesHttp` client from `sprites.ts`; endpoint + bearer
10
+ * resolution is shared. Validation is pure and runs before any HTTP (invalid
11
+ * rules / a `needs` cycle throw up front), so a bad config fails the step
12
+ * cleanly rather than half-applying.
13
+ *
14
+ * Scope (v1): network policy is a whole-object replace (converges by
15
+ * construction); services reconcile is additive + update (create-or-update each
16
+ * desired service, optionally start). Owned-only prune of stale services is out
17
+ * of scope — the documented Services REST surface exposes no delete.
18
+ */
19
+ import { type SpritesHttp } from "./sprites.js";
20
+ /** One outbound rule. Ordered — specificity is positional, so order is significant. */
21
+ export interface NetworkRule {
22
+ domain: string;
23
+ action: "allow" | "deny";
24
+ }
25
+ export interface SpriteApplyNetworkPolicyArgs {
26
+ id: string;
27
+ /** The complete desired ruleset (whole-object replace). */
28
+ rules: NetworkRule[];
29
+ endpoint?: string;
30
+ token?: string;
31
+ }
32
+ export interface SpriteApplyNetworkPolicyResult {
33
+ /** True when the live policy differed and was replaced; false when already converged. */
34
+ changed: boolean;
35
+ }
36
+ /**
37
+ * Validate a ruleset: every rule needs a non-empty `domain` and an `allow`/`deny`
38
+ * `action`. Pure; throws on the first offender.
39
+ */
40
+ export declare function validateNetworkRules(rules: NetworkRule[]): void;
41
+ /** Order-sensitive equality of two rulesets (position is significant). Pure. */
42
+ export declare function networkRulesEqual(a: NetworkRule[], b: NetworkRule[]): boolean;
43
+ /**
44
+ * Reconcile a Sprite's outbound network policy. GET the live ruleset, and POST
45
+ * the desired set only when it differs (`GET`/`POST /policy/network`). Returns
46
+ * whether a change was applied.
47
+ */
48
+ export declare function spriteApplyNetworkPolicy(args: SpriteApplyNetworkPolicyArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<SpriteApplyNetworkPolicyResult>;
49
+ /** A desired background service. Keyed by `name`; PUT is create-or-update. */
50
+ export interface ServiceSpec {
51
+ name: string;
52
+ cmd: string;
53
+ args?: string[];
54
+ env?: Record<string, string>;
55
+ dir?: string;
56
+ /** Names of services that must start first. */
57
+ needs?: string[];
58
+ /** Route the Sprite's public URL to this port. */
59
+ http_port?: number;
60
+ }
61
+ export interface SpriteApplyServicesArgs {
62
+ id: string;
63
+ services: ServiceSpec[];
64
+ /** Start each service after applying (in dependency order). Default: false. */
65
+ start?: boolean;
66
+ endpoint?: string;
67
+ token?: string;
68
+ }
69
+ export interface SpriteApplyServicesResult {
70
+ /** Names that were created or updated (converged services are skipped). */
71
+ applied: string[];
72
+ /** Names that were started (empty unless `start`). */
73
+ started: string[];
74
+ }
75
+ /**
76
+ * Validate a service set: names are unique, every `needs` target exists, and the
77
+ * dependency graph is acyclic. Pure; throws on the first violation. Returns the
78
+ * names in a valid start order (dependencies first).
79
+ */
80
+ export declare function validateServices(services: ServiceSpec[]): string[];
81
+ /** Comparable service config (the fields the reconcile diffs on). Pure. */
82
+ export declare function serviceConfigEqual(a: Partial<ServiceSpec>, b: Partial<ServiceSpec>): boolean;
83
+ /**
84
+ * Reconcile a Sprite's background services (additive + update). Lists the live
85
+ * services, then `PUT`s each desired service that is new or changed
86
+ * (create-or-update by name); when `start` is set, `POST .../start`s them in
87
+ * dependency order. Converged services are skipped. Owned-only prune is out of
88
+ * scope (no delete in the Services REST surface).
89
+ */
90
+ export declare function spriteApplyServices(args: SpriteApplyServicesArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<SpriteApplyServicesResult>;
91
+ //# sourceMappingURL=sprite-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite-config.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAA8C,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAYzF,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC7C,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAS/D;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAG7E;AAKD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,4BAA4B,EAClC,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,8BAA8B,CAAC,CAiBzC;AAID,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,EAAE,CA0BlE;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAW5F;AAkBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,yBAAyB,CAAC,CAsCpC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Sprite filesystem activities (#848) — imperative file-I/O primitives over the
3
+ * Sprites filesystem API (`/v1/sprites/{id}/fs/*`). Same category as the
4
+ * lifecycle activities in `sprites.ts`: runtime-orchestration primitives, no
5
+ * desired state. They let an Op stage an input file into a sprite and read a
6
+ * result out without shelling it through `spriteExec` + `cat`/`tee`.
7
+ *
8
+ * read/write move raw file bytes in the body (not JSON), so these use a small
9
+ * raw HTTP client (`SpritesRawHttp`) rather than the JSON `SpritesHttp` the
10
+ * lifecycle activities use; path/mode/mkdir/recursive ride as query params.
11
+ * Endpoint + bearer resolution mirror `sprites.ts` — an explicit `endpoint` /
12
+ * `token` wins, then `SPRITES_BASE_URL` / `SPRITES_API_TOKEN`.
13
+ */
14
+ /**
15
+ * Build a `/v1/sprites/{id}/fs/{op}?...` URL. `params` values that are undefined
16
+ * or empty are dropped so the query only carries what the caller set. Pure.
17
+ */
18
+ export declare function spriteFsUrl(base: string, id: string, op: "read" | "write" | "list" | "delete", params: Record<string, string | boolean | undefined>): string;
19
+ /**
20
+ * Injectable raw HTTP client — like `SpritesHttp` but the body is sent verbatim
21
+ * (a file's bytes as a string), not JSON-encoded, and the response `text` is the
22
+ * raw body. Tests inject a fake; the default hits `fetch`.
23
+ */
24
+ export type SpritesRawHttp = (method: string, url: string, body?: string, headers?: Record<string, string>, signal?: AbortSignal) => Promise<{
25
+ status: number;
26
+ text: string;
27
+ }>;
28
+ /**
29
+ * Default `fetch`-based raw client. Sends the body as-is with an
30
+ * `application/octet-stream` content-type and `Authorization: Bearer <token>`
31
+ * when a token is set (real Sprites); the fake ignores the token. The token
32
+ * defaults to `SPRITES_API_TOKEN` at call time. `fetchImpl` is injectable.
33
+ */
34
+ export declare function defaultSpritesRawHttp(token?: string, fetchImpl?: typeof fetch): SpritesRawHttp;
35
+ export interface SpriteWriteFileArgs {
36
+ /** Target sprite id (the `name` passed to `spriteCreate`). */
37
+ id: string;
38
+ /** Absolute path (or relative to `workingDir`) to write. */
39
+ path: string;
40
+ /** File contents. */
41
+ content: string;
42
+ /** Octal file mode, e.g. `"0644"`. */
43
+ mode?: string;
44
+ /** Create missing parent directories. */
45
+ mkdir?: boolean;
46
+ /** Base directory for a relative `path`. */
47
+ workingDir?: string;
48
+ endpoint?: string;
49
+ token?: string;
50
+ }
51
+ export interface SpriteReadFileArgs {
52
+ id: string;
53
+ path: string;
54
+ workingDir?: string;
55
+ endpoint?: string;
56
+ token?: string;
57
+ }
58
+ export interface SpriteReadFileResult {
59
+ content: string;
60
+ }
61
+ export interface SpriteListDirArgs {
62
+ id: string;
63
+ path: string;
64
+ workingDir?: string;
65
+ endpoint?: string;
66
+ token?: string;
67
+ }
68
+ /** One directory entry. `type` is `file` or `dir`. */
69
+ export interface SpriteDirEntry {
70
+ name: string;
71
+ type: "file" | "dir";
72
+ size?: number;
73
+ }
74
+ export interface SpriteRemoveArgs {
75
+ id: string;
76
+ path: string;
77
+ /** Remove a directory and its contents. */
78
+ recursive?: boolean;
79
+ /** Perform the delete as root. */
80
+ asRoot?: boolean;
81
+ workingDir?: string;
82
+ endpoint?: string;
83
+ token?: string;
84
+ }
85
+ /** Write a file into the sprite. `PUT /v1/sprites/{id}/fs/write` with raw body. */
86
+ export declare function spriteWriteFile(args: SpriteWriteFileArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<Record<string, never>>;
87
+ /** Read a file from the sprite. `GET /v1/sprites/{id}/fs/read` → raw body. */
88
+ export declare function spriteReadFile(args: SpriteReadFileArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<SpriteReadFileResult>;
89
+ /** List a directory in the sprite. `GET /v1/sprites/{id}/fs/list` → entry array. */
90
+ export declare function spriteListDir(args: SpriteListDirArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<SpriteDirEntry[]>;
91
+ /**
92
+ * Remove a path in the sprite. `DELETE /v1/sprites/{id}/fs/delete`. Idempotent:
93
+ * a 404 (already gone) is a no-op, matching `rm -f` and the destroy activity.
94
+ */
95
+ export declare function spriteRemove(args: SpriteRemoveArgs, signal?: AbortSignal, http?: SpritesRawHttp): Promise<Record<string, never>>;
96
+ //# sourceMappingURL=sprite-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite-fs.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-fs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Sprite keep-alive Tasks activities (#847) — a hold that prevents a Sprite from
3
+ * pausing while a session runs. While at least one task exists the Sprite stays
4
+ * active; the hold is refreshed on an interval and released on exit.
5
+ *
6
+ * Per the Sprites docs a task carries an `expire` (seconds or a duration string
7
+ * like `"5m"`/`"1h"`) with a **1-hour max per task**, so a session longer than
8
+ * that must refresh. The recommended shape is a short expiry refreshed on a
9
+ * shorter interval — 5-minute expiry / 60-second refresh — released on exit.
10
+ *
11
+ * These are the three primitives, not a magic looping hold: a phased Op creates
12
+ * the task around a session (`spriteTaskCreate`) and releases it after (in the
13
+ * happy path and in `onFailure`). A worker whose session can outlast the 1-hour
14
+ * cap wraps its own run in a `spriteTaskRefresh` loop (that ambient loop lives in
15
+ * the long-running caller, not a single serializable activity — a phased Op has
16
+ * no single step to hang it on). `spriteTaskRelease` is idempotent so a crash
17
+ * still frees the Sprite (and the task auto-expires if the release never lands).
18
+ *
19
+ * The task REST path is provisional (S6, #766); it mirrors the other endpoints'
20
+ * `/v1/sprites/{id}/...` shape. URL building is a pure helper so the path can
21
+ * move without touching callers.
22
+ */
23
+ import { type SpritesHttp } from "./sprites.js";
24
+ /** The task REST base for a sprite. Pure. */
25
+ export declare function spriteTasksUrl(base: string, id: string): string;
26
+ export declare function spriteTaskUrl(base: string, id: string, name: string): string;
27
+ export interface SpriteTaskCreateArgs {
28
+ id: string;
29
+ /** Task name (the key later refresh/release use). */
30
+ name: string;
31
+ /** Expiry: seconds (number) or a duration string (`"5m"`, `"1h"`). Max 1h. */
32
+ expire?: number | string;
33
+ endpoint?: string;
34
+ token?: string;
35
+ }
36
+ export interface SpriteTaskRefreshArgs extends SpriteTaskCreateArgs {
37
+ }
38
+ export interface SpriteTaskReleaseArgs {
39
+ id: string;
40
+ name: string;
41
+ endpoint?: string;
42
+ token?: string;
43
+ }
44
+ /** Create a keep-alive task. `POST /v1/sprites/{id}/tasks`. */
45
+ export declare function spriteTaskCreate(args: SpriteTaskCreateArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<{
46
+ name: string;
47
+ }>;
48
+ /** Refresh a task's expiry. `PUT /v1/sprites/{id}/tasks/{name}`. */
49
+ export declare function spriteTaskRefresh(args: SpriteTaskRefreshArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<{
50
+ name: string;
51
+ }>;
52
+ /** Release a task (idempotent; a 404 means already gone). `DELETE /v1/sprites/{id}/tasks/{name}`. */
53
+ export declare function spriteTaskRelease(args: SpriteTaskReleaseArgs, signal?: AbortSignal, http?: SpritesHttp): Promise<Record<string, never>>;
54
+ //# sourceMappingURL=sprite-tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite-tasks.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprite-tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAA8C,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzF,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/D;AACD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;CAAG;AAEtE,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,oBAAoB,EAC1B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAM3B;AAED,oEAAoE;AACpE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAM3B;AAED,qGAAqG;AACrG,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,GAAE,WAA4C,GACjD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAOhC"}
@@ -5,8 +5,8 @@
5
5
  * the fly resource surface generates + drift-checks against. The Sprites API
6
6
  * (api.sprites.dev) ships no such spec at any conventional path, so there is
7
7
  * nothing to diff automatically. This module is the manual stand-in: the exact
8
- * endpoint set the fly sprite activities (./sprites.ts) depend on, maintained by
9
- * hand from https://docs.sprites.dev.
8
+ * endpoint set the fly sprite activities (lifecycle, filesystem, config, tasks)
9
+ * depend on, maintained by hand from https://docs.sprites.dev.
10
10
  *
11
11
  * It anchors two fidelity checks:
12
12
  * 1. Coverage — every endpoint here must be served by the pinned spritzer
@@ -23,15 +23,19 @@
23
23
  /** One endpoint the fly sprite activities call. */
24
24
  export interface SpritesEndpoint {
25
25
  /** HTTP method, or "WS" for the control-WebSocket exec channel. */
26
- method: "GET" | "POST" | "DELETE" | "WS";
26
+ method: "GET" | "POST" | "PUT" | "DELETE" | "WS";
27
27
  /** Path template under the Sprites base, e.g. `/v1/sprites/{id}/checkpoint`. */
28
28
  path: string;
29
- /** The fly activity that calls it (./sprites.ts export). */
29
+ /** The fly activity that calls it (an activity module export). */
30
30
  activity: string;
31
31
  }
32
32
  /**
33
- * The Sprites endpoints ./sprites.ts depends on. Keep in sync with the activity
34
- * implementations the unit test asserts every sprite activity is represented.
33
+ * The Sprites endpoints the fly sprite activities depend on, across the lifecycle
34
+ * (./sprites.ts), filesystem (./sprite-fs.ts), config reconcile
35
+ * (./sprite-config.ts), and keep-alive tasks (./sprite-tasks.ts) modules. Keep in
36
+ * sync with the activity implementations — the unit test asserts every sprite
37
+ * activity is represented, and the coverage test asserts the pinned spritzer
38
+ * serves each one.
35
39
  */
36
40
  export declare const SPRITES_CONTRACT: readonly SpritesEndpoint[];
37
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"sprites-contract.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IACzC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAO7C,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,CAE1C"}
1
+ {"version":3,"file":"sprites-contract.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;IACjD,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAwB7C,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,CAE1C"}
@@ -26,6 +26,21 @@ interface StoredCheckpoint {
26
26
  is_auto: boolean;
27
27
  fs: Record<string, string>;
28
28
  }
29
+ interface StoredService {
30
+ name: string;
31
+ cmd: string;
32
+ args?: string[];
33
+ env?: Record<string, string>;
34
+ dir?: string;
35
+ needs?: string[];
36
+ http_port?: number;
37
+ state: {
38
+ name: string;
39
+ pid: number;
40
+ status: string;
41
+ started_at?: string;
42
+ };
43
+ }
29
44
  interface SpriteState {
30
45
  id: string;
31
46
  status: SpriteStatus;
@@ -37,6 +52,18 @@ interface SpriteState {
37
52
  /** Monotonic version counter for `v<N>` ids. */
38
53
  version: number;
39
54
  policy?: unknown;
55
+ /** Outbound network policy (whole-object replace via /policy/network). */
56
+ netPolicy: Array<{
57
+ domain: string;
58
+ action: string;
59
+ }>;
60
+ /** Background services keyed by name (create-or-update via PUT). */
61
+ services: Record<string, StoredService>;
62
+ /** Keep-alive tasks keyed by name; while any exists the sprite stays active. */
63
+ tasks: Record<string, {
64
+ name: string;
65
+ expire?: number | string;
66
+ }>;
40
67
  }
41
68
  interface ExecResult {
42
69
  stdout: string;
@@ -50,6 +77,16 @@ interface ExecResult {
50
77
  * `;` run in order; the exit code is the last segment's (shell `;` semantics).
51
78
  */
52
79
  export declare function fakeExec(sprite: SpriteState, cmd: string): ExecResult;
80
+ /**
81
+ * Immediate children of `dir` in a flat `path → contents` map: a key
82
+ * `${dir}/name` is a file; `${dir}/name/...` contributes the dir `name` once.
83
+ * Pure — the filesystem-list model for the fake.
84
+ */
85
+ export declare function fakeListDir(fs: Record<string, string>, dir: string): Array<{
86
+ name: string;
87
+ type: "file" | "dir";
88
+ size?: number;
89
+ }>;
53
90
  /**
54
91
  * Start the in-process Sprites fake on an ephemeral port. Returns its base
55
92
  * `url` (feed it to `SPRITES_BASE_URL`) and a `close()`.
@@ -1 +1 @@
1
- {"version":3,"file":"sprites-fake.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,KAAK,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpE,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAwCrE;AAqCD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA4KpF"}
1
+ {"version":3,"file":"sprites-fake.d.ts","sourceRoot":"","sources":["../../../src/op/activities/sprites-fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,KAAK,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEpE,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,SAAS,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;CACnE;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CA6CrE;AA4CD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBjI;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA+TpF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-fly",
3
- "version": "0.18.6",
3
+ "version": "0.18.8",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src/",
@@ -57,7 +57,7 @@
57
57
  "typescript": "^5.9.3"
58
58
  },
59
59
  "peerDependencies": {
60
- "@intentius/chant": "^0.18.6"
60
+ "@intentius/chant": "^0.18.8"
61
61
  },
62
62
  "description": "Google Cloud lexicon for chant — declarative IaC in TypeScript",
63
63
  "license": "Apache-2.0",
package/src/index.ts CHANGED
@@ -28,6 +28,15 @@ export {
28
28
  spriteRestore,
29
29
  listCheckpoints,
30
30
  spriteDestroy,
31
+ spriteWriteFile,
32
+ spriteReadFile,
33
+ spriteListDir,
34
+ spriteRemove,
35
+ spriteApplyNetworkPolicy,
36
+ spriteApplyServices,
37
+ spriteTaskCreate,
38
+ spriteTaskRefresh,
39
+ spriteTaskRelease,
31
40
  spritesUp,
32
41
  spritesDown,
33
42
  } from "@intentius/chant/op";
@@ -18,4 +18,4 @@
18
18
  export const MUDFLAPS_IMAGE = "ghcr.io/intentius/mudflaps:0.4.0";
19
19
 
20
20
  /** Pinned spritzer (Fly Sprites emulator) image. */
21
- export const SPRITZER_IMAGE = "ghcr.io/intentius/spritzer:0.3.1";
21
+ export const SPRITZER_IMAGE = "ghcr.io/intentius/spritzer:0.4.0";
@@ -85,6 +85,62 @@ export type {
85
85
  SpriteDestroyArgs,
86
86
  } from "./sprites";
87
87
 
88
+ // Sprite filesystem activities (#848) — imperative file I/O over the fs API.
89
+ // `loadActivities(["fly"])` binds these; the step builders live in core.
90
+ export {
91
+ spriteWriteFile,
92
+ spriteReadFile,
93
+ spriteListDir,
94
+ spriteRemove,
95
+ spriteFsUrl,
96
+ defaultSpritesRawHttp,
97
+ } from "./sprite-fs";
98
+ export type {
99
+ SpritesRawHttp,
100
+ SpriteWriteFileArgs,
101
+ SpriteReadFileArgs,
102
+ SpriteReadFileResult,
103
+ SpriteListDirArgs,
104
+ SpriteDirEntry,
105
+ SpriteRemoveArgs,
106
+ } from "./sprite-fs";
107
+
108
+ // Sprite config reconcile activities (#849) — the desired-state a Sprite carries:
109
+ // its outbound network policy and its background services. `loadActivities(["fly"])`
110
+ // binds these; the step builders live in core. Apply-activities, not a declarable
111
+ // resource — a Sprite has no build→plan→apply pipeline.
112
+ export {
113
+ spriteApplyNetworkPolicy,
114
+ spriteApplyServices,
115
+ validateNetworkRules,
116
+ networkRulesEqual,
117
+ validateServices,
118
+ serviceConfigEqual,
119
+ } from "./sprite-config";
120
+ export type {
121
+ NetworkRule,
122
+ SpriteApplyNetworkPolicyArgs,
123
+ SpriteApplyNetworkPolicyResult,
124
+ ServiceSpec,
125
+ SpriteApplyServicesArgs,
126
+ SpriteApplyServicesResult,
127
+ } from "./sprite-config";
128
+
129
+ // Sprite keep-alive Tasks activities (#847) — a hold that stops a Sprite pausing
130
+ // mid-session. `loadActivities(["fly"])` binds these; step builders live in core.
131
+ export {
132
+ spriteTaskCreate,
133
+ spriteTaskRefresh,
134
+ spriteTaskRelease,
135
+ spriteTasksUrl,
136
+ spriteTaskUrl,
137
+ } from "./sprite-tasks";
138
+ export type {
139
+ SpriteTaskCreateArgs,
140
+ SpriteTaskRefreshArgs,
141
+ SpriteTaskReleaseArgs,
142
+ } from "./sprite-tasks";
143
+
88
144
  // spritzer (the Sprites API emulator) Docker lifecycle — the twin of mudflaps
89
145
  // above. `spritesUp`/`spritesDown` resolve by name so an Op can boot/tear down
90
146
  // the emulator as a modeled step; the sprite activities target it via
@@ -0,0 +1,98 @@
1
+ import { describe, test, expect, beforeAll, afterAll } from "vitest";
2
+ import { spritesUp, spritesDown } from "./sprites-emulator";
3
+ import { spriteCreate } from "./sprites";
4
+ import { spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove } from "./sprite-fs";
5
+ import { spriteApplyNetworkPolicy, spriteApplyServices } from "./sprite-config";
6
+ import { spriteTaskCreate, spriteTaskRelease } from "./sprite-tasks";
7
+
8
+ // The filesystem / config-reconcile / keep-alive activities driven against the
9
+ // REAL spritzer image (ghcr.io/intentius/spritzer), booted via `spritesUp` — the
10
+ // twin of the lifecycle docker test. Proves the image serves these endpoints
11
+ // with the same wire shape the in-process fake does. Docker required;
12
+ // deterministically skipped in CI unless SPRITES_DOCKER=1.
13
+
14
+ const CONTAINER = "chant-spritzer-config-it";
15
+ const PORT = 4294;
16
+
17
+ let available = false;
18
+ let endpoint = "";
19
+
20
+ async function inspect(id: string): Promise<{
21
+ fs: Record<string, string>;
22
+ netPolicy: Array<{ domain: string; action: string }>;
23
+ services: Record<string, { state: { status: string } }>;
24
+ tasks: Record<string, unknown>;
25
+ }> {
26
+ const res = await fetch(`${endpoint}/v1/sprites/${id}`);
27
+ return (await res.json()) as never;
28
+ }
29
+
30
+ beforeAll(async () => {
31
+ if (process.env.CI && !process.env.SPRITES_DOCKER) {
32
+ available = false;
33
+ return;
34
+ }
35
+ try {
36
+ const up = await spritesUp({ name: CONTAINER, port: PORT, timeoutMs: 30_000 });
37
+ endpoint = up.endpoint;
38
+ available = true;
39
+ } catch {
40
+ available = false;
41
+ }
42
+ }, 60_000);
43
+
44
+ afterAll(async () => {
45
+ if (available) await spritesDown({ name: CONTAINER });
46
+ });
47
+
48
+ describe("fs / config / tasks activities against real spritzer", () => {
49
+ test("filesystem round-trips (write → read → list → remove)", async (ctx) => {
50
+ if (!available) ctx.skip();
51
+ await spriteCreate({ name: "d-fs", endpoint });
52
+ await spriteWriteFile({ id: "d-fs", path: "/work/input", content: "hello", endpoint });
53
+ expect((await spriteReadFile({ id: "d-fs", path: "/work/input", endpoint })).content).toBe("hello");
54
+ await spriteWriteFile({ id: "d-fs", path: "/work/notes/a", content: "x", endpoint });
55
+ const list = await spriteListDir({ id: "d-fs", path: "/work", endpoint });
56
+ expect(list.map((e) => e.name).sort()).toEqual(["input", "notes"]);
57
+ await spriteRemove({ id: "d-fs", path: "/work/input", endpoint });
58
+ await expect(spriteReadFile({ id: "d-fs", path: "/work/input", endpoint })).rejects.toThrow(/not found/);
59
+ });
60
+
61
+ test("network policy reconcile converges", async (ctx) => {
62
+ if (!available) ctx.skip();
63
+ await spriteCreate({ name: "d-np", endpoint });
64
+ const rules = [
65
+ { domain: "api.anthropic.com", action: "allow" as const },
66
+ { domain: "*", action: "deny" as const },
67
+ ];
68
+ expect((await spriteApplyNetworkPolicy({ id: "d-np", rules, endpoint })).changed).toBe(true);
69
+ expect((await spriteApplyNetworkPolicy({ id: "d-np", rules, endpoint })).changed).toBe(false);
70
+ expect((await inspect("d-np")).netPolicy).toEqual(rules);
71
+ });
72
+
73
+ test("services reconcile creates + starts in dependency order", async (ctx) => {
74
+ if (!available) ctx.skip();
75
+ await spriteCreate({ name: "d-svc", endpoint });
76
+ const r = await spriteApplyServices({
77
+ id: "d-svc",
78
+ start: true,
79
+ endpoint,
80
+ services: [
81
+ { name: "web", cmd: "run-web", needs: ["db"], http_port: 8080 },
82
+ { name: "db", cmd: "run-db" },
83
+ ],
84
+ });
85
+ expect(r.started).toEqual(["db", "web"]);
86
+ expect((await inspect("d-svc")).services.web.state.status).toBe("running");
87
+ });
88
+
89
+ test("keep-alive task holds then releases (idempotent)", async (ctx) => {
90
+ if (!available) ctx.skip();
91
+ await spriteCreate({ name: "d-task", endpoint });
92
+ await spriteTaskCreate({ id: "d-task", name: "session", expire: "5m", endpoint });
93
+ expect(Object.keys((await inspect("d-task")).tasks)).toEqual(["session"]);
94
+ await spriteTaskRelease({ id: "d-task", name: "session", endpoint });
95
+ expect(Object.keys((await inspect("d-task")).tasks)).toEqual([]);
96
+ await expect(spriteTaskRelease({ id: "d-task", name: "session", endpoint })).resolves.toBeDefined();
97
+ });
98
+ });