@yagni-app/code-staging 1.0.3-staging.1222.1 → 1.0.4-staging.1225.1

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.
@@ -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-staging",
3
- "version": "1.0.3-staging.1222.1",
3
+ "version": "1.0.4-staging.1225.1",
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": "180f2fe5eda13aabc43dde056df32b5a4e4a6195"
44
+ "yagniSourceSha": "0a684e046e6b27f6b5ad797376620a98031b671f"
45
45
  }