@tea-agent/loop-agent 0.39.0-next.26 → 0.39.0-next.27

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.
@@ -10,6 +10,18 @@ export const dagNodeExecutorSchema = z.enum(["pi", "shell", "static"]);
10
10
  export const CURSOR_DAG_EXECUTOR_REMOVED_ERROR = 'executor "cursor" is no longer supported; regenerate the DAG with Pi-only writers (implement-pi / repair-pi)';
11
11
  export const CURSOR_EXECUTOR_MODELS_REMOVED_ERROR = "executorModels.cursor is no longer supported; use executorModels.pi only";
12
12
  export const dagToolProfileSchema = z.enum(["read-only", "write"]);
13
+ /**
14
+ * Frozen Pi extension short ids for backend implementation DAGs (plan
15
+ * 2026-08-21 D2): the DAG carries only these ids; the executor resolves them
16
+ * against the Pi settings package inventory at run time. Adding a package
17
+ * requires changing this enum and the plan.
18
+ */
19
+ export const dagPiExtensionIdSchema = z.enum(["pi-codegraph", "pi-lens"]);
20
+ /** Node-level explicit Pi extension allowlist (omitted = all off, R8.1). */
21
+ export const dagPiExtensionsSchema = z
22
+ .array(dagPiExtensionIdSchema)
23
+ .min(1)
24
+ .transform((ids) => Array.from(new Set(ids)));
13
25
  /** Static command capabilities only; tasks cannot inject executables or shell prefixes. */
14
26
  export const dagCommandCapabilitySchema = z.enum(["playwright-cli"]);
15
27
  export const dagCommandPolicySchema = z.discriminatedUnion("mode", [
@@ -753,6 +765,13 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
753
765
  role: dagRoleSchema.optional(),
754
766
  skills: z.array(z.string()).optional(),
755
767
  toolProfile: dagToolProfileSchema.optional(),
768
+ /**
769
+ * Explicit Pi extension allowlist (backend implementation DAGs only):
770
+ * frozen short ids resolved at run time against the Pi settings package
771
+ * inventory. Omitted = extension discovery stays fully closed (R8.1).
772
+ * Only `executor: "pi"` nodes may declare it (validated fail-closed).
773
+ */
774
+ piExtensions: dagPiExtensionsSchema.optional(),
756
775
  /** Default deny: file write (toolProfile=write) does not grant command execution. */
757
776
  commandPolicy: dagCommandPolicySchema.optional(),
758
777
  writePolicy: dagWritePolicySchema.optional(),
@@ -1,4 +1,4 @@
1
- import { DEFAULT_DAG_EXECUTOR_MODELS, ENV_VAR_NAME_PATTERN, dagCommandPolicyAllows, resolveDagCommandPolicy, } from "./types.js";
1
+ import { DEFAULT_DAG_EXECUTOR_MODELS, ENV_VAR_NAME_PATTERN, dagCommandPolicyAllows, dagPiExtensionIdSchema, resolveDagCommandPolicy, } from "./types.js";
2
2
  import { resolveShellCommands } from "../../executors/shell-executor.js";
3
3
  import { pathMatchesPattern } from "../../shared/git-progress.js";
4
4
  import { resolveRepairTaskForGate } from "./repair-artifact.js";
@@ -955,6 +955,7 @@ export function validateDagSpec(spec) {
955
955
  validateCommandPolicyTaskConfig(task, issues);
956
956
  validateDynamicChildCommandPolicy(task, issues);
957
957
  validateProjectGovernanceTaskConfig(task, spec, issues);
958
+ validatePiExtensionsTaskConfig(task, issues);
958
959
  validateFailureAwareDependsOn(task, spec, issues);
959
960
  }
960
961
  validateSameRankWriteSetConflicts(spec, ranks, issues);
@@ -965,6 +966,43 @@ export function validateDagSpec(spec) {
965
966
  }
966
967
  return issues;
967
968
  }
969
+ /**
970
+ * Fail-closed `piExtensions` validation (plan 2026-08-21 D1/D2):
971
+ * - only `executor: "pi"` nodes may declare it (shell/static reject);
972
+ * - unknown ids outside the frozen enum are rejected at parse time by zod,
973
+ * and here for task objects that bypass schema parsing;
974
+ * - closeout nodes must stay fully closed (extension-free) — the two-bucket
975
+ * generator never assigns it there, so any appearance is contract drift.
976
+ */
977
+ function validatePiExtensionsTaskConfig(task, issues) {
978
+ const ids = task.piExtensions;
979
+ if (ids === undefined)
980
+ return;
981
+ if (task.executor !== "pi") {
982
+ issues.push({
983
+ type: "invalid-pi-extensions-config",
984
+ message: `task ${task.id} piExtensions requires executor "pi" (found ${task.executor})`,
985
+ });
986
+ return;
987
+ }
988
+ const allowed = new Set(dagPiExtensionIdSchema.options);
989
+ for (const id of ids) {
990
+ if (!allowed.has(id)) {
991
+ issues.push({
992
+ type: "invalid-pi-extensions-config",
993
+ message: `task ${task.id} piExtensions has unknown id "${id}"; allowed: ${[
994
+ ...allowed,
995
+ ].join(", ")}`,
996
+ });
997
+ }
998
+ }
999
+ if (task.id === "closeout-pi" && ids.length > 0) {
1000
+ issues.push({
1001
+ type: "invalid-pi-extensions-config",
1002
+ message: "closeout-pi must stay extension-free (read buckets exclude closeout)",
1003
+ });
1004
+ }
1005
+ }
968
1006
  function validateProjectGovernanceTaskConfig(task, spec, issues) {
969
1007
  if (task.governanceStandardReview) {
970
1008
  if (task.executor !== "pi" ||
@@ -130,6 +130,18 @@
130
130
  "toolProfile": {
131
131
  "enum": ["read-only", "write"]
132
132
  },
133
+ "piExtensionId": {
134
+ "type": "string",
135
+ "enum": ["pi-codegraph", "pi-lens"],
136
+ "description": "Frozen Pi extension short id resolved at run time against the Pi settings package inventory. Adding a package requires changing the plan and this enum."
137
+ },
138
+ "piExtensions": {
139
+ "type": "array",
140
+ "minItems": 1,
141
+ "uniqueItems": true,
142
+ "items": { "$ref": "#/$defs/piExtensionId" },
143
+ "description": "Node-level explicit Pi extension allowlist (backend implementation DAGs only). Omitted = extension discovery stays fully closed (R8.1). Only executor 'pi' nodes may declare it."
144
+ },
133
145
  "role": {
134
146
  "enum": ["planner", "scout", "implementer", "reviewer", "supervisor", "verifier", "closeout"]
135
147
  },
@@ -516,6 +528,7 @@
516
528
  "items": { "type": "string", "minLength": 1 }
517
529
  },
518
530
  "toolProfile": { "$ref": "#/$defs/toolProfile" },
531
+ "piExtensions": { "$ref": "#/$defs/piExtensions" },
519
532
  "governanceStandardReview": {
520
533
  "type": "boolean",
521
534
  "description": "Explicitly opts this node into writer-change-scoped AGENTS.md and repository-local code-standard review. Never inferred from node id or role."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.39.0-next.26",
3
+ "version": "0.39.0-next.27",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",