@blogic-cz/agent-tools 1.6.1 → 1.6.2

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/README.md CHANGED
@@ -654,6 +654,8 @@ Literal assignments such as `F=README.md; cat "$F"` work in supported static com
654
654
 
655
655
  Ordinary navigation operands such as `cd "$HOME"` and `git -C "$WORKTREE_ROOT" status --short` do not need display permission. This does not authorize printing those values, using them as code/options, or reading unknown file paths. In `printf`, approved values belong in data arguments after a fixed nonmutating format, for example `printf -- '%s' "$WORKSPACE_LABEL"`.
656
656
 
657
+ Literal `herdr agent prompt` commands can be composed with independent `cat` readers and passive text pipelines. Prompt text stays data; command substitutions, environment mutation, unknown consumers, and executable pipelines cannot establish the proof. All reader operands and redirects still receive the ordinary sensitive-path checks. Literal loops also support `herdr pane read ID --source recent-unwrapped --lines N`, with the binder restricted to `ID`, and `2>&1` file-descriptor duplication. A bounded Python stdin processor supports only `import json,sys; d=json.load(sys.stdin); print(d["result"].get("text","") if isinstance(d.get("result"),dict) else d)`, including insignificant spacing and single lowercase-letter local renaming. Extra imports, statements, calls, runtime options, arguments, and other Python programs cannot establish this loop proof. The existing loop size and command limits apply.
658
+
657
659
  The guard recognizes `rtk`, `rtk proxy`, `command`, and supported `env` prefixes and checks commands in pipelines and chains. Quoted filenames, comments, and redirects retain sensitive-path checks. Jq object selectors and inline awk programs qualify only when their actual program and options establish passive behavior. Literal environment-command text in `rg`, `grep`, `git grep`, `echo`, and `printf` is allowed only with supported command roles and passive pipeline consumers. Environment-source evidence and startup identity checks also apply to the complete original invocation. Custom dangerous-command patterns apply to both the original input and proved expansions.
658
660
 
659
661
  Paths are checked against sensitive filename patterns and configured path rules. Supported proofs apply those checks to their expanded operands. Ordinary parent-directory and absolute paths may be allowed; the guard does not resolve filesystem paths or symlinks, or enforce repository confinement.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credential-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAK5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAQF,+CAA+C;AAC/C,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,sBAAsB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjF,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AA6qEF,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAErE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAMD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CA4TrF;AAQD,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,UAnhFD,SAAS,UAAU,UAAU,KAAK,IAmhFM,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,aAAa,YArhFC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAqhFjB,CAAC;AAExD,yEAAyE;AACzE,eAAO,MAAM,aAAa,aAvhFE,MAAM,KAAK,OAuhFgB,CAAC;AAExD,yDAAyD;AACzD,eAAO,MAAM,aAAa,aAzhFE,MAAM,KAAK,OAyhFgB,CAAC;AAExD,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,YA3hFC,MAAM,KAAK,OA2hF0B,CAAC;AAE1E,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,YA7hFC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IA6hFf,CAAC;AAEhE,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,YA/hFC,MAAM,KAAK,OA+hFsB,CAAC;AAElE,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,YAjiFC,MAAM,KAAK,MAAM,GAAG,IAiiFa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credential-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAK5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAQF,+CAA+C;AAC/C,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,sBAAsB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjF,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AA6tEF,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAErE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAMD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CA4TrF;AAQD,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,UAnkFD,SAAS,UAAU,UAAU,KAAK,IAmkFM,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,aAAa,YArkFC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAqkFjB,CAAC;AAExD,yEAAyE;AACzE,eAAO,MAAM,aAAa,aAvkFE,MAAM,KAAK,OAukFgB,CAAC;AAExD,yDAAyD;AACzD,eAAO,MAAM,aAAa,aAzkFE,MAAM,KAAK,OAykFgB,CAAC;AAExD,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,YA3kFC,MAAM,KAAK,OA2kF0B,CAAC;AAE1E,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,YA7kFC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IA6kFf,CAAC;AAEhE,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,YA/kFC,MAAM,KAAK,OA+kFsB,CAAC;AAElE,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,YAjlFC,MAAM,KAAK,MAAM,GAAG,IAilFa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure platform, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -504,9 +504,8 @@ function isLiteralLoopCommand(words: string[], marker: string, value: string): b
504
504
  }
505
505
  if (name === "herdr")
506
506
  return (
507
- argv.length === 4 &&
508
- argv[1] === "agent" &&
509
- argv[2] === "get" &&
507
+ ((argv.length === 4 && argv[1] === "agent" && argv[2] === "get") ||
508
+ isLiteralHerdrPaneRead(argv)) &&
510
509
  /^[A-Za-z0-9_.:-]+$/.test(argv[3] ?? "") &&
511
510
  uses.every((index) => index === 3)
512
511
  );
@@ -520,7 +519,36 @@ function isLiteralLoopCommand(words: string[], marker: string, value: string): b
520
519
  uses.every((index) => index === 8)
521
520
  );
522
521
  return (
523
- ["grep", "head", "tail"].includes(name ?? "") && uses.length === 0 && isPassiveTextCommand(argv)
522
+ uses.length === 0 &&
523
+ ((["grep", "head", "tail"].includes(name ?? "") && isPassiveTextCommand(argv)) ||
524
+ isLiteralStdinJsonDisplay(argv))
525
+ );
526
+ }
527
+
528
+ function isLiteralHerdrPaneRead(argv: string[]): boolean {
529
+ return (
530
+ argv.length === 8 &&
531
+ argv.slice(0, 3).join(" ") === "herdr pane read" &&
532
+ /^[A-Za-z0-9_.:-]+$/.test(argv[3] ?? "") &&
533
+ argv[4] === "--source" &&
534
+ argv[5] === "recent-unwrapped" &&
535
+ argv[6] === "--lines" &&
536
+ /^[1-9]\d*$/.test(argv[7] ?? "")
537
+ );
538
+ }
539
+
540
+ /** A complete stdin-only JSON projection, with no suffix, imports or executable input. */
541
+ function isLiteralStdinJsonDisplay(argv: string[]): boolean {
542
+ if (argv.length !== 3 || !["python", "python3"].includes(argv[0] ?? "") || argv[1] !== "-c")
543
+ return false;
544
+ const program = argv[2] ?? "";
545
+ if (program.length > 65_536) return false;
546
+ const parts = programParts(program, true);
547
+ if (!parts || parts.literals.join("\0") !== "result\0text\0\0result") return false;
548
+ // ponytail: one JSON projection with a single-letter local; extend only with another complete grammar.
549
+ const code = parts.code.replace(/[ \t]+/g, " ").trim();
550
+ return /^import json\s*,\s*sys\s*(?:;|\r?\n)\s*([a-z])\s*=\s*json\s*\.\s*load\s*\(\s*sys\s*\.\s*stdin\s*\)\s*(?:;|\r?\n)\s*print\s*\(\s*\1\s*\[\s*STRING\s*\]\s*\.\s*get\s*\(\s*STRING\s*,\s*STRING\s*\)\s+if isinstance\s*\(\s*\1\s*\.\s*get\s*\(\s*STRING\s*\)\s*,\s*dict\s*\)\s+else \1\s*\)\s*;?$/.test(
551
+ code,
524
552
  );
525
553
  }
526
554
 
@@ -567,7 +595,8 @@ function materializeLiteralShell(command: string): LiteralShellProof | undefined
567
595
  const values = rawValues.map((item) => item.replace(/^['"]|['"]$/g, ""));
568
596
  if (!values.length || values.length > 16) return undefined;
569
597
  const marked = literalBindingText(loop[3] ?? "", name, marker);
570
- if (!marked || /&&|\|\||[<>]|&/.test(marked.syntax.replace(/\b2>&1\b/g, ""))) return undefined;
598
+ if (!marked || /&&|\|\||[<>]|&/.test(marked.syntax.replace(/\b2>&1(?=[ \t\n;|]|$)/g, "")))
599
+ return undefined;
571
600
  const parsed = parseStaticShellCommands(marked.text);
572
601
  if (
573
602
  !parsed ||
@@ -1597,24 +1626,43 @@ function hasStaticEnvironmentRead(
1597
1626
  }
1598
1627
 
1599
1628
  function isStaticHerdrPrompt(command: string): boolean {
1629
+ // Preserve shell word boundaries and executable identity before proving composition.
1630
+ if (!literalBindingText(command, "", "")) return false;
1600
1631
  const parsed = parseStaticShellCommands(command);
1601
1632
  if (!parsed || typeof parsed === "string") return false;
1602
- const commands = parsed.pipelines.flat().map(unwrapStaticCommand);
1633
+ const commands = parsed.pipelines.flat().map((words) => unwrapProofCommand(words, "\0"));
1603
1634
  const prompts = commands.filter(
1604
- (argv) => argv[0] === "herdr" && argv[1] === "agent" && argv[2] === "prompt",
1635
+ (argv) => argv?.[0] === "herdr" && argv[1] === "agent" && argv[2] === "prompt",
1605
1636
  );
1606
1637
  return (
1607
1638
  prompts.length > 0 &&
1608
- commands.every((argv) =>
1609
- argv[0] === "herdr" && argv[1] === "agent" && argv[2] === "prompt"
1610
- ? argv.length >= 5
1611
- : isPassiveTextCommand(argv),
1639
+ parsed.pipelines.every((pipeline) =>
1640
+ pipeline.every((words, index) => {
1641
+ const argv = unwrapProofCommand(words, "\0");
1642
+ if (!argv) return false;
1643
+ if (argv[0] === "herdr" && argv[1] === "agent" && argv[2] === "prompt")
1644
+ return index === 0 && argv.length >= 5;
1645
+ // cat is a reader at the start of an independent pipeline, never a consumer.
1646
+ if (argv[0] === "cat")
1647
+ return (
1648
+ index === 0 &&
1649
+ argv.length > 1 &&
1650
+ argv.slice(1).every((arg) => arg === "--" || !arg.startsWith("-"))
1651
+ );
1652
+ return isPassiveTextCommand(argv);
1653
+ }),
1612
1654
  )
1613
1655
  );
1614
1656
  }
1615
1657
 
1616
1658
  function isHerdrPrompt(command: string): boolean {
1617
- return /^herdr\s+agent\s+prompt\b/.test(command.trim());
1659
+ if (/^herdr\s+agent\s+prompt\b/.test(command.trim())) return true;
1660
+ const parsed = parseStaticShellCommands(command, true);
1661
+ if (!parsed || typeof parsed === "string") return false;
1662
+ return parsed.pipelines.flat().some((words) => {
1663
+ const argv = unwrapStaticCommand(words);
1664
+ return argv[0] === "herdr" && argv[1] === "agent" && argv[2] === "prompt";
1665
+ });
1618
1666
  }
1619
1667
 
1620
1668
  function hasEnvironmentRead(