poe-code 3.0.339 → 3.0.341

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.
Files changed (27) hide show
  1. package/dist/index.js +153 -27
  2. package/dist/index.js.map +3 -3
  3. package/dist/metafile.json +1 -1
  4. package/dist/workflow-templates/fix-vulnerabilities.ejected.yml +4 -3
  5. package/dist/workflow-templates/github-issue-comment-created.ejected.yml +8 -6
  6. package/dist/workflow-templates/github-issue-opened.ejected.yml +8 -6
  7. package/dist/workflow-templates/github-pull-request-comment-created.ejected.yml +8 -6
  8. package/dist/workflow-templates/github-pull-request-opened.ejected.yml +8 -6
  9. package/dist/workflow-templates/github-pull-request-synchronized.ejected.yml +8 -6
  10. package/dist/workflow-templates/update-dependencies.ejected.yml +4 -3
  11. package/dist/workflow-templates/update-documentation.ejected.yml +4 -3
  12. package/package.json +1 -1
  13. package/packages/github-workflows/dist/commands.js +4 -2
  14. package/packages/github-workflows/dist/discover.d.ts +1 -0
  15. package/packages/github-workflows/dist/discover.js +33 -4
  16. package/packages/github-workflows/dist/exec/trufflehog-pr-scan.js +26 -6
  17. package/packages/github-workflows/dist/preflight.js +1 -1
  18. package/packages/github-workflows/dist/workflow-templates/fix-vulnerabilities.ejected.yml +4 -3
  19. package/packages/github-workflows/dist/workflow-templates/github-issue-comment-created.ejected.yml +8 -6
  20. package/packages/github-workflows/dist/workflow-templates/github-issue-opened.ejected.yml +8 -6
  21. package/packages/github-workflows/dist/workflow-templates/github-pull-request-comment-created.ejected.yml +8 -6
  22. package/packages/github-workflows/dist/workflow-templates/github-pull-request-opened.ejected.yml +8 -6
  23. package/packages/github-workflows/dist/workflow-templates/github-pull-request-synchronized.ejected.yml +8 -6
  24. package/packages/github-workflows/dist/workflow-templates/update-dependencies.ejected.yml +4 -3
  25. package/packages/github-workflows/dist/workflow-templates/update-documentation.ejected.yml +4 -3
  26. package/packages/plan-browser/dist/actions.js +54 -8
  27. package/packages/plan-browser/dist/discovery.js +31 -5
@@ -19,9 +19,10 @@ jobs:
19
19
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
20
20
  run: |
21
21
  missing=()
22
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
23
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
22
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
23
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
24
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
25
26
  if [ ${#missing[@]} -gt 0 ]; then
26
27
  for name in "${missing[@]}"; do
27
28
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -24,9 +24,10 @@ jobs:
24
24
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
25
25
  run: |
26
26
  missing=()
27
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
28
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
29
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
27
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
28
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
29
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
30
31
  if [ ${#missing[@]} -gt 0 ]; then
31
32
  for name in "${missing[@]}"; do
32
33
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -82,9 +83,10 @@ jobs:
82
83
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
83
84
  run: |
84
85
  missing=()
85
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
86
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
87
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
86
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
87
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
88
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
89
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
88
90
  if [ ${#missing[@]} -gt 0 ]; then
89
91
  for name in "${missing[@]}"; do
90
92
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -25,9 +25,10 @@ jobs:
25
25
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
26
26
  run: |
27
27
  missing=()
28
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
29
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
28
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
29
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
30
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
31
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
31
32
  if [ ${#missing[@]} -gt 0 ]; then
32
33
  for name in "${missing[@]}"; do
33
34
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -75,9 +76,10 @@ jobs:
75
76
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
76
77
  run: |
77
78
  missing=()
78
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
79
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
80
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
79
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
80
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
81
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
82
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
81
83
  if [ ${#missing[@]} -gt 0 ]; then
82
84
  for name in "${missing[@]}"; do
83
85
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -25,9 +25,10 @@ jobs:
25
25
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
26
26
  run: |
27
27
  missing=()
28
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
29
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
28
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
29
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
30
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
31
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
31
32
  if [ ${#missing[@]} -gt 0 ]; then
32
33
  for name in "${missing[@]}"; do
33
34
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -84,9 +85,10 @@ jobs:
84
85
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
85
86
  run: |
86
87
  missing=()
87
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
88
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
89
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
88
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
89
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
90
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
91
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
90
92
  if [ ${#missing[@]} -gt 0 ]; then
91
93
  for name in "${missing[@]}"; do
92
94
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -20,9 +20,10 @@ jobs:
20
20
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
21
21
  run: |
22
22
  missing=()
23
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
24
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
23
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
24
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
25
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
26
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
26
27
  if [ ${#missing[@]} -gt 0 ]; then
27
28
  for name in "${missing[@]}"; do
28
29
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -69,9 +70,10 @@ jobs:
69
70
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
70
71
  run: |
71
72
  missing=()
72
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
73
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
74
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
73
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
74
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
75
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
76
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
75
77
  if [ ${#missing[@]} -gt 0 ]; then
76
78
  for name in "${missing[@]}"; do
77
79
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -20,9 +20,10 @@ jobs:
20
20
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
21
21
  run: |
22
22
  missing=()
23
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
24
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
23
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
24
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
25
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
26
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
26
27
  if [ ${#missing[@]} -gt 0 ]; then
27
28
  for name in "${missing[@]}"; do
28
29
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -69,9 +70,10 @@ jobs:
69
70
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
70
71
  run: |
71
72
  missing=()
72
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
73
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
74
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
73
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
74
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
75
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
76
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
75
77
  if [ ${#missing[@]} -gt 0 ]; then
76
78
  for name in "${missing[@]}"; do
77
79
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -18,9 +18,10 @@ jobs:
18
18
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
19
19
  run: |
20
20
  missing=()
21
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
22
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
23
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
21
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
22
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
23
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
24
25
  if [ ${#missing[@]} -gt 0 ]; then
25
26
  for name in "${missing[@]}"; do
26
27
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -18,9 +18,10 @@ jobs:
18
18
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
19
19
  run: |
20
20
  missing=()
21
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
22
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
23
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
21
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
22
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
23
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
24
25
  if [ ${#missing[@]} -gt 0 ]; then
25
26
  for name in "${missing[@]}"; do
26
27
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "3.0.339",
3
+ "version": "3.0.341",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -6,7 +6,7 @@ import { runCommand, spawn } from "@poe-code/agent-spawn";
6
6
  import { S } from "toolcraft-schema";
7
7
  import { UserError, defineCommand, defineGroup } from "toolcraft";
8
8
  import { cancel, isCancel, renderTemplate, select } from "toolcraft-design";
9
- import { discoverAutomations, loadAutomation } from "./discover.js";
9
+ import { discoverAutomations, loadAutomation, usesDefaultAgent } from "./discover.js";
10
10
  import { checkUserAllow } from "./exec/check-user-allow.js";
11
11
  import { requireCommentPrefix } from "./exec/require-comment-prefix.js";
12
12
  import { runTruffleHogPrScanCommand } from "./exec/trufflehog-pr-scan.js";
@@ -67,7 +67,9 @@ const runCommandDef = defineCommand({
67
67
  const name = params.name ??
68
68
  (await selectAutomationName("Pick a workflow to run", await discoverAutomations(await resolveBuiltInPromptsDir(), ...projectPromptDirs(cwd))));
69
69
  const automation = await loadNamedAutomation(name, cwd);
70
- const agent = automation.agent ?? params.agent ?? "codex";
70
+ const agent = params.agent !== undefined && usesDefaultAgent(automation)
71
+ ? params.agent
72
+ : automation.agent ?? params.agent ?? "codex";
71
73
  const variables = await loadVariables(await resolveBuiltInAssetsDir(), projectGitHubWorkflowsDir(cwd));
72
74
  const sharedTemplateContext = { ...variables, ...buildTemplateContext(env) };
73
75
  if (automation.source === undefined) {
@@ -1,3 +1,4 @@
1
1
  import type { AutomationDefinition } from "./types.js";
2
2
  export declare function discoverAutomations(builtInDir: string, ...projectDirs: string[]): Promise<AutomationDefinition[]>;
3
3
  export declare function loadAutomation(name: string, dirs: string[]): Promise<AutomationDefinition | undefined>;
4
+ export declare function usesDefaultAgent(automation: AutomationDefinition): boolean;
@@ -2,6 +2,8 @@ import { readdir, readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { resolve } from "@poe-code/config-extends";
4
4
  import { hasOwnErrorCode } from "./errors.js";
5
+ const DEFAULTS_SOURCE = "defaults";
6
+ const AGENT_SOURCE_PROPERTY = "__poeCodeAgentSource";
5
7
  const VALID_AUTHOR_ASSOCIATIONS = new Set([
6
8
  "COLLABORATOR",
7
9
  "CONTRIBUTOR",
@@ -70,7 +72,7 @@ async function readAutomation(dir, fileName, baseName, baseDirs) {
70
72
  path: baseDir
71
73
  })),
72
74
  {
73
- source: "defaults",
75
+ source: DEFAULTS_SOURCE,
74
76
  data: {
75
77
  agent: "codex"
76
78
  }
@@ -79,11 +81,23 @@ async function readAutomation(dir, fileName, baseName, baseDirs) {
79
81
  fs: { readFile }
80
82
  });
81
83
  const name = stripPrefix(fileName.slice(0, -3));
82
- return {
84
+ const automation = {
83
85
  name,
84
86
  prompt: readPrompt(getOwnEntry(resolved.data, "prompt"), fileName),
85
87
  ...readAutomationFields(resolved.data, fileName)
86
88
  };
89
+ Object.defineProperty(automation, AGENT_SOURCE_PROPERTY, {
90
+ configurable: true,
91
+ enumerable: false,
92
+ value: resolved.sources.agent
93
+ });
94
+ return automation;
95
+ }
96
+ export function usesDefaultAgent(automation) {
97
+ return getInternalAgentSource(automation) === DEFAULTS_SOURCE;
98
+ }
99
+ function getInternalAgentSource(automation) {
100
+ return automation[AGENT_SOURCE_PROPERTY];
87
101
  }
88
102
  function readPrompt(value, fileName) {
89
103
  if (typeof value === "string") {
@@ -96,8 +110,8 @@ function readPrompt(value, fileName) {
96
110
  }
97
111
  function readAutomationFields(frontmatter, fileName) {
98
112
  const label = readOptionalString(getOwnEntry(frontmatter, "label"), "label", fileName);
99
- const source = readOptionalString(getOwnEntry(frontmatter, "source"), "source", fileName);
100
- const agent = readOptionalString(getOwnEntry(frontmatter, "agent"), "agent", fileName);
113
+ const source = readOptionalNonBlankString(getOwnEntry(frontmatter, "source"), "source", fileName);
114
+ const agent = readOptionalNonBlankString(getOwnEntry(frontmatter, "agent"), "agent", fileName);
101
115
  const mcp = readOptionalMcp(getOwnEntry(frontmatter, "mcp"), fileName);
102
116
  const allow = readOptionalStringArray(getOwnEntry(frontmatter, "allow"), "allow", fileName);
103
117
  const prefix = readOptionalPrefix(getOwnEntry(frontmatter, "prefix"), fileName);
@@ -119,6 +133,18 @@ function readOptionalString(value, field, fileName) {
119
133
  }
120
134
  return value;
121
135
  }
136
+ function readOptionalNonBlankString(value, field, fileName) {
137
+ if (value === undefined) {
138
+ return undefined;
139
+ }
140
+ if (typeof value !== "string") {
141
+ throw new Error(`Automation "${fileName}" has invalid "${field}" frontmatter. Expected a string.`);
142
+ }
143
+ if (value.trim().length === 0) {
144
+ throw new Error(`Automation "${fileName}" has invalid "${field}" frontmatter. Expected a non-empty string.`);
145
+ }
146
+ return value;
147
+ }
122
148
  function readOptionalPrefix(value, fileName) {
123
149
  if (value === undefined) {
124
150
  return undefined;
@@ -176,6 +202,9 @@ function readOptionalMcp(value, fileName) {
176
202
  if (typeof command !== "string") {
177
203
  throw new Error(`Automation "${fileName}" has invalid "mcp.${serverName}.command" frontmatter. Expected a string.`);
178
204
  }
205
+ if (command.trim().length === 0) {
206
+ throw new Error(`Automation "${fileName}" has invalid "mcp.${serverName}.command" frontmatter. Expected a non-empty string.`);
207
+ }
179
208
  const args = getOwnEntry(serverValue, "args");
180
209
  if (args !== undefined && (!Array.isArray(args) || args.some((item) => typeof item !== "string"))) {
181
210
  throw new Error(`Automation "${fileName}" has invalid "mcp.${serverName}.args" frontmatter. Expected an array of strings.`);
@@ -59,6 +59,7 @@ export function uniqueTruffleHogFindings(findings) {
59
59
  return [...unique.values()];
60
60
  }
61
61
  export function renderTruffleHogFindingsTable(findings, options) {
62
+ assertPositiveInteger(options.maxFindings, "maxFindings");
62
63
  const uniqueFindings = uniqueTruffleHogFindings(findings);
63
64
  const rows = [
64
65
  "| Detector | Location | Verification |",
@@ -133,7 +134,7 @@ async function scanForSecrets(env, cwd, runner, fs) {
133
134
  async function reportAdvisoryResult(env, runner, fs) {
134
135
  const githubToken = requireEnv(env, "GH_TOKEN");
135
136
  const headSha = requireEnv(env, "HEAD_SHA");
136
- const maxFindings = numberEnv(env, "MAX_FINDINGS");
137
+ const maxFindings = positiveDecimalIntegerEnv(env, "MAX_FINDINGS");
137
138
  const prNumber = requireEnv(env, "PR_NUMBER");
138
139
  const repository = requireEnv(env, "REPOSITORY");
139
140
  const resultsFile = env.get("TRUFFLEHOG_RESULTS_FILE") ?? DEFAULT_RESULTS_FILE;
@@ -330,12 +331,31 @@ function requireEnv(env, name) {
330
331
  }
331
332
  return value;
332
333
  }
333
- function numberEnv(env, name) {
334
- const value = Number(requireEnv(env, name));
335
- if (!Number.isFinite(value)) {
336
- throw new UserError(`${name} must be a number.`);
334
+ function positiveDecimalIntegerEnv(env, name) {
335
+ const parsed = parsePositiveDecimalInteger(requireEnv(env, name));
336
+ if (parsed === undefined) {
337
+ throw new UserError(`${name} must be a positive integer.`);
338
+ }
339
+ return parsed;
340
+ }
341
+ function parsePositiveDecimalInteger(value) {
342
+ let parsed = 0;
343
+ for (const char of value) {
344
+ const digit = char.charCodeAt(0) - "0".charCodeAt(0);
345
+ if (digit < 0 || digit > 9) {
346
+ return undefined;
347
+ }
348
+ parsed = parsed * 10 + digit;
349
+ if (!Number.isSafeInteger(parsed)) {
350
+ return undefined;
351
+ }
352
+ }
353
+ return parsed > 0 ? parsed : undefined;
354
+ }
355
+ function assertPositiveInteger(value, label) {
356
+ if (!Number.isInteger(value) || value <= 0) {
357
+ throw new Error(`${label} must be a positive integer.`);
337
358
  }
338
- return value;
339
359
  }
340
360
  function parseJsonObject(value) {
341
361
  try {
@@ -5,7 +5,7 @@ export function runPreflightChecks(context) {
5
5
  }
6
6
  function checkRequiredEnvVar(env, key) {
7
7
  const value = env.get(key);
8
- if (value === undefined || value === "") {
8
+ if (value === undefined || value.trim() === "") {
9
9
  throw new UserError(`Missing required environment variable: ${key}`);
10
10
  }
11
11
  }
@@ -19,9 +19,10 @@ jobs:
19
19
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
20
20
  run: |
21
21
  missing=()
22
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
23
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
22
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
23
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
24
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
25
26
  if [ ${#missing[@]} -gt 0 ]; then
26
27
  for name in "${missing[@]}"; do
27
28
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -24,9 +24,10 @@ jobs:
24
24
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
25
25
  run: |
26
26
  missing=()
27
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
28
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
29
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
27
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
28
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
29
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
30
31
  if [ ${#missing[@]} -gt 0 ]; then
31
32
  for name in "${missing[@]}"; do
32
33
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -82,9 +83,10 @@ jobs:
82
83
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
83
84
  run: |
84
85
  missing=()
85
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
86
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
87
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
86
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
87
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
88
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
89
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
88
90
  if [ ${#missing[@]} -gt 0 ]; then
89
91
  for name in "${missing[@]}"; do
90
92
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -25,9 +25,10 @@ jobs:
25
25
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
26
26
  run: |
27
27
  missing=()
28
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
29
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
28
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
29
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
30
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
31
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
31
32
  if [ ${#missing[@]} -gt 0 ]; then
32
33
  for name in "${missing[@]}"; do
33
34
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -75,9 +76,10 @@ jobs:
75
76
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
76
77
  run: |
77
78
  missing=()
78
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
79
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
80
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
79
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
80
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
81
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
82
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
81
83
  if [ ${#missing[@]} -gt 0 ]; then
82
84
  for name in "${missing[@]}"; do
83
85
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -25,9 +25,10 @@ jobs:
25
25
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
26
26
  run: |
27
27
  missing=()
28
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
29
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
30
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
28
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
29
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
30
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
31
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
31
32
  if [ ${#missing[@]} -gt 0 ]; then
32
33
  for name in "${missing[@]}"; do
33
34
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -84,9 +85,10 @@ jobs:
84
85
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
85
86
  run: |
86
87
  missing=()
87
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
88
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
89
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
88
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
89
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
90
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
91
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
90
92
  if [ ${#missing[@]} -gt 0 ]; then
91
93
  for name in "${missing[@]}"; do
92
94
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -20,9 +20,10 @@ jobs:
20
20
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
21
21
  run: |
22
22
  missing=()
23
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
24
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
23
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
24
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
25
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
26
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
26
27
  if [ ${#missing[@]} -gt 0 ]; then
27
28
  for name in "${missing[@]}"; do
28
29
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -69,9 +70,10 @@ jobs:
69
70
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
70
71
  run: |
71
72
  missing=()
72
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
73
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
74
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
73
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
74
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
75
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
76
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
75
77
  if [ ${#missing[@]} -gt 0 ]; then
76
78
  for name in "${missing[@]}"; do
77
79
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -20,9 +20,10 @@ jobs:
20
20
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
21
21
  run: |
22
22
  missing=()
23
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
24
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
25
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
23
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
24
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
25
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
26
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
26
27
  if [ ${#missing[@]} -gt 0 ]; then
27
28
  for name in "${missing[@]}"; do
28
29
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -69,9 +70,10 @@ jobs:
69
70
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
70
71
  run: |
71
72
  missing=()
72
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
73
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
74
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
73
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
74
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
75
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
76
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
75
77
  if [ ${#missing[@]} -gt 0 ]; then
76
78
  for name in "${missing[@]}"; do
77
79
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -18,9 +18,10 @@ jobs:
18
18
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
19
19
  run: |
20
20
  missing=()
21
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
22
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
23
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
21
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
22
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
23
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
24
25
  if [ ${#missing[@]} -gt 0 ]; then
25
26
  for name in "${missing[@]}"; do
26
27
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"
@@ -18,9 +18,10 @@ jobs:
18
18
  POE_API_KEY: ${{ secrets.POE_API_KEY }}
19
19
  run: |
20
20
  missing=()
21
- [ -z "$POE_CODE_AGENT_APP_ID" ] && missing+=("POE_CODE_AGENT_APP_ID")
22
- [ -z "$POE_CODE_AGENT_PRIVATE_KEY" ] && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
23
- [ -z "$POE_API_KEY" ] && missing+=("POE_API_KEY")
21
+ is_blank() { [[ -z "${1//[[:space:]]/}" ]]; }
22
+ is_blank "$POE_CODE_AGENT_APP_ID" && missing+=("POE_CODE_AGENT_APP_ID")
23
+ is_blank "$POE_CODE_AGENT_PRIVATE_KEY" && missing+=("POE_CODE_AGENT_PRIVATE_KEY")
24
+ is_blank "$POE_API_KEY" && missing+=("POE_API_KEY")
24
25
  if [ ${#missing[@]} -gt 0 ]; then
25
26
  for name in "${missing[@]}"; do
26
27
  echo "::error::Missing required secret: $name — add it in Settings → Secrets and variables → Actions"