@awebai/oats 0.42.0 → 0.43.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/lib/triggers.mjs CHANGED
@@ -30,7 +30,7 @@ import { dirname, join } from "node:path";
30
30
  import { fileURLToPath } from "node:url";
31
31
  import { readDefinitions, writeDefinitions, stateDir, withScopeLock, childEnv, parseEnvelopeText, schedulerStatus, readRegistry, definitionsPath } from "./schedule.mjs";
32
32
  import { herdrSettingRemoved } from "./errors.mjs";
33
- import { MODEL_RE, automationError, baseRow, localEntry, localId, parseOwner, qualifiedId, soulOriginOf } from "./automations.mjs";
33
+ import { MODEL_RE, automationError, baseRow, localEntry, localId, parseOwner, qualifiedId, soulOriginOf, validateDescription } from "./automations.mjs";
34
34
  import { lockedPackageRef } from "./packages.mjs";
35
35
 
36
36
  export const TRIGGER_API = 1;
@@ -91,11 +91,13 @@ function checkTemplate(text, field) {
91
91
  * spawn.backend, for the refusal of `herdr` (Herdr was removed in 0.31.0). */
92
92
  export function validateTrigger(def, { backendSource = "the trigger's spawn.backend" } = {}) {
93
93
  if (!isObject(def)) throw invalid("definition", "must be an object");
94
- onlyKeys(def, ["id", "enabled", "kind", "on", "spawn", "concurrency", "template", "createdAt", "updatedAt"], "");
94
+ onlyKeys(def, ["id", "enabled", "kind", "description", "on", "spawn", "concurrency", "template", "createdAt", "updatedAt"], "");
95
95
  if (typeof def.id !== "string" || !ID_RE.test(def.id)) throw invalid("id", "lowercase letters, digits and dashes, 1 to 40 characters");
96
96
  if (def.kind !== "trigger") throw invalid("kind", "must be \"trigger\"");
97
97
  const enabled = def.enabled === undefined ? true : def.enabled;
98
98
  if (typeof enabled !== "boolean") throw invalid("enabled", "boolean");
99
+ // A label for people (list, show, the Desktop), never templated or read by a poll or a spawn.
100
+ if (def.description !== undefined) validateDescription(def.description, "E_TRIGGER_INVALID");
99
101
  const on = def.on;
100
102
  if (!isObject(on)) throw invalid("on", "{ source, repo, events, labels?, base?, poll? }");
101
103
  onlyKeys(on, ["source", "repo", "events", "labels", "base", "poll"], "on.");
@@ -133,7 +135,7 @@ export function validateTrigger(def, { backendSource = "the trigger's spawn.back
133
135
  for (const [k, v] of [["max", max], ["perKey", perKey]]) if (!Number.isInteger(v) || v < 1 || v > 100) throw invalid(`concurrency.${k}`, "a whole number from 1 to 100");
134
136
  if (def.template !== undefined && !isObject(def.template)) throw invalid("template", "the package template this trigger was made from");
135
137
  return {
136
- id: def.id, enabled, kind: "trigger",
138
+ id: def.id, enabled, kind: "trigger", ...(def.description !== undefined ? { description: def.description } : {}),
137
139
  on: { source: on.source, repo: repo.key, events: [...on.events], labels: [...labels], ...(on.base !== undefined ? { base: on.base.trim() } : {}), poll },
138
140
  spawn: { soul: sp.soul, purpose, task: sp.task, teams: [...teams], ...(sp.launchConfig ? { launchConfig: sp.launchConfig } : {}), ...(sp.harness ? { harness: sp.harness } : {}), ...(sp.model ? { model: sp.model } : {}), ...(sp.yolo !== undefined ? { yolo: sp.yolo } : {}), ...(sp.backend ? { backend: sp.backend } : {}) },
139
141
  concurrency: { max, perKey },
@@ -601,6 +603,23 @@ export function setTriggerEnabled(ws, id, enabled, ctx = null) {
601
603
  return describeTrigger(ws, e.id, ctx);
602
604
  });
603
605
  }
606
+ /** Change only a LOCAL trigger's description (`oats trigger update <id> --description=<text>`):
607
+ * `""` or null removes it. Its fired and pending state is untouched; a workspace trigger is
608
+ * changed in Git. */
609
+ export function updateTriggerDescription(ws, id, description, ctx = null) {
610
+ const e = requireTrigger(ws, id, ctx);
611
+ refuseWorkspace(e, "change");
612
+ const clear = description === "" || description === null || description === undefined;
613
+ if (!clear) validateDescription(description, "E_TRIGGER_INVALID");
614
+ return withScopeLock(ws, () => {
615
+ const defs = readDefinitions(ws);
616
+ if (defs.jobs[e.name]?.kind !== "trigger") throw triggerError("E_TRIGGER_UNKNOWN", `no trigger ${JSON.stringify(id)} in ${ws}`, { details: { id: e.id } });
617
+ const { description: _d, ...rest } = defs.jobs[e.name]; void _d;
618
+ defs.jobs[e.name] = { ...rest, ...(clear ? {} : { description }), updatedAt: new Date().toISOString() };
619
+ writeDefinitions(ws, defs);
620
+ return describeTrigger(ws, e.id, ctx);
621
+ });
622
+ }
604
623
  /** Remove the definition and its state. Live instances it spawned are untouched. */
605
624
  export function removeTrigger(ws, id, ctx = null) {
606
625
  const e = requireTrigger(ws, id, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/oats",
3
- "version": "0.42.0",
3
+ "version": "0.43.0",
4
4
  "description": "OATS (Open Agent Team Specification) — durable souls, disposable instances, targetable capability packages, and the runtime-neutral oats CLI/kernel.",
5
5
  "keywords": [
6
6
  "agents",