@yagni-app/code 1.0.4 → 1.0.5

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.
@@ -885,9 +885,12 @@ export async function registerYagni(pi, deps = {}) {
885
885
  // Surface Pi's native find/grep/ls on the driver. These are Pi's
886
886
  // equivalents of Claude Code's Glob/Grep/LS; the /go stages and subagents
887
887
  // already pass them explicitly, but the driver defaults to read/bash/edit/write
888
- // and otherwise reaches for `bash` find/grep/ls.
888
+ // and otherwise reaches for `bash` find/grep/ls. Dedupe against the active
889
+ // set — condensedTools re-registers these built-ins, so they can already be
890
+ // active here, and a duplicated name in the request's tool list is a hard
891
+ // 400 on some providers (Baseten: "Tool names must be unique.").
889
892
  try {
890
- pi.setActiveTools([...pi.getActiveTools(), "grep", "find", "ls"]);
893
+ pi.setActiveTools([...new Set([...pi.getActiveTools(), "grep", "find", "ls"])]);
891
894
  }
892
895
  catch {
893
896
  // Tool enrichment must never break session start.
@@ -616,10 +616,20 @@ function classifySegmentTokens(rawTokens, policy, opts) {
616
616
  }
617
617
  const { tokens: strippedTokens, stripped } = stripLeadingTokens(rawTokens);
618
618
  if (strippedTokens.length === 0) {
619
+ // A segment made only of environment assignments (`FOO=bar`) is a no-op: it
620
+ // sets shell variables and executes nothing. Recognize it so a compound like
621
+ // `SF="$F"; echo hi` is not floored by its leading assignment. Safety holds
622
+ // because classifyCommand's construct floor + substitution danger scan run
623
+ // afterward: an assignment whose value is a `$(...)` substitution frees the
624
+ // inner text for the danger scan and downgrades the overall result to prompt
625
+ // or forbidden there.
626
+ if (!opts.forbiddenOnly && rawTokens.length > 0 && rawTokens.every((t) => ENV_ASSIGNMENT_RE.test(t))) {
627
+ return { decision: "allow", justification: "no-op environment assignment" };
628
+ }
619
629
  // env standalone: `env` or `env VAR=val` with no following command prints
620
630
  // environment variables — a read-only operation. stripLeadingTokens removes
621
631
  // `env` as a wrapper word, leaving empty tokens. Recognize this case instead
622
- // of returning "empty command segment" (YAG-549).
632
+ // of returning "empty command segment".
623
633
  if (!opts.forbiddenOnly && rawTokens.length > 0 && basenameToken(rawTokens[0]) === "env") {
624
634
  const onlyEnvAndAssignments = rawTokens.every((t) => basenameToken(t) === "env" || ENV_ASSIGNMENT_RE.test(t));
625
635
  if (onlyEnvAndAssignments) {
@@ -951,6 +961,9 @@ export const DEFAULT_EXEC_POLICY = {
951
961
  { pattern: ["printf"], decision: "allow", justification: "print formatted text" },
952
962
  { pattern: ["whoami"], decision: "allow", justification: "show current user" },
953
963
  { pattern: ["uname"], decision: "allow", justification: "show system info" },
964
+ { pattern: ["ps"], decision: "allow", justification: "list processes (read-only)" },
965
+ { pattern: ["lsof"], decision: "allow", justification: "list open files and ports (read-only)" },
966
+ { pattern: ["sleep"], decision: "allow", justification: "no-op delay" },
954
967
  { pattern: ["git", "status"], decision: "allow", justification: "show working tree status" },
955
968
  { pattern: ["git", "log"], decision: "allow", justification: "show commit log" },
956
969
  { pattern: ["git", "diff"], decision: "allow", justification: "show changes" },
@@ -989,6 +1002,9 @@ export const DEFAULT_EXEC_POLICY = {
989
1002
  },
990
1003
  { pattern: ["linear", ["--help", "-h"]], decision: "allow", justification: "show Linear CLI help" },
991
1004
  { pattern: ["linear", ["--version", "-V"]], decision: "allow", justification: "show Linear CLI version" },
1005
+ { pattern: ["linear", "user", "list"], decision: "allow", justification: "list Linear workspace members (read-only)" },
1006
+ { pattern: ["linear", "team", ["list", "members", "states", "id"]], decision: "allow", justification: "read Linear team data (read-only)" },
1007
+ { pattern: ["linear", "project", ["list", "view"]], decision: "allow", justification: "read Linear project data (read-only)" },
992
1008
  // gh api — REST GET (no params, no method override) and GraphQL queries (no mutation)
993
1009
  // gh api defaults to POST when -f/-F params are present, so params are disqualifying.
994
1010
  // GraphQL is always POST, but queries are reads; mutations/subscriptions are disqualifying.
@@ -1065,7 +1081,6 @@ export const DEFAULT_EXEC_POLICY = {
1065
1081
  { pattern: ["tar"], decision: "prompt", justification: "archive operation" },
1066
1082
  { pattern: ["zip"], decision: "prompt", justification: "archive operation" },
1067
1083
  { pattern: ["unzip"], decision: "prompt", justification: "archive operation" },
1068
- { pattern: ["ps"], decision: "prompt", justification: "lists processes" },
1069
1084
  { pattern: ["kill"], decision: "prompt", justification: "sends a signal to a process" },
1070
1085
  { pattern: ["chmod"], decision: "prompt", justification: "permission change — review the mode" },
1071
1086
  { pattern: ["chown"], decision: "prompt", justification: "ownership change" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagni-app/code",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
@@ -41,5 +41,5 @@
41
41
  "turndown": "^7.2.4",
42
42
  "typebox": "^1.3.15"
43
43
  },
44
- "yagniSourceSha": "58371f52233aaff50f140f858c9018d3e500e4e1"
44
+ "yagniSourceSha": "5bd359dcd98d8104d425f698a65ed60d780df0af"
45
45
  }