@intentius/chant-lexicon-e2b 0.0.0-stage → 0.124.32

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 (123) hide show
  1. package/README.md +147 -2
  2. package/dist/catalog.d.ts +19 -0
  3. package/dist/catalog.d.ts.map +1 -0
  4. package/dist/catalog.js +58 -0
  5. package/dist/codegen/docs-cli.d.ts +3 -0
  6. package/dist/codegen/docs-cli.d.ts.map +1 -0
  7. package/dist/codegen/docs-cli.js +6 -0
  8. package/dist/codegen/docs.d.ts +15 -0
  9. package/dist/codegen/docs.d.ts.map +1 -0
  10. package/dist/codegen/docs.js +123 -0
  11. package/dist/codegen/generate-cli.d.ts +3 -0
  12. package/dist/codegen/generate-cli.d.ts.map +1 -0
  13. package/dist/codegen/generate-cli.js +4 -0
  14. package/dist/codegen/generate.d.ts +11 -0
  15. package/dist/codegen/generate.d.ts.map +1 -0
  16. package/dist/codegen/generate.js +20 -0
  17. package/dist/codegen/package.d.ts +10 -0
  18. package/dist/codegen/package.d.ts.map +1 -0
  19. package/dist/codegen/package.js +34 -0
  20. package/dist/config.d.ts +113 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +82 -0
  23. package/dist/index.d.ts +7 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +6 -0
  26. package/dist/integrity.json +15 -0
  27. package/dist/lint/audit-catalog.d.ts +11 -0
  28. package/dist/lint/audit-catalog.d.ts.map +1 -0
  29. package/dist/lint/audit-catalog.js +15 -0
  30. package/dist/lint/post-synth/e2b011-template-name.d.ts +12 -0
  31. package/dist/lint/post-synth/e2b011-template-name.d.ts.map +1 -0
  32. package/dist/lint/post-synth/e2b011-template-name.js +48 -0
  33. package/dist/lint/post-synth/e2b012-steward-tools.d.ts +20 -0
  34. package/dist/lint/post-synth/e2b012-steward-tools.d.ts.map +1 -0
  35. package/dist/lint/post-synth/e2b012-steward-tools.js +53 -0
  36. package/dist/lint/post-synth/index.d.ts +3 -0
  37. package/dist/lint/post-synth/index.d.ts.map +1 -0
  38. package/dist/lint/post-synth/index.js +6 -0
  39. package/dist/lint/rules/index.d.ts +6 -0
  40. package/dist/lint/rules/index.d.ts.map +1 -0
  41. package/dist/lint/rules/index.js +6 -0
  42. package/dist/lint/rules/pinned-image.d.ts +14 -0
  43. package/dist/lint/rules/pinned-image.d.ts.map +1 -0
  44. package/dist/lint/rules/pinned-image.js +36 -0
  45. package/dist/lint/rules/template-literal.d.ts +11 -0
  46. package/dist/lint/rules/template-literal.d.ts.map +1 -0
  47. package/dist/lint/rules/template-literal.js +39 -0
  48. package/dist/lint/rules/template-size.d.ts +10 -0
  49. package/dist/lint/rules/template-size.d.ts.map +1 -0
  50. package/dist/lint/rules/template-size.js +31 -0
  51. package/dist/lsp/completions.d.ts +7 -0
  52. package/dist/lsp/completions.d.ts.map +1 -0
  53. package/dist/lsp/completions.js +10 -0
  54. package/dist/lsp/hover.d.ts +7 -0
  55. package/dist/lsp/hover.d.ts.map +1 -0
  56. package/dist/lsp/hover.js +30 -0
  57. package/dist/manifest.json +6 -0
  58. package/dist/meta.json +45 -0
  59. package/dist/okf/index.md +14 -0
  60. package/dist/okf/rules/E2B001.md +15 -0
  61. package/dist/okf/rules/E2B002.md +15 -0
  62. package/dist/okf/rules/E2B011.md +15 -0
  63. package/dist/okf/rules/E2B012.md +15 -0
  64. package/dist/okf/types/Template.md +16 -0
  65. package/dist/op/runtime.d.ts +119 -0
  66. package/dist/op/runtime.d.ts.map +1 -0
  67. package/dist/op/runtime.js +522 -0
  68. package/dist/op/sandbox.d.ts +67 -0
  69. package/dist/op/sandbox.d.ts.map +1 -0
  70. package/dist/op/sandbox.js +87 -0
  71. package/dist/package-cli.d.ts +3 -0
  72. package/dist/package-cli.d.ts.map +1 -0
  73. package/dist/package-cli.js +14 -0
  74. package/dist/plugin.d.ts +12 -0
  75. package/dist/plugin.d.ts.map +1 -0
  76. package/dist/plugin.js +66 -0
  77. package/dist/resources.d.ts +38 -0
  78. package/dist/resources.d.ts.map +1 -0
  79. package/dist/resources.js +21 -0
  80. package/dist/rules/e2b011-template-name.ts +51 -0
  81. package/dist/rules/e2b012-steward-tools.ts +58 -0
  82. package/dist/rules/pinned-image.ts +41 -0
  83. package/dist/rules/template-literal.ts +42 -0
  84. package/dist/rules/template-size.ts +36 -0
  85. package/dist/serializer.d.ts +18 -0
  86. package/dist/serializer.d.ts.map +1 -0
  87. package/dist/serializer.js +70 -0
  88. package/dist/skills/chant-e2b-ops.md +69 -0
  89. package/dist/types/index.d.ts +1 -0
  90. package/package.json +67 -4
  91. package/src/catalog.ts +72 -0
  92. package/src/codegen/docs-cli.ts +7 -0
  93. package/src/codegen/docs.ts +130 -0
  94. package/src/codegen/generate-cli.ts +5 -0
  95. package/src/codegen/generate.ts +22 -0
  96. package/src/codegen/package.ts +39 -0
  97. package/src/config.ts +102 -0
  98. package/src/index.ts +6 -0
  99. package/src/lint/audit-catalog.ts +29 -0
  100. package/src/lint/post-synth/e2b011-template-name.ts +51 -0
  101. package/src/lint/post-synth/e2b012-steward-tools.ts +58 -0
  102. package/src/lint/post-synth/index.ts +9 -0
  103. package/src/lint/post-synth/post-synth.test.ts +59 -0
  104. package/src/lint/rules/index.ts +9 -0
  105. package/src/lint/rules/pinned-image.ts +41 -0
  106. package/src/lint/rules/rules.test.ts +46 -0
  107. package/src/lint/rules/template-literal.ts +42 -0
  108. package/src/lint/rules/template-size.ts +36 -0
  109. package/src/lsp/completions.test.ts +23 -0
  110. package/src/lsp/completions.ts +13 -0
  111. package/src/lsp/hover.test.ts +29 -0
  112. package/src/lsp/hover.ts +35 -0
  113. package/src/op/ledger-sync.test.ts +136 -0
  114. package/src/op/runtime.test.ts +394 -0
  115. package/src/op/runtime.ts +573 -0
  116. package/src/op/sandbox.ts +138 -0
  117. package/src/package-cli.ts +16 -0
  118. package/src/plugin.test.ts +39 -0
  119. package/src/plugin.ts +79 -0
  120. package/src/resources.ts +50 -0
  121. package/src/serializer.test.ts +88 -0
  122. package/src/serializer.ts +73 -0
  123. package/src/skills/chant-e2b-ops.md +69 -0
package/dist/config.js ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The `e2b` namespace in `chant.config.ts`.
3
+ *
4
+ * ```ts
5
+ * import type { ChantConfig } from "@intentius/chant/config";
6
+ * import "@intentius/chant-lexicon-e2b"; // brings the `e2b` key into ChantConfig
7
+ *
8
+ * export default {
9
+ * lexicons: ["e2b"],
10
+ * e2b: {
11
+ * profiles: {
12
+ * prod: {
13
+ * apiKey: { env: "E2B_API_KEY" },
14
+ * domain: "e2b.loam.example.com", // omit for hosted E2B
15
+ * steward: "prod-steward",
16
+ * gitToken: { env: "GITHUB_TOKEN" },
17
+ * },
18
+ * },
19
+ * defaultProfile: "prod",
20
+ * },
21
+ * } satisfies ChantConfig;
22
+ * ```
23
+ *
24
+ * One schema, three consumers, as for fountain's namespace: core validates the
25
+ * namespace against it at load, the type below is derived from it, and that
26
+ * type augments `ChantConfig`. A project with no `e2b.profiles` keeps working:
27
+ * the runtime falls back to `E2B_API_KEY`, `E2B_DOMAIN` and `CHANT_GIT_TOKEN`.
28
+ */
29
+ import { z } from "zod";
30
+ /** A secret named by its environment variable, never a literal value. */
31
+ const envRef = z.strictObject({ env: z.string() });
32
+ export const e2bProfileSchema = z.strictObject({
33
+ /** The E2B API key, by environment variable. Default `E2B_API_KEY`. */
34
+ apiKey: envRef.optional(),
35
+ /**
36
+ * The E2B domain the SDK talks to: `api.<domain>` and `<port>-<id>.<domain>`.
37
+ * Omitted, the SDK's own default (hosted E2B, or `E2B_DOMAIN`).
38
+ */
39
+ domain: z.string().optional(),
40
+ /** The template a steward's sandbox is made from. Default `base`. It needs git and Node. */
41
+ template: z.string().optional(),
42
+ /**
43
+ * The steward's name: the one sandbox every run of this profile lands on,
44
+ * found again by its `chant/steward` metadata. Default: the repository's name.
45
+ */
46
+ steward: z.string().optional(),
47
+ /**
48
+ * The repository the sandbox clones, as an https URL. Default: `origin`'s
49
+ * URL, with an ssh URL rewritten to https.
50
+ */
51
+ repo: z.string().optional(),
52
+ /**
53
+ * A token for that repository, by environment variable, so the sandbox can
54
+ * fetch a private repo and push chant's ledger branch. It is handed to each
55
+ * command in the sandbox and never written to its disk.
56
+ */
57
+ gitToken: envRef.optional(),
58
+ });
59
+ export const e2bConfigSchema = z.strictObject({
60
+ profiles: z.record(z.string(), e2bProfileSchema).optional(),
61
+ /** Profile used when a run names none. */
62
+ defaultProfile: z.string().optional(),
63
+ });
64
+ /**
65
+ * The named profile, else `defaultProfile`, else `undefined`. A name that is
66
+ * not declared is an error rather than a fall back to the default: running
67
+ * against the wrong steward because a profile name was misspelt is the one
68
+ * mistake a runtime must not make.
69
+ */
70
+ export function resolveProfile(config, name) {
71
+ const profiles = config?.e2b?.profiles;
72
+ if (name !== undefined) {
73
+ const named = profiles?.[name];
74
+ if (!named) {
75
+ throw new Error(`e2b runtime: no profile "${name}" under e2b.profiles in chant.config.ts. ` +
76
+ `Declare it, or drop --profile to use e2b.defaultProfile.`);
77
+ }
78
+ return named;
79
+ }
80
+ const fallback = config?.e2b?.defaultProfile;
81
+ return fallback !== undefined ? profiles?.[fallback] : undefined;
82
+ }
@@ -0,0 +1,7 @@
1
+ export { e2bPlugin } from "./plugin.js";
2
+ export { e2bSerializer } from "./serializer.js";
3
+ export { Template, type TemplateProps } from "./resources.js";
4
+ export { e2bConfigSchema, e2bProfileSchema, resolveProfile, type E2bConfig, type E2bProfile } from "./config.js";
5
+ export { createE2bOpRuntime, type E2bOpRuntimeOptions } from "./op/runtime.js";
6
+ export { e2bSandboxes, STEWARD_METADATA_KEY, type StewardSandbox, type StewardSandboxes } from "./op/sandbox.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC9G,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { e2bPlugin } from "./plugin.js";
2
+ export { e2bSerializer } from "./serializer.js";
3
+ export { Template } from "./resources.js";
4
+ export { e2bConfigSchema, e2bProfileSchema, resolveProfile } from "./config.js";
5
+ export { createE2bOpRuntime } from "./op/runtime.js";
6
+ export { e2bSandboxes, STEWARD_METADATA_KEY } from "./op/sandbox.js";
@@ -0,0 +1,15 @@
1
+ {
2
+ "algorithm": "sha256",
3
+ "artifacts": {
4
+ "manifest.json": "fd36bde57f75482471fbc6444daf3b190f9b7ffcadba72e5fad1a419328aac9c",
5
+ "meta.json": "324b605d8aa8c5fae317aad1f0fa1afb3704e2586ffb8bb958dd868d8cf5b6ae",
6
+ "types/index.d.ts": "1a79ae1697e6c89fa1d79443c17791366bac50baf7dff00d3c6fbb2260800798",
7
+ "rules/pinned-image.ts": "a93030b2694e552c2f7565edef9117216067e3b68138ed95aad46e1e06c0bdd8",
8
+ "rules/template-literal.ts": "4da6b9e62e92f0db34410f9a806a6c2e1894bab37618988b1a7d7a127958f1d6",
9
+ "rules/template-size.ts": "035c28ce063c447dee2e2dc46f2426ab542998257eb08c15d6c69d5c5512af7b",
10
+ "rules/e2b011-template-name.ts": "3b9af285d5d658538f948a9bf9d74eea149c6933861b38c008d9a887f68711d4",
11
+ "rules/e2b012-steward-tools.ts": "1e4e1a93b80b939c3a2135ba43493e4d9b8552f71e5fe9c0ca71dae7fa49842e",
12
+ "skills/chant-e2b-ops.md": "8e6ae4c8af6a724501c5363d7fa3a4adf85537788529a6039d6857b2865889e7"
13
+ },
14
+ "composite": "2b10b0b5337aa1febb3718cdd2e8dc8d155afae40a415ff9d6a9a1cc01efb092"
15
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The e2b lexicon's chant audit catalog: metadata for the E2B post-synth
3
+ * checks, contributed via `e2bPlugin.auditCatalog()`.
4
+ *
5
+ * Every check reads the chant model (`ctx.entities`), not the emitted files,
6
+ * so they fire on `chant build` and not on an audit of a hand-written
7
+ * `e2b.Dockerfile`.
8
+ */
9
+ import type { RuleMeta } from "@intentius/chant/audit/catalog";
10
+ export declare const e2bAuditCatalog: Record<string, RuleMeta>;
11
+ //# sourceMappingURL=audit-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-catalog.d.ts","sourceRoot":"","sources":["../../src/lint/audit-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAM/D,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAapD,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The e2b lexicon's chant audit catalog: metadata for the E2B post-synth
3
+ * checks, contributed via `e2bPlugin.auditCatalog()`.
4
+ *
5
+ * Every check reads the chant model (`ctx.entities`), not the emitted files,
6
+ * so they fire on `chant build` and not on an audit of a hand-written
7
+ * `e2b.Dockerfile`.
8
+ */
9
+ function rule(id, tier, title, remediation) {
10
+ return { id, tier, fixKind: "guidance", category: "correctness", title, remediation, yamlBased: false };
11
+ }
12
+ export const e2bAuditCatalog = {
13
+ E2B011: rule("E2B011", "merge-worthy", "Template name is not one E2B accepts, or two templates share it", "Name the template with lowercase letters, digits, dashes and underscores, and give each template its own name."),
14
+ E2B012: rule("E2B012", "report-only", "Template shows no sign of git or Node", "Start from a `node` image, or add a `run` step that installs git and Node."),
15
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * E2B011: a template's name is one E2B accepts, and only one template has it.
3
+ *
4
+ * E2B names templates with lowercase letters, digits, dashes and underscores;
5
+ * `e2b template create` refuses anything else. The name is also the profile's
6
+ * `template` and the stem of the Dockerfile the serializer writes, so two
7
+ * templates with one name would overwrite each other's file.
8
+ */
9
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
10
+ export declare const TEMPLATE_NAME: RegExp;
11
+ export declare const e2b011: PostSynthCheck;
12
+ //# sourceMappingURL=e2b011-template-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2b011-template-name.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/e2b011-template-name.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAG9G,eAAO,MAAM,aAAa,QAAkB,CAAC;AAE7C,eAAO,MAAM,MAAM,EAAE,cAoCpB,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * E2B011: a template's name is one E2B accepts, and only one template has it.
3
+ *
4
+ * E2B names templates with lowercase letters, digits, dashes and underscores;
5
+ * `e2b template create` refuses anything else. The name is also the profile's
6
+ * `template` and the stem of the Dockerfile the serializer writes, so two
7
+ * templates with one name would overwrite each other's file.
8
+ */
9
+ import { templateProps } from "../../resources.js";
10
+ export const TEMPLATE_NAME = /^[a-z0-9_-]+$/;
11
+ export const e2b011 = {
12
+ id: "E2B011",
13
+ description: "A Template's name must be lowercase letters, digits, dashes and underscores, and unique",
14
+ check(ctx) {
15
+ const diagnostics = [];
16
+ const seen = new Map();
17
+ for (const [entityName, entity] of ctx.entities) {
18
+ const props = templateProps(entity);
19
+ if (!props)
20
+ continue;
21
+ const name = props.name;
22
+ if (typeof name !== "string" || !TEMPLATE_NAME.test(name)) {
23
+ diagnostics.push({
24
+ checkId: "E2B011",
25
+ severity: "error",
26
+ message: `Template "${entityName}" has name ${JSON.stringify(name)}. E2B template names are lowercase letters, digits, dashes and underscores.`,
27
+ entity: entityName,
28
+ lexicon: "e2b",
29
+ });
30
+ continue;
31
+ }
32
+ const first = seen.get(name);
33
+ if (first !== undefined) {
34
+ diagnostics.push({
35
+ checkId: "E2B011",
36
+ severity: "error",
37
+ message: `Templates "${first}" and "${entityName}" are both named "${name}"; their e2b.${name}.Dockerfile files would overwrite each other.`,
38
+ entity: entityName,
39
+ lexicon: "e2b",
40
+ });
41
+ }
42
+ else {
43
+ seen.set(name, entityName);
44
+ }
45
+ }
46
+ return diagnostics;
47
+ },
48
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * E2B012: a template has the git and Node a steward needs.
3
+ *
4
+ * The runtime clones the repository with git and runs the project's own chant
5
+ * with Node, and it stops a run at once on a sandbox that lacks either. This
6
+ * check looks for both in the declaration: Node from a `node` image or a
7
+ * step that installs it, git from a full (not `-slim` or `-alpine`) `node` image, which
8
+ * ships it, or a step that installs it. It cannot see inside other images, so
9
+ * it warns rather than fails: a template from an image that already has both
10
+ * can say so with a `run` step such as `git --version && node --version`.
11
+ */
12
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
13
+ import { type TemplateProps } from "../../resources.js";
14
+ /** Which of git and Node the declaration visibly provides. */
15
+ export declare function stewardTools(props: TemplateProps): {
16
+ git: boolean;
17
+ node: boolean;
18
+ };
19
+ export declare const e2b012: PostSynthCheck;
20
+ //# sourceMappingURL=e2b012-steward-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2b012-steward-tools.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/e2b012-steward-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAC9G,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AASpE,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAQlF;AAED,eAAO,MAAM,MAAM,EAAE,cAwBpB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * E2B012: a template has the git and Node a steward needs.
3
+ *
4
+ * The runtime clones the repository with git and runs the project's own chant
5
+ * with Node, and it stops a run at once on a sandbox that lacks either. This
6
+ * check looks for both in the declaration: Node from a `node` image or a
7
+ * step that installs it, git from a full (not `-slim` or `-alpine`) `node` image, which
8
+ * ships it, or a step that installs it. It cannot see inside other images, so
9
+ * it warns rather than fails: a template from an image that already has both
10
+ * can say so with a `run` step such as `git --version && node --version`.
11
+ */
12
+ import { templateProps } from "../../resources.js";
13
+ function imageRepoAndTag(image) {
14
+ const ref = image.toLowerCase().split("@")[0];
15
+ const segment = ref.slice(ref.lastIndexOf("/") + 1);
16
+ const [repo, tag = ""] = segment.split(":");
17
+ return { repo, tag };
18
+ }
19
+ /** Which of git and Node the declaration visibly provides. */
20
+ export function stewardTools(props) {
21
+ const { repo, tag } = imageRepoAndTag(props.fromImage ?? "");
22
+ const steps = (props.run ?? []).join("\n");
23
+ const nodeImage = repo === "node";
24
+ return {
25
+ node: nodeImage || /\b(nodejs|node|nvm|fnm|volta)\b/.test(steps),
26
+ git: (nodeImage && !/slim|alpine/.test(tag)) || /\bgit\b/.test(steps),
27
+ };
28
+ }
29
+ export const e2b012 = {
30
+ id: "E2B012",
31
+ description: "A Template a steward runs on needs git and Node",
32
+ check(ctx) {
33
+ const diagnostics = [];
34
+ for (const [name, entity] of ctx.entities) {
35
+ const props = templateProps(entity);
36
+ if (!props)
37
+ continue;
38
+ const tools = stewardTools(props);
39
+ const missing = [tools.git ? undefined : "git", tools.node ? undefined : "Node"].filter((t) => t !== undefined);
40
+ if (missing.length === 0)
41
+ continue;
42
+ diagnostics.push({
43
+ checkId: "E2B012",
44
+ severity: "warning",
45
+ message: `Template "${name}" shows no sign of ${missing.join(" or ")}. A steward needs both; ` +
46
+ `start from a node image or add a run step that installs ${missing.length === 2 ? "them" : "it"}.`,
47
+ entity: name,
48
+ lexicon: "e2b",
49
+ });
50
+ }
51
+ return diagnostics;
52
+ },
53
+ };
@@ -0,0 +1,3 @@
1
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
2
+ export declare const postSynthChecks: PostSynthCheck[];
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAIvE,eAAO,MAAM,eAAe,EAAE,cAAc,EAG3C,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { e2b011 } from "./e2b011-template-name.js";
2
+ import { e2b012 } from "./e2b012-steward-tools.js";
3
+ export const postSynthChecks = [
4
+ e2b011,
5
+ e2b012,
6
+ ];
@@ -0,0 +1,6 @@
1
+ import type { LintRule } from "@intentius/chant/lint/rule";
2
+ export { templateSizeRule } from "./template-size.js";
3
+ export { pinnedImageRule, isFloatingImage } from "./pinned-image.js";
4
+ /** All lint rules the e2b lexicon provides. */
5
+ export declare const rules: LintRule[];
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAI3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAElE,+CAA+C;AAC/C,eAAO,MAAM,KAAK,EAAE,QAAQ,EAAwC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { templateSizeRule } from "./template-size.js";
2
+ import { pinnedImageRule } from "./pinned-image.js";
3
+ export { templateSizeRule } from "./template-size.js";
4
+ export { pinnedImageRule, isFloatingImage } from "./pinned-image.js";
5
+ /** All lint rules the e2b lexicon provides. */
6
+ export const rules = [templateSizeRule, pinnedImageRule];
@@ -0,0 +1,14 @@
1
+ import type { LintRule } from "@intentius/chant/lint/rule";
2
+ /** An image reference with no tag or digest, or the `latest` tag. */
3
+ export declare function isFloatingImage(image: string): boolean;
4
+ /**
5
+ * E2B002: A template's base image is pinned.
6
+ *
7
+ * A steward keeps one sandbox for months, but a template is rebuilt whenever
8
+ * someone runs `e2b template create`. With `fromImage` untagged or on `latest`,
9
+ * two builds of the same declaration can carry different Node or git
10
+ * versions, and a steward made from the second behaves differently with no
11
+ * change in the repository.
12
+ */
13
+ export declare const pinnedImageRule: LintRule;
14
+ //# sourceMappingURL=pinned-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-image.d.ts","sourceRoot":"","sources":["../../../src/lint/rules/pinned-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAA+B,MAAM,4BAA4B,CAAC;AAIxF,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKtD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,QAmB7B,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { ts } from "@intentius/chant/lint/typescript";
2
+ import { at, property, templateLiterals } from "./template-literal.js";
3
+ /** An image reference with no tag or digest, or the `latest` tag. */
4
+ export function isFloatingImage(image) {
5
+ if (image.includes("@"))
6
+ return false;
7
+ const lastSegment = image.slice(image.lastIndexOf("/") + 1);
8
+ const colon = lastSegment.indexOf(":");
9
+ return colon === -1 || lastSegment.slice(colon + 1) === "latest";
10
+ }
11
+ /**
12
+ * E2B002: A template's base image is pinned.
13
+ *
14
+ * A steward keeps one sandbox for months, but a template is rebuilt whenever
15
+ * someone runs `e2b template create`. With `fromImage` untagged or on `latest`,
16
+ * two builds of the same declaration can carry different Node or git
17
+ * versions, and a steward made from the second behaves differently with no
18
+ * change in the repository.
19
+ */
20
+ export const pinnedImageRule = {
21
+ id: "E2B002",
22
+ severity: "warning",
23
+ category: "correctness",
24
+ description: "A Template's fromImage should name a tag other than latest, or a digest",
25
+ check(context) {
26
+ const { sourceFile } = context;
27
+ const diagnostics = [];
28
+ for (const obj of templateLiterals(sourceFile)) {
29
+ const image = property(obj, "fromImage", sourceFile);
30
+ if (image && ts.isStringLiteralLike(image) && image.text.length > 0 && isFloatingImage(image.text)) {
31
+ diagnostics.push(at(sourceFile, image, "E2B002", "warning", `fromImage "${image.text}" is not pinned; name a version tag such as node:22-bookworm, or a digest.`));
32
+ }
33
+ }
34
+ return diagnostics;
35
+ },
36
+ };
@@ -0,0 +1,11 @@
1
+ /** Helpers the e2b lint rules share: finding `new Template({...})` literals and reporting on them. */
2
+ import type { LintDiagnostic } from "@intentius/chant/lint/rule";
3
+ import { ts } from "@intentius/chant/lint/typescript";
4
+ /** The object literal passed to each `new Template({...})` in the file. */
5
+ export declare function templateLiterals(sourceFile: ts.SourceFile): ts.ObjectLiteralExpression[];
6
+ /** The initializer of `key` in an object literal, when it is written there. */
7
+ export declare function property(obj: ts.ObjectLiteralExpression, key: string, sourceFile: ts.SourceFile): ts.Expression | undefined;
8
+ /** A numeric literal's value, a negated one included; `undefined` for anything computed. */
9
+ export declare function numberLiteral(expr: ts.Expression): number | undefined;
10
+ export declare function at(sourceFile: ts.SourceFile, node: ts.Node, ruleId: string, severity: LintDiagnostic["severity"], message: string): LintDiagnostic;
11
+ //# sourceMappingURL=template-literal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-literal.d.ts","sourceRoot":"","sources":["../../../src/lint/rules/template-literal.ts"],"names":[],"mappings":"AAAA,sGAAsG;AAEtG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,kCAAkC,CAAC;AAEtD,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,uBAAuB,EAAE,CAaxF;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,GAAG,SAAS,CAK3H;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAMrE;AAED,wBAAgB,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAGlJ"}
@@ -0,0 +1,39 @@
1
+ /** Helpers the e2b lint rules share: finding `new Template({...})` literals and reporting on them. */
2
+ import { ts } from "@intentius/chant/lint/typescript";
3
+ /** The object literal passed to each `new Template({...})` in the file. */
4
+ export function templateLiterals(sourceFile) {
5
+ const found = [];
6
+ function visit(node) {
7
+ if (ts.isNewExpression(node)) {
8
+ const callee = node.expression;
9
+ const name = ts.isIdentifier(callee) ? callee.text : ts.isPropertyAccessExpression(callee) ? callee.name.text : "";
10
+ const arg = node.arguments?.[0];
11
+ if (name === "Template" && arg && ts.isObjectLiteralExpression(arg))
12
+ found.push(arg);
13
+ }
14
+ ts.forEachChild(node, visit);
15
+ }
16
+ visit(sourceFile);
17
+ return found;
18
+ }
19
+ /** The initializer of `key` in an object literal, when it is written there. */
20
+ export function property(obj, key, sourceFile) {
21
+ for (const p of obj.properties) {
22
+ if (ts.isPropertyAssignment(p) && p.name.getText(sourceFile) === key)
23
+ return p.initializer;
24
+ }
25
+ return undefined;
26
+ }
27
+ /** A numeric literal's value, a negated one included; `undefined` for anything computed. */
28
+ export function numberLiteral(expr) {
29
+ if (ts.isNumericLiteral(expr))
30
+ return Number(expr.text);
31
+ if (ts.isPrefixUnaryExpression(expr) && expr.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(expr.operand)) {
32
+ return -Number(expr.operand.text);
33
+ }
34
+ return undefined;
35
+ }
36
+ export function at(sourceFile, node, ruleId, severity, message) {
37
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
38
+ return { file: sourceFile.fileName, line: line + 1, column: character + 1, ruleId, severity, message };
39
+ }
@@ -0,0 +1,10 @@
1
+ import type { LintRule } from "@intentius/chant/lint/rule";
2
+ /**
3
+ * E2B001: A template's CPU and memory are sizes E2B accepts.
4
+ *
5
+ * `cpuCount` is a whole number of vCPUs, at least one. `memoryMB` is a whole
6
+ * number of MiB, at least one and even: `e2b template create` refuses an odd
7
+ * one. Both are only checked when written as literals.
8
+ */
9
+ export declare const templateSizeRule: LintRule;
10
+ //# sourceMappingURL=template-size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-size.d.ts","sourceRoot":"","sources":["../../../src/lint/rules/template-size.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAA+B,MAAM,4BAA4B,CAAC;AAGxF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAyB9B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { at, numberLiteral, property, templateLiterals } from "./template-literal.js";
2
+ /**
3
+ * E2B001: A template's CPU and memory are sizes E2B accepts.
4
+ *
5
+ * `cpuCount` is a whole number of vCPUs, at least one. `memoryMB` is a whole
6
+ * number of MiB, at least one and even: `e2b template create` refuses an odd
7
+ * one. Both are only checked when written as literals.
8
+ */
9
+ export const templateSizeRule = {
10
+ id: "E2B001",
11
+ severity: "error",
12
+ category: "correctness",
13
+ description: "A Template's cpuCount must be a positive integer and its memoryMB a positive even integer",
14
+ check(context) {
15
+ const { sourceFile } = context;
16
+ const diagnostics = [];
17
+ for (const obj of templateLiterals(sourceFile)) {
18
+ const cpu = property(obj, "cpuCount", sourceFile);
19
+ const cpuValue = cpu ? numberLiteral(cpu) : undefined;
20
+ if (cpu && cpuValue !== undefined && !(Number.isInteger(cpuValue) && cpuValue >= 1)) {
21
+ diagnostics.push(at(sourceFile, cpu, "E2B001", "error", `cpuCount ${cpuValue} is not a whole number of vCPUs; use 1 or more.`));
22
+ }
23
+ const mem = property(obj, "memoryMB", sourceFile);
24
+ const memValue = mem ? numberLiteral(mem) : undefined;
25
+ if (mem && memValue !== undefined && !(Number.isInteger(memValue) && memValue >= 2 && memValue % 2 === 0)) {
26
+ diagnostics.push(at(sourceFile, mem, "E2B001", "error", `memoryMB ${memValue} is not a positive even number of MiB, which E2B requires.`));
27
+ }
28
+ }
29
+ return diagnostics;
30
+ },
31
+ };
@@ -0,0 +1,7 @@
1
+ import type { CompletionContext, CompletionItem } from "@intentius/chant/lsp/types";
2
+ /**
3
+ * e2b completions: `Template` after `new`, and its properties inside the
4
+ * object passed to it.
5
+ */
6
+ export declare function completions(ctx: CompletionContext): CompletionItem[];
7
+ //# sourceMappingURL=completions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completions.d.ts","sourceRoot":"","sources":["../../src/lsp/completions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAMpF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAEpE"}
@@ -0,0 +1,10 @@
1
+ import { LexiconIndex, lexiconCompletions } from "@intentius/chant/lsp/lexicon-providers";
2
+ import { LEXICON_ENTRIES } from "../catalog.js";
3
+ const index = new LexiconIndex(LEXICON_ENTRIES);
4
+ /**
5
+ * e2b completions: `Template` after `new`, and its properties inside the
6
+ * object passed to it.
7
+ */
8
+ export function completions(ctx) {
9
+ return lexiconCompletions(ctx, index, "E2B sandbox template");
10
+ }
@@ -0,0 +1,7 @@
1
+ import type { HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
2
+ /**
3
+ * e2b hover: the `Template` class, with its properties and what it builds
4
+ * into, and each of its properties by name.
5
+ */
6
+ export declare function hover(ctx: HoverContext): HoverInfo | undefined;
7
+ //# sourceMappingURL=hover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../src/lsp/hover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAG1E;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,CA2B9D"}
@@ -0,0 +1,30 @@
1
+ import { LEXICON_ENTRIES, TEMPLATE_PROPERTIES } from "../catalog.js";
2
+ /**
3
+ * e2b hover: the `Template` class, with its properties and what it builds
4
+ * into, and each of its properties by name.
5
+ */
6
+ export function hover(ctx) {
7
+ const { word } = ctx;
8
+ if (!word)
9
+ return undefined;
10
+ const entry = LEXICON_ENTRIES[word];
11
+ if (entry) {
12
+ const lines = [
13
+ `**${word}**`,
14
+ "",
15
+ `E2B type: \`${entry.resourceType}\``,
16
+ "",
17
+ "*A sandbox template, written out as `e2b.<name>.Dockerfile` and built with `e2b template create`.*",
18
+ "",
19
+ ...Object.entries(TEMPLATE_PROPERTIES).map(([name, p]) => `- \`${name}${p.required ? "" : "?"}: ${p.type}\`: ${p.description}`),
20
+ ];
21
+ return { contents: lines.join("\n") };
22
+ }
23
+ // A property name only means a Template property on a line that builds one
24
+ // or inside its object, so the hover stays quiet on an unrelated `name`.
25
+ const prop = TEMPLATE_PROPERTIES[word];
26
+ if (prop && /\bTemplate\b|^\s*\w+\??\s*:/.test(ctx.lineText ?? "") && ctx.content.includes("Template")) {
27
+ return { contents: `**${word}**${prop.required ? "" : " (optional)"}: \`${prop.type}\`\n\n${prop.description}` };
28
+ }
29
+ return undefined;
30
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "e2b",
3
+ "version": "0.124.32",
4
+ "chantVersion": ">=0.1.0",
5
+ "namespace": "E2B"
6
+ }
package/dist/meta.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "Template": {
3
+ "resourceType": "E2B::Template",
4
+ "kind": "resource",
5
+ "lexicon": "e2b",
6
+ "propertyConstraints": {
7
+ "name": {
8
+ "type": "string",
9
+ "required": true
10
+ },
11
+ "fromImage": {
12
+ "type": "string",
13
+ "required": true
14
+ },
15
+ "run": {
16
+ "type": "string[]",
17
+ "required": false
18
+ },
19
+ "env": {
20
+ "type": "Record<string, string>",
21
+ "required": false
22
+ },
23
+ "workdir": {
24
+ "type": "string",
25
+ "required": false
26
+ },
27
+ "startCmd": {
28
+ "type": "string",
29
+ "required": false
30
+ },
31
+ "readyCmd": {
32
+ "type": "string",
33
+ "required": false
34
+ },
35
+ "cpuCount": {
36
+ "type": "number",
37
+ "required": false
38
+ },
39
+ "memoryMB": {
40
+ "type": "number",
41
+ "required": false
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ okf_version: '0.2'
3
+ ---
4
+
5
+ # Resource types
6
+
7
+ * [Template](/types/Template.md) - E2B::Template
8
+
9
+ # Rules
10
+
11
+ * [E2B001](/rules/E2B001.md) - A template's CPU and memory are sizes E2B accepts.
12
+ * [E2B002](/rules/E2B002.md) - A template's base image is pinned.
13
+ * [E2B011](/rules/E2B011.md) - A Template's name must be lowercase letters, digits, dashes and underscores, and unique
14
+ * [E2B012](/rules/E2B012.md) - A Template a steward runs on needs git and Node