@ai-setting/roy-agent-core 1.7.53 → 1.7.55

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 (62) hide show
  1. package/dist/env/agent/index.js +3 -3
  2. package/dist/env/error-reply.d.ts +184 -0
  3. package/dist/env/event-source/event-source-handlers.d.ts +9 -23
  4. package/dist/env/event-source/index.js +6 -6
  5. package/dist/env/index.js +18 -18
  6. package/dist/env/llm/adapter-pi-ai.d.ts +147 -2
  7. package/dist/env/llm/adapter.d.ts +21 -1
  8. package/dist/env/llm/index.js +2 -2
  9. package/dist/env/llm/invoke.d.ts +41 -1
  10. package/dist/env/llm/llm.d.ts +25 -0
  11. package/dist/env/llm/reasoning-defense.d.ts +104 -0
  12. package/dist/env/llm/types.d.ts +26 -0
  13. package/dist/env/prompt/index.js +2 -2
  14. package/dist/env/prompt/prompts-index.d.ts +1 -1
  15. package/dist/env/session/index.js +4 -4
  16. package/dist/env/session/storage/index.js +3 -3
  17. package/dist/env/task/backend/index.js +0 -2
  18. package/dist/env/task/backend/types.d.ts +0 -11
  19. package/dist/env/task/delegate/index.js +2 -2
  20. package/dist/env/task/index.js +3 -3
  21. package/dist/env/task/plugins/card-chat-routing.d.ts +42 -89
  22. package/dist/env/task/plugins/index.js +4 -4
  23. package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +0 -51
  24. package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +14 -31
  25. package/dist/env/task/plugins/per-task-group-chat-plugin.d.ts +4 -4
  26. package/dist/env/workflow/engine/engine.d.ts +65 -0
  27. package/dist/env/workflow/engine/index.js +2 -2
  28. package/dist/env/workflow/index.js +9 -9
  29. package/dist/env/workflow/nodes/index.js +1 -1
  30. package/dist/env/workflow/nodes/tool-node.d.ts +6 -0
  31. package/dist/env/workflow/plugins/index.js +2 -2
  32. package/dist/env/workflow/tools/index.js +6 -6
  33. package/dist/env/workflow/tools/workflow-validate-tool.d.ts +11 -2
  34. package/dist/env/workflow/types/run.d.ts +19 -0
  35. package/dist/env/workflow/utils/agent-session-metadata.d.ts +13 -0
  36. package/dist/env/workflow/utils/index.js +1 -1
  37. package/dist/env/workflow/utils/redact-command-secrets.d.ts +70 -0
  38. package/dist/env/workflow/utils/shell-dialect-lint.d.ts +75 -0
  39. package/dist/env/workflow/utils/validate-workflow-definition.d.ts +22 -0
  40. package/dist/index.js +20 -20
  41. package/dist/shared/@ai-setting/{roy-agent-core-stnddvx9.js → roy-agent-core-12d2xap8.js} +1 -1
  42. package/dist/shared/@ai-setting/{roy-agent-core-pk1b3kvf.js → roy-agent-core-2b8jtv7m.js} +1 -1
  43. package/dist/shared/@ai-setting/{roy-agent-core-x8n1r7h4.js → roy-agent-core-2bscfrr1.js} +188 -7
  44. package/dist/shared/@ai-setting/{roy-agent-core-gdsqp6j8.js → roy-agent-core-6masakz4.js} +45 -0
  45. package/dist/shared/@ai-setting/{roy-agent-core-vvxb9522.js → roy-agent-core-6qxh4xrm.js} +67 -6
  46. package/dist/shared/@ai-setting/{roy-agent-core-h93v6p6y.js → roy-agent-core-7qy3nffr.js} +2 -2
  47. package/dist/shared/@ai-setting/{roy-agent-core-4vpk40ss.js → roy-agent-core-8eqngasy.js} +2 -2
  48. package/dist/shared/@ai-setting/{roy-agent-core-brwzs8wf.js → roy-agent-core-9h72sk1n.js} +1 -1
  49. package/dist/shared/@ai-setting/{roy-agent-core-na73mym1.js → roy-agent-core-a4vzsn0g.js} +212 -1
  50. package/dist/shared/@ai-setting/{roy-agent-core-35s1w7tc.js → roy-agent-core-aer5kw1j.js} +142 -70
  51. package/dist/shared/@ai-setting/{roy-agent-core-j8e92gj8.js → roy-agent-core-b5ew8t0k.js} +0 -59
  52. package/dist/shared/@ai-setting/{roy-agent-core-4sx6sdb2.js → roy-agent-core-cd62e9p1.js} +1 -1
  53. package/dist/shared/@ai-setting/{roy-agent-core-39xejr39.js → roy-agent-core-e2z1etk4.js} +1 -1
  54. package/dist/shared/@ai-setting/{roy-agent-core-hch2geta.js → roy-agent-core-g36jevrk.js} +14 -183
  55. package/dist/shared/@ai-setting/{roy-agent-core-ph5qbqcx.js → roy-agent-core-j2nvedt6.js} +465 -128
  56. package/dist/shared/@ai-setting/{roy-agent-core-p2r27era.js → roy-agent-core-mxdc756a.js} +1 -1
  57. package/dist/shared/@ai-setting/{roy-agent-core-p8ak03s0.js → roy-agent-core-w527pcpe.js} +293 -42
  58. package/dist/shared/@ai-setting/{roy-agent-core-3tv1q6f2.js → roy-agent-core-ytr2w0vb.js} +2 -2
  59. package/dist/shared/@ai-setting/{roy-agent-core-yd21n6c7.js → roy-agent-core-zvemdfx5.js} +1 -1
  60. package/dist/test-utils/child-process-mock.d.ts +73 -0
  61. package/package.json +2 -2
  62. /package/dist/shared/@ai-setting/{roy-agent-core-zy3hqfwg.js → roy-agent-core-0hq21px2.js} +0 -0
@@ -186,6 +186,25 @@ export interface NodeExecutionContext {
186
186
  askUser(query: string): never;
187
187
  /** Patch agent sub-session id onto latest workflow.node.start (agent nodes) */
188
188
  attachAgentSessionToLastStart?(nodeId: string, agentSessionId: string): Promise<void>;
189
+ /**
190
+ * Register (or refresh) an agent sub-session entry in the parent workflow
191
+ * session's `metadata.agentSessions` (Task #4412 C1).
192
+ *
193
+ * AgentNode must use this instead of doing its own
194
+ * `get → push → update` on the parent metadata. That read-modify-write is
195
+ * unsafe once dispatch is concurrent: N sibling agent nodes all read the
196
+ * same parent snapshot and each writes back its own array-with-one-extra
197
+ * entry, so the last writer wins and every sibling's marker is silently
198
+ * dropped (measured: 4 concurrent agents → only 2 markers survive).
199
+ *
200
+ * The engine implements this by routing the mutation through the same
201
+ * per-session serialization queue it uses for its own metadata writes, so
202
+ * the whole class of lost updates is closed by construction.
203
+ *
204
+ * Optional for backward compatibility with hand-built contexts in tests;
205
+ * AgentNode falls back to the legacy inline RMW when it is absent.
206
+ */
207
+ registerAgentSubSession?(nodeId: string, agentSessionId: string): Promise<void>;
189
208
  /**
190
209
  * Abort signal for this node's execution (Task #1976).
191
210
  *
@@ -9,6 +9,19 @@ export declare function updateAgentSessionStatus(agentSessions: AgentSessionRef[
9
9
  * Convenience wrapper over updateAgentSessionStatus for symmetry with Failed/Stopped.
10
10
  */
11
11
  export declare function markAgentSessionCompleted(agentSessions: AgentSessionRef[] | undefined, nodeId: string): AgentSessionRef[];
12
+ /**
13
+ * Register (or refresh) a node's agent sub-session reference.
14
+ *
15
+ * Replaces an existing entry for the same `nodeId` (refresh + reset to
16
+ * 'active') or appends a new one. Returns a new array; does not mutate input.
17
+ *
18
+ * Task #4412 C1: this used to be inline in `AgentNode.createAgentSubSession()`
19
+ * operating directly on the metadata it had just read, which loses entries when
20
+ * sibling agent nodes register concurrently. Extracted here so the engine can
21
+ * run it *inside* its serialized metadata queue (where the array it receives is
22
+ * guaranteed to be the current one).
23
+ */
24
+ export declare function upsertAgentSession(agentSessions: AgentSessionRef[] | undefined, nodeId: string, agentSessionId: string): AgentSessionRef[];
12
25
  /**
13
26
  * Mark a single node's agent session as 'failed'.
14
27
  */
@@ -14,7 +14,7 @@ import {
14
14
  hasClosedOutputContract,
15
15
  validateTemplateContracts,
16
16
  validateWorkflowDefinition
17
- } from "../../../shared/@ai-setting/roy-agent-core-na73mym1.js";
17
+ } from "../../../shared/@ai-setting/roy-agent-core-a4vzsn0g.js";
18
18
  import {
19
19
  TemplateResolver,
20
20
  init_template_resolver,
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview redact-command-secrets.ts — Mask inline secrets in shell commands
3
+ * before they are embedded in a user/agent-visible error message (Task #4392 P0-2).
4
+ *
5
+ * Background: #4385 §5.5 diff-1 asks for `Tool exited with code N` to be enriched
6
+ * with the command that was run. That command may legitimately contain inline
7
+ * credentials (`twine upload --password=...`, `curl -H "Authorization: Bearer ..."`,
8
+ * `PIP_INDEX_TOKEN=... npm publish`), which must NOT leak into:
9
+ * - `workflow.node.end` session messages,
10
+ * - trace span attributes,
11
+ * - the LLM context of the next turn.
12
+ *
13
+ * This helper is a *best-effort* shell-string masker (complementary to
14
+ * `sensitive-redact.ts`, which only redacts object **field names**). It never
15
+ * tries to parse shell; it matches the common credential shapes:
16
+ *
17
+ * 1. `KEY=value` / `KEY: value` / `--flag value` / `--flag=value`
18
+ * where KEY looks sensitive (`ASSIGNMENT_RE`, `FLAG_RE`).
19
+ * 2. `<Scheme> <credential>` auth headers — `Authorization: Bearer <token>`,
20
+ * `Basic <base64>`, `Token <value>`, `Digest <value>` (`AUTH_SCHEME_RE`).
21
+ * The value is a *separate* word from the scheme, hence its own rule.
22
+ * 3. URL query credentials — `?token=`, `&api_key=`, `&secret=`, `&sig=`
23
+ * (`URL_QUERY_RE`).
24
+ * 4. URL userinfo credentials — `https://user:pass@host` (`URL_USERINFO_RE`).
25
+ * 5. Short-option credentials — `curl -u user:pass`, `docker login -p <pw>`,
26
+ * `mysql -pVALUE` (`SHORT_CRED_RE`).
27
+ *
28
+ * ## Why rules 2–5 exist (Task #4419, from #4417 §B-1)
29
+ *
30
+ * The original implementation only had rules 1, and its bare-value branch stops
31
+ * at the first whitespace. `Authorization: Bearer <token>` is *two* words, so it
32
+ * masked `Bearer` and left the token intact. #4417 measured 9 of 14 real command
33
+ * shapes still leaking. Rules 2–5 close those holes.
34
+ *
35
+ * ## Ordering / idempotency
36
+ *
37
+ * The rules are applied in a fixed order and each rule already skips values that
38
+ * equal the `[REDACTED]` sentinel, so `redact(redact(x)) === redact(x)` holds.
39
+ * Rule 2 is applied **before** rule 1: rule 1 would otherwise see
40
+ * `Authorization: Bearer` and mask only the scheme word, leaving an
41
+ * `Authorization: [REDACTED] <token>` remainder that rule 2 can no longer anchor.
42
+ *
43
+ * ## Non-goals
44
+ *
45
+ * - No shell parsing / word-splitting (quoting, `$VAR` expansion, heredocs).
46
+ * - Environment-variable *references* (`$TOKEN`, `${TOKEN}`) are left alone —
47
+ * the variable name is not itself a secret, and masking it destroys the
48
+ * diagnostic value of the message.
49
+ */
50
+ /**
51
+ * Mask inline secrets inside a single shell command string.
52
+ *
53
+ * Idempotent: masked values (`[REDACTED]`) are left as-is.
54
+ *
55
+ * @param command - The raw command string (may be multi-line).
56
+ * @returns The command with sensitive values replaced by `[REDACTED]`.
57
+ */
58
+ export declare function redactCommandSecrets(command: string): string;
59
+ /**
60
+ * Collapse a multi-line command into a single readable line and truncate it.
61
+ *
62
+ * Rationale: error messages are rendered as one line in `workflow.node.end`
63
+ * messages and in most logs; embedding raw newlines makes them unreadable and
64
+ * breaks naive `grep`-based diagnosis.
65
+ *
66
+ * @param command - Raw command (possibly multi-line, possibly huge).
67
+ * @param maxLen - Maximum length of the returned string (default 120).
68
+ * @returns Single-line, whitespace-normalized, truncated command.
69
+ */
70
+ export declare function summarizeCommand(command: string, maxLen?: number): string;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @fileoverview Shell dialect lint for workflow `tool` node commands
3
+ * (Task #4392 P0-3; root cause proven in Task #4385 §3.2.1).
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * The built-in `bash` tool spawns its command with Node's
8
+ * `child_process.spawn(command, [], { shell: true })`
9
+ * (see `env/tool/built-in/bash-effect.ts`). On POSIX, `shell: true` resolves to
10
+ * **`/bin/sh`**, which on Debian/Ubuntu is a symlink to **dash** — *not* bash.
11
+ *
12
+ * Every bash-only construct therefore fails inside a workflow tool node. Worse,
13
+ * half of them fail **silently**:
14
+ *
15
+ * | construct | dash behaviour | exit | loud? |
16
+ * | -------------------- | ----------------------------- | ---- | ----- |
17
+ * | `set -o pipefail` | `Illegal option -o pipefail` | 2 | ✅ |
18
+ * | `${PIPESTATUS[0]}` | `Bad substitution` | 2 | ✅ |
19
+ * | `${V//a/b}` | `Bad substitution` | 2 | ✅ |
20
+ * | `${BASH_SOURCE[0]}` | `Bad substitution` | 2 | ✅ |
21
+ * | `A=(1 2 3)` | `Syntax error: "(" unexpected`| 2 | ✅ |
22
+ * | `function f() {}` | `Syntax error: "(" unexpected`| 2 | ✅ |
23
+ * | `[[ ... ]]` | `[[: not found` | 127 | ✅ |
24
+ * | `source <file>` | `source: not found` | 0 | ❌ |
25
+ * | `echo -e "a\tb"` | prints a literal `-e` | 0 | ❌ |
26
+ * | `$RANDOM` | empty string | 0 | ❌ |
27
+ *
28
+ * Task #4385 measured **63** `/bin/sh:` signature hits across 45 sessions, and
29
+ * these account for 27 of the workflow-creator's `exit 2` failures.
30
+ *
31
+ * ## Severity policy
32
+ *
33
+ * These findings are **warnings, never errors**. The 76 workflows already in
34
+ * `workflows.db` must keep validating cleanly, and a `dash`-safe workflow can
35
+ * legitimately contain the *string* `pipefail` inside an embedded heredoc that
36
+ * is executed by `bash -c` on purpose. Blocking on a heuristic regex would be
37
+ * wrong; surfacing it loudly for the author to judge is right.
38
+ *
39
+ * ## What is deliberately NOT flagged
40
+ *
41
+ * - `. <file>` (POSIX dot-command) — the correct replacement for `source`.
42
+ * - `$?`, `$0`, `$1`… — POSIX.
43
+ * - `[ ... ]` — POSIX test.
44
+ * - `sed 's/a/b/'` — no `${...}` involved.
45
+ * - Text inside shell **comments** (`# ...`) — cannot fail at runtime.
46
+ */
47
+ /** A single detected bash-ism. */
48
+ export interface ShellDialectFinding {
49
+ /** Stable rule name, e.g. `pipefail`. Used in machine-readable output. */
50
+ name: string;
51
+ /** Actionable replacement hint written for an LLM/tool author to act on. */
52
+ fix: string;
53
+ /** Short excerpt of the offending command (surrounding context). */
54
+ excerpt: string;
55
+ }
56
+ /**
57
+ * Detect bash-only constructs in a shell command intended for the `bash` tool.
58
+ *
59
+ * @param command - The raw command string (from `config.command`).
60
+ * @returns One finding per *distinct* rule that matched. Repeated occurrences of
61
+ * the same rule are collapsed (a 50-line script using `$RANDOM` ten
62
+ * times should produce one warning, not ten).
63
+ */
64
+ export declare function lintShellDialect(command: string): ShellDialectFinding[];
65
+ /**
66
+ * Render findings as one actionable line each, prefixed with the node id.
67
+ *
68
+ * Format is deliberately stable so it can be asserted in tests and grepped in
69
+ * logs:
70
+ * `[shell-dialect] node "build-x" uses bash-only "pipefail": <fix> | near: <excerpt>`
71
+ *
72
+ * @param nodeId - The workflow node id that owns the command.
73
+ * @param findings - Output of `lintShellDialect`.
74
+ */
75
+ export declare function formatShellDialectFindings(nodeId: string, findings: ShellDialectFinding[]): string[];
@@ -13,6 +13,14 @@
13
13
  * read `.result` off a **tool** node (which has no such field) and the
14
14
  * engine silently substituted an empty string.
15
15
  *
16
+ * Layer 3 — **Shell dialect lint** (Task #4392 P0-3, see
17
+ * `shell-dialect-lint.ts`): the `bash` tool spawns with `shell: true`,
18
+ * i.e. `/bin/sh` = dash. bash-only constructs (`set -o pipefail`,
19
+ * `${PIPESTATUS[0]}`, `[[ ]]`, `source`, arrays, `$RANDOM`, `echo -e`, ...)
20
+ * either fail loudly or -- worse -- silently no-op. Reported as **warning**
21
+ * only: existing registered workflows must not be invalidated by a
22
+ * heuristic regex.
23
+ *
16
24
  * Wraps everything in a defensive try/catch so callers (workflow_add tool,
17
25
  * `workflow add` CLI, workflow_validate tool, TaskTagPlugin.extractWorkflow)
18
26
  * always get a consistent `{ valid, errors, warnings, infos }` shape — even
@@ -46,6 +54,14 @@ export interface ValidateWorkflowOptions {
46
54
  * incrementally).
47
55
  */
48
56
  skipTemplateContracts?: boolean;
57
+ /**
58
+ * Skip the Layer-3 shell-dialect lint. Defaults to `false`.
59
+ *
60
+ * Layer 3 emits **warnings only**, so there is rarely a reason to disable it;
61
+ * this switch exists for corpus/regression tests that pin the exact warning
62
+ * set of already-registered workflows.
63
+ */
64
+ lintShellDialect?: boolean;
49
65
  }
50
66
  /**
51
67
  * Validate a workflow definition (structure + template contracts).
@@ -55,3 +71,9 @@ export interface ValidateWorkflowOptions {
55
71
  * @returns `{ valid, errors, warnings, infos, findings }` — never throws.
56
72
  */
57
73
  export declare function validateWorkflowDefinition(definition: unknown, options?: ValidateWorkflowOptions): ValidateWorkflowResult;
74
+ /**
75
+ * Walk every `tool` node of a definition and lint its shell command(s).
76
+ *
77
+ * @returns Formatted, actionable warning lines (empty when clean).
78
+ */
79
+ export declare function collectShellDialectWarnings(definition: unknown): string[];
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  PromptComponent,
23
23
  PromptStore
24
- } from "./shared/@ai-setting/roy-agent-core-stnddvx9.js";
24
+ } from "./shared/@ai-setting/roy-agent-core-12d2xap8.js";
25
25
  import {
26
26
  LLMComponent,
27
27
  LLMConfigSchema,
@@ -29,7 +29,7 @@ import {
29
29
  ModelLimitsSchema,
30
30
  ProviderCapabilitiesSchema,
31
31
  ProviderConfigSchema
32
- } from "./shared/@ai-setting/roy-agent-core-p8ak03s0.js";
32
+ } from "./shared/@ai-setting/roy-agent-core-w527pcpe.js";
33
33
  import"./shared/@ai-setting/roy-agent-core-adg9ghbt.js";
34
34
  import {
35
35
  ATTACH_FILE_MAX_BYTES,
@@ -66,10 +66,10 @@ import {
66
66
  BaseEnvironment,
67
67
  generateDescendingId,
68
68
  generateId
69
- } from "./shared/@ai-setting/roy-agent-core-4sx6sdb2.js";
69
+ } from "./shared/@ai-setting/roy-agent-core-cd62e9p1.js";
70
70
  import {
71
71
  TaskComponent
72
- } from "./shared/@ai-setting/roy-agent-core-39xejr39.js";
72
+ } from "./shared/@ai-setting/roy-agent-core-e2z1etk4.js";
73
73
  import"./shared/@ai-setting/roy-agent-core-amkqnyzy.js";
74
74
  import {
75
75
  SQLiteTaskStore,
@@ -78,7 +78,7 @@ import {
78
78
  import"./shared/@ai-setting/roy-agent-core-7g03zkkb.js";
79
79
  import"./shared/@ai-setting/roy-agent-core-rn57psp0.js";
80
80
  import"./shared/@ai-setting/roy-agent-core-8gxth0eh.js";
81
- import"./shared/@ai-setting/roy-agent-core-p2r27era.js";
81
+ import"./shared/@ai-setting/roy-agent-core-mxdc756a.js";
82
82
  import"./shared/@ai-setting/roy-agent-core-tbrn9wdm.js";
83
83
  import {
84
84
  BountyIMInstance,
@@ -92,7 +92,7 @@ import {
92
92
  larkCliHandler,
93
93
  resolveBountyIMSystemPrompt,
94
94
  timerHandler
95
- } from "./shared/@ai-setting/roy-agent-core-ph5qbqcx.js";
95
+ } from "./shared/@ai-setting/roy-agent-core-j2nvedt6.js";
96
96
  import {
97
97
  BUILT_IN_EVENT_SOURCE_TYPES,
98
98
  BUILT_IN_EVENT_SOURCE_TYPE_LIST,
@@ -109,7 +109,7 @@ import {
109
109
  import {
110
110
  TaskTagPlugin,
111
111
  createAutoTaskPlugin
112
- } from "./shared/@ai-setting/roy-agent-core-hch2geta.js";
112
+ } from "./shared/@ai-setting/roy-agent-core-g36jevrk.js";
113
113
  import {
114
114
  EventStoreImpl,
115
115
  getSharedEventStore,
@@ -122,12 +122,12 @@ import {
122
122
  import {
123
123
  getBuiltInPrompt,
124
124
  getBuiltInPromptNames
125
- } from "./shared/@ai-setting/roy-agent-core-gdsqp6j8.js";
126
- import"./shared/@ai-setting/roy-agent-core-brwzs8wf.js";
127
- import"./shared/@ai-setting/roy-agent-core-j8e92gj8.js";
125
+ } from "./shared/@ai-setting/roy-agent-core-6masakz4.js";
126
+ import"./shared/@ai-setting/roy-agent-core-9h72sk1n.js";
127
+ import"./shared/@ai-setting/roy-agent-core-b5ew8t0k.js";
128
128
  import {
129
129
  WorkflowComponent
130
- } from "./shared/@ai-setting/roy-agent-core-4vpk40ss.js";
130
+ } from "./shared/@ai-setting/roy-agent-core-8eqngasy.js";
131
131
  import {
132
132
  init_node_registry_helper,
133
133
  registerDecoratorNodeType
@@ -140,25 +140,25 @@ import {
140
140
  createWorkflowFromClass
141
141
  } from "./shared/@ai-setting/roy-agent-core-h0x19xgn.js";
142
142
  import"./shared/@ai-setting/roy-agent-core-1ce3fqrk.js";
143
- import"./shared/@ai-setting/roy-agent-core-vvxb9522.js";
143
+ import"./shared/@ai-setting/roy-agent-core-6qxh4xrm.js";
144
144
  import {
145
145
  SessionComponent
146
- } from "./shared/@ai-setting/roy-agent-core-yd21n6c7.js";
146
+ } from "./shared/@ai-setting/roy-agent-core-zvemdfx5.js";
147
147
  import {
148
148
  MemorySessionStore
149
- } from "./shared/@ai-setting/roy-agent-core-h93v6p6y.js";
149
+ } from "./shared/@ai-setting/roy-agent-core-7qy3nffr.js";
150
150
  import"./shared/@ai-setting/roy-agent-core-hhrg314p.js";
151
151
  import"./shared/@ai-setting/roy-agent-core-7evvpfwc.js";
152
- import"./shared/@ai-setting/roy-agent-core-35s1w7tc.js";
152
+ import"./shared/@ai-setting/roy-agent-core-aer5kw1j.js";
153
153
  import"./shared/@ai-setting/roy-agent-core-6atd905e.js";
154
154
  import"./shared/@ai-setting/roy-agent-core-6167phd4.js";
155
- import"./shared/@ai-setting/roy-agent-core-x8n1r7h4.js";
155
+ import"./shared/@ai-setting/roy-agent-core-2bscfrr1.js";
156
156
  import"./shared/@ai-setting/roy-agent-core-1db4vpc6.js";
157
157
  import"./shared/@ai-setting/roy-agent-core-ze068vc9.js";
158
158
  import"./shared/@ai-setting/roy-agent-core-fs36xgcs.js";
159
159
  import"./shared/@ai-setting/roy-agent-core-9csa89jx.js";
160
160
  import"./shared/@ai-setting/roy-agent-core-7exqwax1.js";
161
- import"./shared/@ai-setting/roy-agent-core-na73mym1.js";
161
+ import"./shared/@ai-setting/roy-agent-core-a4vzsn0g.js";
162
162
  import"./shared/@ai-setting/roy-agent-core-tjg71zqp.js";
163
163
  import"./shared/@ai-setting/roy-agent-core-ddwa0n6h.js";
164
164
  import"./shared/@ai-setting/roy-agent-core-8s9jd2qy.js";
@@ -170,7 +170,7 @@ import {
170
170
  import {
171
171
  AgentComponent,
172
172
  AgentComponentConfigSchema
173
- } from "./shared/@ai-setting/roy-agent-core-3tv1q6f2.js";
173
+ } from "./shared/@ai-setting/roy-agent-core-ytr2w0vb.js";
174
174
  import {
175
175
  ToolComponent,
176
176
  ToolRegistry,
@@ -186,7 +186,7 @@ import {
186
186
  getXDGPaths
187
187
  } from "./shared/@ai-setting/roy-agent-core-qxnbvgwe.js";
188
188
  import"./shared/@ai-setting/roy-agent-core-dv714bqh.js";
189
- import"./shared/@ai-setting/roy-agent-core-pk1b3kvf.js";
189
+ import"./shared/@ai-setting/roy-agent-core-2b8jtv7m.js";
190
190
  import {
191
191
  buildOpencodeHeaders,
192
192
  createInvokeConfig,
@@ -195,7 +195,7 @@ import {
195
195
  isOpencodeEndpoint,
196
196
  isOpencodeProvider,
197
197
  parseModelString
198
- } from "./shared/@ai-setting/roy-agent-core-zy3hqfwg.js";
198
+ } from "./shared/@ai-setting/roy-agent-core-0hq21px2.js";
199
199
  import"./shared/@ai-setting/roy-agent-core-c1v263jn.js";
200
200
  import {
201
201
  AskUserError,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  builtInPrompts
3
- } from "./roy-agent-core-gdsqp6j8.js";
3
+ } from "./roy-agent-core-6masakz4.js";
4
4
  import {
5
5
  getXDGPath
6
6
  } from "./roy-agent-core-qxnbvgwe.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  safeParseToolArgs
3
- } from "./roy-agent-core-zy3hqfwg.js";
3
+ } from "./roy-agent-core-0hq21px2.js";
4
4
 
5
5
  // src/env/session/session-message-converter.ts
6
6
  import { randomUUID } from "crypto";
@@ -7,6 +7,157 @@ import {
7
7
  __legacyDecorateClassTS
8
8
  } from "./roy-agent-core-fs0mn2jk.js";
9
9
 
10
+ // src/env/workflow/utils/redact-command-secrets.ts
11
+ function replaceTrailing(match, raw) {
12
+ if (raw.length === 0)
13
+ return match;
14
+ const idx = match.lastIndexOf(raw);
15
+ if (idx < 0)
16
+ return match;
17
+ return match.slice(0, idx) + MASK;
18
+ }
19
+ function looksLikeCredentialCommand(command) {
20
+ return PASSWORD_FLAG_TOOL_RE.test(command);
21
+ }
22
+ function looksLikeShortATool(command) {
23
+ return SHORT_A_TOOL_RE.test(command);
24
+ }
25
+ function looksLikePasswordValue(value) {
26
+ if (value.length === 0)
27
+ return false;
28
+ if (PATH_LIKE_RE.test(value))
29
+ return false;
30
+ if (NUMERIC_RE.test(value))
31
+ return false;
32
+ return true;
33
+ }
34
+ function redactCommandSecrets(command) {
35
+ if (!command)
36
+ return command;
37
+ let out = command;
38
+ out = out.replace(AUTH_SCHEME_RE, (match, prefix, scheme, value) => isMasked(value) ? match : `${prefix}${scheme} ${MASK}`);
39
+ out = out.replace(URL_USERINFO_RE, (match, head, value, at) => isMasked(value) ? match : `${head}${MASK}${at}`);
40
+ out = out.replace(URL_QUERY_RE, (match, amp, name, eq, value) => {
41
+ if (!SENSITIVE_QUERY_KEY_RE.test(name))
42
+ return match;
43
+ if (isMasked(value))
44
+ return match;
45
+ return `${amp}${name}${eq}${MASK}`;
46
+ });
47
+ out = out.replace(SHORT_U_RE, (match, lead, flag, user, pass) => {
48
+ if (isMasked(pass))
49
+ return match;
50
+ const name = user.slice(0, -1);
51
+ if (UID_GID_RE.test(name) && UID_GID_RE.test(pass))
52
+ return match;
53
+ if (name === pass)
54
+ return match;
55
+ return `${lead}${flag}${user}${MASK}`;
56
+ });
57
+ out = out.replace(LONG_USER_RE, (match, lead, flag, user, pass) => {
58
+ if (isMasked(pass))
59
+ return match;
60
+ const name = user.slice(0, -1);
61
+ if (UID_GID_RE.test(name) && UID_GID_RE.test(pass))
62
+ return match;
63
+ if (name === pass)
64
+ return match;
65
+ return `${lead}${flag}${user}${MASK}`;
66
+ });
67
+ if (looksLikeCredentialCommand(command)) {
68
+ const maskPassword = (match, lead, flag, dq, sq, bare) => {
69
+ const value = dq ?? sq ?? bare ?? "";
70
+ if (isMasked(value) || !looksLikePasswordValue(value))
71
+ return match;
72
+ if (dq !== undefined)
73
+ return `${lead}${flag}"${MASK}"`;
74
+ if (sq !== undefined)
75
+ return `${lead}${flag}'${MASK}'`;
76
+ return lead + flag + MASK;
77
+ };
78
+ out = out.replace(SHORT_P_SPACED_RE, maskPassword);
79
+ out = out.replace(SHORT_P_ATTACHED_RE, maskPassword);
80
+ }
81
+ out = out.replace(AUTH_FAILURE_CRED_RE, (match, head, user, pass) => isMasked(pass) ? match : `${head}${user}:${MASK}`);
82
+ out = out.replace(AWS_SET_SECRET_RE, (match, key, value) => isMasked(value) ? match : `${key} ${MASK}`);
83
+ if (looksLikeShortATool(command)) {
84
+ out = out.replace(SHORT_A_SECRET_RE, (match, lead, flag, value) => isMasked(value) || !looksLikePasswordValue(value) ? match : `${lead}${flag}${MASK}`);
85
+ out = out.replace(SHORT_A_ATTACHED_RE, (match, lead, flag, value) => isMasked(value) || !looksLikePasswordValue(value) ? match : `${lead}${flag}${MASK}`);
86
+ }
87
+ out = out.replace(ASSIGNMENT_RE, (match, key, dq, sq, bare) => {
88
+ if (!SENSITIVE_KEY_RE.test(key))
89
+ return match;
90
+ const value = dq ?? sq ?? bare ?? "";
91
+ if (value === MASK)
92
+ return match;
93
+ const isAuthHeaderKey = /^(?:proxy-)?authorization$/i.test(key);
94
+ if (isAuthHeaderKey && AUTH_SCHEME_WORD_RE.test(value))
95
+ return match;
96
+ const raw = dq !== undefined ? `"${value}"` : sq !== undefined ? `'${value}'` : value;
97
+ return replaceTrailing(match, raw);
98
+ });
99
+ out = out.replace(FLAG_RE, (match, lead, flag, _sep, dq, sq, bare) => {
100
+ if (!SENSITIVE_KEY_RE.test(flag))
101
+ return match;
102
+ const value = dq ?? sq ?? bare ?? "";
103
+ if (value === MASK)
104
+ return match;
105
+ const raw = dq !== undefined ? `"${value}"` : sq !== undefined ? `'${value}'` : value;
106
+ return replaceTrailing(match, raw);
107
+ });
108
+ return out;
109
+ }
110
+ function summarizeCommand(command, maxLen = 120) {
111
+ if (!command)
112
+ return "";
113
+ const collapsed = command.replace(/\s+/g, " ").trim();
114
+ if (collapsed.length <= maxLen)
115
+ return collapsed;
116
+ return `${collapsed.slice(0, maxLen)}…`;
117
+ }
118
+ var MASK = "[REDACTED]", SENSITIVE_KEY_RE, BARE_VALUE = `[^\\s;&|]+[^\\s;&|"'<>()]|[^\\s;&|]`, ASSIGNMENT_RE, FLAG_RE, AUTH_SCHEME_RE, SENSITIVE_QUERY_KEY_RE, URL_QUERY_RE, URL_USERINFO_RE, AUTH_FAILURE_CRED_RE, SHORT_U_RE, LONG_USER_RE, UID_GID_RE, SHORT_P_SPACED_RE, SHORT_P_ATTACHED_RE, isMasked = (value) => (value ?? "").trim() === MASK, AUTH_SCHEME_WORD_RE, PASSWORD_FLAG_TOOL_RE, SHORT_A_TOOL_RE, SHORT_A_SECRET_RE, SHORT_A_ATTACHED_RE, AWS_SET_SECRET_RE, PATH_LIKE_RE, NUMERIC_RE;
119
+ var init_redact_command_secrets = __esm(() => {
120
+ SENSITIVE_KEY_RE = /(?:pass(?:word|wd|phrase)?|token|secret|api[_-]?key|apikey|credential|authorization|private[_-]?key)/i;
121
+ ASSIGNMENT_RE = new RegExp(`(?<![A-Za-z0-9_.-])([A-Za-z0-9_][A-Za-z0-9_.-]*)\\s*[=:]\\s*(?:"([^"]*)"|'([^']*)'|(${BARE_VALUE}))`, "g");
122
+ FLAG_RE = new RegExp(`(^|[\\s])(--?[A-Za-z0-9][A-Za-z0-9_.-]*)(=\\s*|\\s+)(?:"([^"]*)"|'([^']*)'|(${BARE_VALUE}))`, "g");
123
+ AUTH_SCHEME_RE = new RegExp(`((?:Proxy-)?Authorization["']?\\s*[:=]\\s*["']?\\s*)(Bearer|Basic|Token|Digest)\\s+(${BARE_VALUE}|\\[REDACTED\\])`, "gi");
124
+ SENSITIVE_QUERY_KEY_RE = new RegExp([
125
+ "^pass(?:word|wd)?$",
126
+ "^pwd$",
127
+ "^token$",
128
+ "^access[_-]?token$",
129
+ "^refresh[_-]?token$",
130
+ "^id[_-]?token$",
131
+ "^secret$",
132
+ "^client[_-]?secret$",
133
+ "^api[_-]?key$",
134
+ "^apikey$",
135
+ "^credential$",
136
+ "^credentials$",
137
+ "^sig$",
138
+ "^signature$",
139
+ "^auth$",
140
+ "^authorization$",
141
+ "^private[_-]?key$"
142
+ ].join("|"), "i");
143
+ URL_QUERY_RE = /([?&])([A-Za-z_][A-Za-z0-9_.-]*)(=)([^&#\s"']+)/g;
144
+ URL_USERINFO_RE = /(\/\/[^/\s:@]+:)([^/\s"']+)(@)/g;
145
+ AUTH_FAILURE_CRED_RE = /(\b(?:auth(?:entication|orization)?|login|credentials?|password|passwd|token)\b[^\n:]{0,40}?[\s"'])([A-Za-z0-9_.-]{1,64}):([^\s;&|"'<>]{3,})/gi;
146
+ SHORT_U_RE = /(^|\s)(-u\s+)([^:\s]+:)([^\s;&|"']+)/g;
147
+ LONG_USER_RE = /(^|\s)(--user(?:=|\s+))([^:\s]+:)([^\s;&|"']+)/g;
148
+ UID_GID_RE = /^\d+$/;
149
+ SHORT_P_SPACED_RE = new RegExp(`(^|\\s)(-p\\s+)(?:"([^"]*)"|'([^']*)'|(${BARE_VALUE}))`, "g");
150
+ SHORT_P_ATTACHED_RE = new RegExp(`(^|\\s)(-p)(?:"([^"]*)"|'([^']*)'|(${BARE_VALUE}))`, "g");
151
+ AUTH_SCHEME_WORD_RE = /^(?:bearer|basic|token|digest|negotiate|ntlm)$/i;
152
+ PASSWORD_FLAG_TOOL_RE = /(?<![\w/.-])(?:docker\s+login|helm\s+(?:registry\s+)?login|mysql|mysqldump|mariadb|sshpass)\b/i;
153
+ SHORT_A_TOOL_RE = /(?<![\w/.-])redis-cli\b/i;
154
+ SHORT_A_SECRET_RE = new RegExp(`(^|\\s)(-a\\s+)(?!-)(${BARE_VALUE})`, "g");
155
+ SHORT_A_ATTACHED_RE = new RegExp(`(^|\\s)(-a)(${BARE_VALUE})`, "g");
156
+ AWS_SET_SECRET_RE = new RegExp(`\\b((?:aws[_-])?(?:secret[_-]?access[_-]?key|session[_-]?token))\\s+(?!set\\b)([^=\\s;&|][^\\s;&|]*[^\\s;&|"'<>()]|[^=\\s;&|])`, "gi");
157
+ PATH_LIKE_RE = /^(?:\/|\.\/|\.\.\/|~\/)/;
158
+ NUMERIC_RE = /^\d+$/;
159
+ });
160
+
10
161
  // src/env/workflow/nodes/tool-node.ts
11
162
  function isPositiveNumber(v) {
12
163
  return typeof v === "number" && Number.isFinite(v) && v > 0;
@@ -23,9 +174,39 @@ function getToolTimeoutMs(input, config) {
23
174
  }
24
175
  return DEFAULT_TOOL_TIMEOUT_MS;
25
176
  }
26
- var DEFAULT_TOOL_TIMEOUT_MS = 60000, ToolNode;
177
+ function redactTail(text, tailChars) {
178
+ const window = text.length > tailChars + REDACT_TAIL_SLACK ? text.slice(-(tailChars + REDACT_TAIL_SLACK)) : text;
179
+ return redactCommandSecrets(window).trim().slice(-tailChars).trim();
180
+ }
181
+ function redactErrorForOutput(err) {
182
+ const message = redactCommandSecrets(err.message);
183
+ const stack = typeof err.stack === "string" ? redactCommandSecrets(err.stack) : undefined;
184
+ if (message === err.message && stack === err.stack)
185
+ return err;
186
+ const clone = new Error(message, { cause: err });
187
+ clone.name = err.name;
188
+ if (stack)
189
+ clone.stack = stack;
190
+ return clone;
191
+ }
192
+ function buildExitCodeError(exitCode, md, toolInput) {
193
+ const parts = [`Tool exited with code ${exitCode}`];
194
+ const rawCommand = toolInput && typeof toolInput === "object" ? toolInput.command ?? toolInput.cmd : undefined;
195
+ if (typeof rawCommand === "string" && rawCommand.trim().length > 0) {
196
+ const safe = summarizeCommand(redactCommandSecrets(rawCommand));
197
+ if (safe.length > 0) {
198
+ parts.push(`command: ${safe}`);
199
+ }
200
+ }
201
+ const stdout = typeof md.stdout === "string" ? md.stdout : "";
202
+ const stdoutTail = redactTail(stdout, 300);
203
+ parts.push(stdoutTail.length > 0 ? `stdout tail: ${stdoutTail}` : "(no stdout)");
204
+ return parts.join(" | ");
205
+ }
206
+ var DEFAULT_TOOL_TIMEOUT_MS = 60000, REDACT_TAIL_SLACK = 4096, ToolNode;
27
207
  var init_tool_node = __esm(() => {
28
208
  init_decorator();
209
+ init_redact_command_secrets();
29
210
  ToolNode = class ToolNode {
30
211
  definition;
31
212
  toolRegistry;
@@ -125,7 +306,7 @@ var init_tool_node = __esm(() => {
125
306
  }
126
307
  }
127
308
  const extractedOutput = this.extractFromWrapper(output);
128
- const wrapperError = this.extractErrorFromWrapper(output);
309
+ const wrapperError = this.extractErrorFromWrapper(output, input);
129
310
  return {
130
311
  output: extractedOutput,
131
312
  error: wrapperError,
@@ -134,7 +315,7 @@ var init_tool_node = __esm(() => {
134
315
  } catch (error) {
135
316
  return {
136
317
  output: undefined,
137
- error: error instanceof Error ? error : new Error(String(error)),
318
+ error: error instanceof Error ? redactErrorForOutput(error) : new Error(redactCommandSecrets(String(error))),
138
319
  durationMs: Date.now() - startTime
139
320
  };
140
321
  }
@@ -159,7 +340,7 @@ var init_tool_node = __esm(() => {
159
340
  }
160
341
  return result;
161
342
  }
162
- extractErrorFromWrapper(value) {
343
+ extractErrorFromWrapper(value, toolInput) {
163
344
  if (value === null || value === undefined) {
164
345
  return;
165
346
  }
@@ -172,10 +353,10 @@ var init_tool_node = __esm(() => {
172
353
  }
173
354
  const err = obj.error;
174
355
  if (typeof err === "string" && err.length > 0) {
175
- return err;
356
+ return redactCommandSecrets(err);
176
357
  }
177
358
  if (err instanceof Error) {
178
- return err;
359
+ return redactErrorForOutput(err);
179
360
  }
180
361
  const md = obj.metadata;
181
362
  if (md) {
@@ -185,7 +366,7 @@ var init_tool_node = __esm(() => {
185
366
  }
186
367
  if (typeof md.exit_code === "number" && md.exit_code !== 0) {
187
368
  const stderr = typeof md.stderr === "string" ? md.stderr : "";
188
- return stderr.length > 0 ? stderr : `Tool exited with code ${md.exit_code}`;
369
+ return stderr.length > 0 ? redactCommandSecrets(stderr) : buildExitCodeError(md.exit_code, md, toolInput);
189
370
  }
190
371
  }
191
372
  return `Tool execution failed (success=false, no error message)`;