@gaia-ai/addon-herdr 0.6.4 → 0.7.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.
@@ -1,4 +1,4 @@
1
- import { envArgs, findTabIdByLabel, parsePaneInfo, parsePanesInTab, parseTabCreate, } from './panes.js';
1
+ import { AGENT_SHELL_ENV, envArgs, findTabIdByLabel, parsePaneInfo, parsePanesInTab, parseTabCreate, } from './panes.js';
2
2
  /** The single tab that holds a group's agent panes. */
3
3
  const groupTabLabel = (group) => `gaia-agents:${group}`;
4
4
  export function herdrAgentHost(execHerdr) {
@@ -31,7 +31,11 @@ export function herdrAgentHost(execHerdr) {
31
31
  return {
32
32
  async launch({ group, cwd, command, env, label }) {
33
33
  await captureHome();
34
- const e = env ?? {};
34
+ // Every pane this host opens holds an agent, so all of them carry the
35
+ // agent-shell marker (GAIA-64) — this is the pane a `gaia ui` user actually
36
+ // attaches to. The caller's own env wins on a key clash; the marker is
37
+ // merged in, never substituted for it.
38
+ const e = { ...AGENT_SHELL_ENV, ...(env ?? {}) };
35
39
  // Find the group's tab and split off a LIVE pane (newest-first; a stale
36
40
  // pane — a previous agent died/was closed — is skipped). None survive, or
37
41
  // no tab yet → create the group tab (its root pane is the agent).
package/dist/src/index.js CHANGED
@@ -3,6 +3,7 @@ import { exec, shellQuote, slugify } from '@gaia-ai/core';
3
3
  import { resolveStateConfig, } from './config.js';
4
4
  import { forceRemoveDir, restoreWritable } from './fs.js';
5
5
  import { applyPaneLayout, isRecord, parseJson, } from './pane-layout.js';
6
+ import { AGENT_SHELL_ENV, envArgs } from './panes.js';
6
7
  import { deriveHerdrRoot } from './root-anchor.js';
7
8
  export { herdrAgentHost } from './agents.js';
8
9
  export { envArgs, findTabIdByLabel, parsePaneInfo, parsePanesInTab, parseTabCreate, } from './panes.js';
@@ -587,7 +588,12 @@ export class HerdrExecutor {
587
588
  runUuid: input.run.uuid,
588
589
  workspacePath: input.workspacePath,
589
590
  };
590
- // 3. Create tab — NO --json flag; label includes the run-id token
591
+ // 3. Create tab — NO --json flag; label includes the run-id token. The tab's
592
+ // root pane IS the agent pane, so it is created carrying the agent-shell
593
+ // marker: the interactive shell must see it at startup for the user's opt-in
594
+ // history isolation to fire (GAIA-64). The run's own env (GAIA-99) stays out
595
+ // of here — it travels as inline `KEY='value'` prefixes on the command, so no
596
+ // secret moves into the pane environment.
591
597
  const { paneId: rootPaneId, tabId } = parseTabCreate(await this.execHerdr([
592
598
  'tab',
593
599
  'create',
@@ -596,6 +602,7 @@ export class HerdrExecutor {
596
602
  '--label',
597
603
  `${input.ticket.identifier} · ${input.ticket.state} #${input.run.id}`,
598
604
  '--no-focus',
605
+ ...envArgs(AGENT_SHELL_ENV),
599
606
  ]));
600
607
  try {
601
608
  // 4+5. Run the agent command in the root pane, then split each configured
@@ -603,10 +610,16 @@ export class HerdrExecutor {
603
610
  // open pane). The root command embeds `KEY='value'` env prefixes whose
604
611
  // values may be secret (GAIA-99); pass a redactor so a failed pane-run
605
612
  // exec-log carries key names, never values (only when env is present).
613
+ // The layout panes belong to the run's tab too, so they are marked as
614
+ // agent shells as well — the executor opts in, the workspace's open-layout
615
+ // caller does not (GAIA-64).
606
616
  const hasEnv = Object.keys(input.env ?? {}).length > 0;
607
- await applyPaneLayout(this.execHerdr, rootPaneId, { command: this.commandFor(input), panes: cfg.panes }, input.workspacePath, vars, hasEnv
608
- ? { redactCommand: () => this.redactedCommandFor(input) }
609
- : undefined);
617
+ await applyPaneLayout(this.execHerdr, rootPaneId, { command: this.commandFor(input), panes: cfg.panes }, input.workspacePath, vars, {
618
+ env: AGENT_SHELL_ENV,
619
+ ...(hasEnv
620
+ ? { redactCommand: () => this.redactedCommandFor(input) }
621
+ : {}),
622
+ });
610
623
  // 6. Return branch as sessionRef (for logging)
611
624
  return { sessionRef: branchName };
612
625
  }
@@ -31,7 +31,15 @@ export interface PaneLayout {
31
31
  * `redactArgs` scrubber is passed so a failed `pane run` exec-log never carries a
32
32
  * secret, while the command herdr actually runs stays real. An empty layout
33
33
  * (`{}`) issues no calls at all — the caller's unconfigured default is preserved.
34
+ *
35
+ * `opts.env` is forwarded to each split pane as `--env` args (GAIA_* only, see
36
+ * {@link envArgs}). It is deliberately per-CALLER rather than baked in: this
37
+ * primitive serves both the executor's agent tab and the workspace's own open
38
+ * pane, and only the former's panes are agent-owned (GAIA-64). The ROOT pane is
39
+ * not touched — it already exists when we get here, so its environment came from
40
+ * whoever created it. Omitted ⇒ no `--env` at all.
34
41
  */
35
42
  export declare function applyPaneLayout(execHerdr: HerdrExec, rootPaneId: string, layout: PaneLayout, cwd: string, vars: Record<string, string>, opts?: {
36
43
  redactCommand?: (command: string) => string;
44
+ env?: Record<string, string | undefined>;
37
45
  }): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { renderTemplate } from './config.js';
2
+ import { envArgs } from './panes.js';
2
3
  export function isRecord(value) {
3
4
  return typeof value === 'object' && value !== null && !Array.isArray(value);
4
5
  }
@@ -33,6 +34,13 @@ export function parsePaneSplit(output) {
33
34
  * `redactArgs` scrubber is passed so a failed `pane run` exec-log never carries a
34
35
  * secret, while the command herdr actually runs stays real. An empty layout
35
36
  * (`{}`) issues no calls at all — the caller's unconfigured default is preserved.
37
+ *
38
+ * `opts.env` is forwarded to each split pane as `--env` args (GAIA_* only, see
39
+ * {@link envArgs}). It is deliberately per-CALLER rather than baked in: this
40
+ * primitive serves both the executor's agent tab and the workspace's own open
41
+ * pane, and only the former's panes are agent-owned (GAIA-64). The ROOT pane is
42
+ * not touched — it already exists when we get here, so its environment came from
43
+ * whoever created it. Omitted ⇒ no `--env` at all.
36
44
  */
37
45
  export async function applyPaneLayout(execHerdr, rootPaneId, layout, cwd, vars, opts) {
38
46
  if (layout.command) {
@@ -58,6 +66,7 @@ export async function applyPaneLayout(execHerdr, rootPaneId, layout, cwd, vars,
58
66
  '--cwd',
59
67
  cwd,
60
68
  spec.focus ? '--focus' : '--no-focus',
69
+ ...envArgs(opts?.env ?? {}),
61
70
  ]));
62
71
  await execHerdr([
63
72
  'pane',
@@ -7,6 +7,18 @@ export interface HerdrPaneRef {
7
7
  export interface HerdrPaneInfo extends HerdrPaneRef {
8
8
  label: string;
9
9
  }
10
+ /**
11
+ * Marker exported into an AGENT pane's interactive shell, so a user's opt-in
12
+ * shell init can recognise an agent-run pane at startup and isolate its history
13
+ * (GAIA-64). It is a plain `GAIA_*` env entry on purpose: it rides {@link envArgs}
14
+ * like every other pane var instead of adding a second mechanism.
15
+ *
16
+ * AGENT panes only — the executor's per-run tab and its layout panes, plus the
17
+ * TUI-hosted agents. NOT the workspace's own open-layout pane: that one is the
18
+ * human's landing pane, and the opt-in unsets `HISTFILE`. See
19
+ * `docs/conductor/node.md` § Agent-pane shell marker.
20
+ */
21
+ export declare const AGENT_SHELL_ENV: Record<string, string>;
10
22
  /** GAIA_* env vars as `--env KEY=VALUE` args (never dump the full environment). */
11
23
  export declare function envArgs(env: Record<string, string | undefined>): string[];
12
24
  /** `{ paneId, tabId }` from a `herdr tab create` envelope. */
package/dist/src/panes.js CHANGED
@@ -4,6 +4,20 @@
4
4
  function isRecord(v) {
5
5
  return typeof v === 'object' && v !== null;
6
6
  }
7
+ /**
8
+ * Marker exported into an AGENT pane's interactive shell, so a user's opt-in
9
+ * shell init can recognise an agent-run pane at startup and isolate its history
10
+ * (GAIA-64). It is a plain `GAIA_*` env entry on purpose: it rides {@link envArgs}
11
+ * like every other pane var instead of adding a second mechanism.
12
+ *
13
+ * AGENT panes only — the executor's per-run tab and its layout panes, plus the
14
+ * TUI-hosted agents. NOT the workspace's own open-layout pane: that one is the
15
+ * human's landing pane, and the opt-in unsets `HISTFILE`. See
16
+ * `docs/conductor/node.md` § Agent-pane shell marker.
17
+ */
18
+ export const AGENT_SHELL_ENV = {
19
+ GAIA_AGENT_SHELL: '1',
20
+ };
7
21
  /** GAIA_* env vars as `--env KEY=VALUE` args (never dump the full environment). */
8
22
  export function envArgs(env) {
9
23
  const out = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gaia-ai/addon-herdr",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "GAIA herdr integration: spawn executor + per-ticket worktree workspace.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,10 +20,10 @@
20
20
  "directory": "gaia-cli/addons/herdr"
21
21
  },
22
22
  "dependencies": {
23
- "@gaia-ai/addon-workspace-git": "^0.6.4"
23
+ "@gaia-ai/addon-workspace-git": "^0.7.0"
24
24
  },
25
25
  "peerDependencies": {
26
- "@gaia-ai/conductor": "^0.6.4",
27
- "@gaia-ai/core": "^0.6.4"
26
+ "@gaia-ai/conductor": "^0.7.0",
27
+ "@gaia-ai/core": "^0.7.0"
28
28
  }
29
29
  }