@ikarmic/forge-core 5.1.0 → 5.2.0

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 (87) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/agent.js +39 -5
  3. package/dist/agent/goal.d.ts +5 -8
  4. package/dist/agent/prompts.d.ts +25 -1
  5. package/dist/agent/prompts.js +61 -17
  6. package/dist/agent/race-abort.d.ts +8 -0
  7. package/dist/agent/race-abort.js +24 -0
  8. package/dist/agent/stack-facts.d.ts +23 -0
  9. package/dist/agent/stack-facts.js +150 -0
  10. package/dist/code-index/parser.js +48 -3
  11. package/dist/github/github-tools.d.ts +2 -18
  12. package/dist/index.d.ts +7 -3
  13. package/dist/index.js +8 -3
  14. package/dist/journey/answers-block.d.ts +17 -0
  15. package/dist/journey/answers-block.js +28 -0
  16. package/dist/journey/index.d.ts +9 -0
  17. package/dist/journey/index.js +8 -0
  18. package/dist/journey/journey.d.ts +13 -0
  19. package/dist/journey/journey.js +40 -0
  20. package/dist/journey/offer.d.ts +25 -0
  21. package/dist/journey/offer.js +49 -0
  22. package/dist/journey/questions.d.ts +23 -0
  23. package/dist/journey/questions.js +49 -0
  24. package/dist/journey/stages.d.ts +13 -0
  25. package/dist/journey/stages.js +107 -0
  26. package/dist/journey/survey.d.ts +10 -0
  27. package/dist/journey/survey.js +203 -0
  28. package/dist/journey/trigger.d.ts +19 -0
  29. package/dist/journey/trigger.js +79 -0
  30. package/dist/journey/types.d.ts +72 -0
  31. package/dist/journey/types.js +1 -0
  32. package/dist/mcp/json-schema-to-zod.js +12 -1
  33. package/dist/orchestrator/index.d.ts +1 -1
  34. package/dist/orchestrator/index.js +1 -1
  35. package/dist/orchestrator/orchestrator.d.ts +45 -6
  36. package/dist/orchestrator/orchestrator.js +62 -12
  37. package/dist/orchestrator/router.d.ts +1 -1
  38. package/dist/orchestrator/router.js +4 -1
  39. package/dist/orchestrator/specialists.d.ts +6 -1
  40. package/dist/orchestrator/specialists.js +165 -68
  41. package/dist/orchestrator/types.d.ts +1 -1
  42. package/dist/policy/policy.d.ts +6 -59
  43. package/dist/pricing.d.ts +2 -0
  44. package/dist/pricing.js +35 -16
  45. package/dist/skills/builtin.js +1 -1
  46. package/dist/specs/generate.d.ts +18 -9
  47. package/dist/specs/generate.js +174 -14
  48. package/dist/specs/index.d.ts +2 -2
  49. package/dist/specs/index.js +1 -1
  50. package/dist/specs/store.d.ts +14 -2
  51. package/dist/specs/store.js +26 -1
  52. package/dist/specs/types.d.ts +11 -0
  53. package/dist/structured/schema.js +9 -12
  54. package/dist/tools/apply-patch.d.ts +1 -5
  55. package/dist/tools/ask-user.d.ts +2 -10
  56. package/dist/tools/ask-user.js +39 -3
  57. package/dist/tools/browser-tools.d.ts +15 -31
  58. package/dist/tools/codebase-search.d.ts +1 -7
  59. package/dist/tools/dependency-audit.d.ts +30 -0
  60. package/dist/tools/dependency-audit.js +197 -0
  61. package/dist/tools/edit-file.d.ts +1 -15
  62. package/dist/tools/fetch-url.d.ts +1 -18
  63. package/dist/tools/find-references.d.ts +1 -5
  64. package/dist/tools/find-symbol.d.ts +10 -8
  65. package/dist/tools/git-diff.d.ts +13 -0
  66. package/dist/tools/git-diff.js +85 -0
  67. package/dist/tools/index.d.ts +3 -1
  68. package/dist/tools/index.js +5 -1
  69. package/dist/tools/list-files.d.ts +1 -19
  70. package/dist/tools/list-symbols.d.ts +1 -5
  71. package/dist/tools/memory.d.ts +23 -43
  72. package/dist/tools/notebook.d.ts +11 -17
  73. package/dist/tools/read-file.d.ts +1 -11
  74. package/dist/tools/read-file.js +5 -0
  75. package/dist/tools/read-image.d.ts +1 -12
  76. package/dist/tools/read-only.d.ts +1 -1
  77. package/dist/tools/read-only.js +2 -0
  78. package/dist/tools/run-command.d.ts +1 -17
  79. package/dist/tools/search-files.d.ts +1 -17
  80. package/dist/tools/sub-agent-wait.d.ts +2 -8
  81. package/dist/tools/sub-agent.d.ts +2 -70
  82. package/dist/tools/sub-agent.js +3 -0
  83. package/dist/tools/todo.d.ts +8 -20
  84. package/dist/tools/web-search.d.ts +1 -7
  85. package/dist/tools/write-file.d.ts +1 -7
  86. package/dist/types.d.ts +27 -0
  87. package/package.json +3 -3
@@ -26,19 +26,8 @@ import { z } from 'zod';
26
26
  import type { ToolDefinition } from '../types.js';
27
27
  declare const params: z.ZodObject<{
28
28
  path: z.ZodString;
29
- /**
30
- * Maximum bytes to read. The tool errors if the file exceeds this
31
- * limit; the default is 5 MB which covers most screenshots and
32
- * diagrams without flooding the model context.
33
- */
34
29
  max_bytes: z.ZodOptional<z.ZodNumber>;
35
- }, "strip", z.ZodTypeAny, {
36
- path: string;
37
- max_bytes?: number | undefined;
38
- }, {
39
- path: string;
40
- max_bytes?: number | undefined;
41
- }>;
30
+ }, z.core.$strip>;
42
31
  export interface ReadImageResult {
43
32
  path: string;
44
33
  mime: string;
@@ -3,6 +3,6 @@
3
3
  * anything. Asking before each of them is noise, so they are approved without a prompt by default;
4
4
  * edits, commands, web access and sub-agents still ask.
5
5
  */
6
- export declare const READ_ONLY_TOOLS: readonly ["read_file", "list_files", "search_files", "find_symbol", "list_symbols", "find_references", "codebase_search", "memory_read", "sub_agent_wait"];
6
+ export declare const READ_ONLY_TOOLS: readonly ["read_file", "list_files", "search_files", "find_symbol", "list_symbols", "find_references", "git_diff", "codebase_search", "memory_read", "sub_agent_wait"];
7
7
  /** The tools that run without a prompt: the user's list, or the read-only tools when none is set. */
8
8
  export declare function resolveAutoApprove(configured?: readonly string[]): string[];
@@ -10,6 +10,8 @@ export const READ_ONLY_TOOLS = [
10
10
  'find_symbol',
11
11
  'list_symbols',
12
12
  'find_references',
13
+ // Runs one fixed git command; refuses option-shaped refs.
14
+ 'git_diff',
13
15
  'codebase_search',
14
16
  'memory_read',
15
17
  // Only observes the sub-agents the person already let start.
@@ -2,25 +2,9 @@ import { z } from 'zod';
2
2
  import type { ToolDefinition } from '../types.js';
3
3
  declare const params: z.ZodObject<{
4
4
  command: z.ZodString;
5
- /**
6
- * Optional explicit timeout in ms. Default 60_000 (1 minute). Set to 0 to
7
- * disable (not recommended).
8
- */
9
5
  timeout_ms: z.ZodOptional<z.ZodNumber>;
10
- /**
11
- * Optional working directory override. Must be inside the project root
12
- * unless the configured ToolContext permits otherwise.
13
- */
14
6
  cwd: z.ZodOptional<z.ZodString>;
15
- }, "strip", z.ZodTypeAny, {
16
- command: string;
17
- timeout_ms?: number | undefined;
18
- cwd?: string | undefined;
19
- }, {
20
- command: string;
21
- timeout_ms?: number | undefined;
22
- cwd?: string | undefined;
23
- }>;
7
+ }, z.core.$strip>;
24
8
  export interface RunCommandResult {
25
9
  command: string;
26
10
  exitCode: number | null;
@@ -4,26 +4,10 @@ declare const params: z.ZodObject<{
4
4
  pattern: z.ZodString;
5
5
  path: z.ZodOptional<z.ZodString>;
6
6
  include: z.ZodOptional<z.ZodString>;
7
- /** Maximum matches to return. Default 200. */
8
7
  max_results: z.ZodOptional<z.ZodNumber>;
9
8
  include_ignored: z.ZodOptional<z.ZodBoolean>;
10
- /** Show a few lines of context around each match. */
11
9
  context_lines: z.ZodOptional<z.ZodNumber>;
12
- }, "strip", z.ZodTypeAny, {
13
- pattern: string;
14
- path?: string | undefined;
15
- include?: string | undefined;
16
- max_results?: number | undefined;
17
- include_ignored?: boolean | undefined;
18
- context_lines?: number | undefined;
19
- }, {
20
- pattern: string;
21
- path?: string | undefined;
22
- include?: string | undefined;
23
- max_results?: number | undefined;
24
- include_ignored?: boolean | undefined;
25
- context_lines?: number | undefined;
26
- }>;
10
+ }, z.core.$strip>;
27
11
  export interface SearchMatch {
28
12
  path: string;
29
13
  line: number;
@@ -1,15 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import type { ToolDefinition } from '../types.js';
3
3
  declare const params: z.ZodObject<{
4
- ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
4
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
5
  timeout_seconds: z.ZodOptional<z.ZodNumber>;
6
- }, "strip", z.ZodTypeAny, {
7
- ids?: string[] | undefined;
8
- timeout_seconds?: number | undefined;
9
- }, {
10
- ids?: string[] | undefined;
11
- timeout_seconds?: number | undefined;
12
- }>;
6
+ }, z.core.$strip>;
13
7
  export interface SubAgentWaitResult {
14
8
  agents: Array<{
15
9
  id: string;
@@ -2,84 +2,16 @@ import { z } from 'zod';
2
2
  import { type AgentDef } from '../agents/agent-files.js';
3
3
  import type { AgentConfig, ModelConfig, ToolContext, ToolDefinition } from '../types.js';
4
4
  declare const params: z.ZodObject<{
5
- /** The task for the sub-agent to perform. Free-form text. */
6
5
  task: z.ZodString;
7
- /** Name of an agent file (`.forge/agents/<name>.md`) to run as: its prompt, tools, model and step cap. */
8
6
  agent: z.ZodOptional<z.ZodString>;
9
- /** Hard cap on iterations for the sub-agent. Default 10. */
10
7
  max_iterations: z.ZodOptional<z.ZodNumber>;
11
- /**
12
- * Run the sub-agent without approval prompts (autonomous). Defaults to
13
- * `false` even when the parent is in `--auto` mode: the sub-agent is
14
- * expected to be focused and short-lived, so the explicit opt-in is
15
- * deliberate to avoid runaway destructive work.
16
- */
17
8
  auto: z.ZodOptional<z.ZodBoolean>;
18
- /**
19
- * Working directory for the sub-agent. Defaults to the parent's cwd.
20
- * Useful when the sub-task should operate on a subdirectory without
21
- * dragging the parent through the navigation.
22
- */
23
9
  cwd: z.ZodOptional<z.ZodString>;
24
- /**
25
- * Run the sub-agent in an isolated git worktree. The worktree is
26
- * created at `<repoRoot>/.forge/worktrees/<label>/`, the child runs
27
- * there, and the worktree is removed on completion (success or
28
- * error). Falls back to plain `cwd` mode (with a stderr warning)
29
- * when the parent's cwd is not inside a git repo.
30
- *
31
- * Pair this with `orchestrator run` parallel dispatch (v2.3) to
32
- * safely run multiple specialists concurrently without them
33
- * clobbering each other's files.
34
- */
35
10
  use_worktree: z.ZodOptional<z.ZodBoolean>;
36
- /**
37
- * Human-readable label for the worktree (used in the branch name and
38
- * directory). Defaults to a random short hash. Ignored when
39
- * `use_worktree` is false.
40
- */
41
11
  worktree_label: z.ZodOptional<z.ZodString>;
42
- /**
43
- * v2.14: when `use_worktree: true`, also delete the auto-created
44
- * `forge/<label>-<short-sha>` branch once the worktree's working
45
- * tree is gone. Default `true` because sub-agents are short-lived
46
- * and orphan branches are pure clutter.
47
- *
48
- * Set to `false` when you want to inspect the diff afterwards (e.g.
49
- * `git diff main..forge/<label>-<sha>`) or hand the branch to a
50
- * human reviewer.
51
- *
52
- * The branch is only deleted when no other worktree currently
53
- * references it, so two Forge sessions working on the same branch
54
- * won't collide.
55
- */
56
12
  cleanup_branch: z.ZodOptional<z.ZodBoolean>;
57
- /**
58
- * Start the child and return at once. The child keeps working while the parent continues; collect its answer with
59
- * `sub_agent_wait`. Only where the surface can show background runs; elsewhere the child runs to completion as usual.
60
- */
61
13
  background: z.ZodOptional<z.ZodBoolean>;
62
- }, "strip", z.ZodTypeAny, {
63
- task: string;
64
- agent?: string | undefined;
65
- cwd?: string | undefined;
66
- auto?: boolean | undefined;
67
- background?: boolean | undefined;
68
- max_iterations?: number | undefined;
69
- use_worktree?: boolean | undefined;
70
- worktree_label?: string | undefined;
71
- cleanup_branch?: boolean | undefined;
72
- }, {
73
- task: string;
74
- agent?: string | undefined;
75
- cwd?: string | undefined;
76
- auto?: boolean | undefined;
77
- background?: boolean | undefined;
78
- max_iterations?: number | undefined;
79
- use_worktree?: boolean | undefined;
80
- worktree_label?: string | undefined;
81
- cleanup_branch?: boolean | undefined;
82
- }>;
14
+ }, z.core.$strip>;
83
15
  /** What `sub_agent { background: true }` returns instead of a result. */
84
16
  export interface SubAgentStarted {
85
17
  started: true;
@@ -145,7 +77,7 @@ export declare function childAgentConfig(setup: {
145
77
  model: ModelConfig;
146
78
  maxIterations: number;
147
79
  systemPrompt?: string;
148
- }, ctx: Pick<ToolContext, 'autoApproveTools' | 'permissionRules' | 'toolSandbox'>, cwd: string, auto: boolean): AgentConfig;
80
+ }, ctx: Pick<ToolContext, 'autoApproveTools' | 'permissionRules' | 'toolSandbox' | 'askBudget'>, cwd: string, auto: boolean): AgentConfig;
149
81
  /** What a child runs without asking: what the parent does, else the read-only tools. Destructive tools still never run unasked. */
150
82
  export declare function childAutoApprove(ctx: Pick<ToolContext, 'autoApproveTools'>): string[];
151
83
  /** The configured sub-agent model, else the parent's, else a last-resort default. */
@@ -328,6 +328,9 @@ export function childAgentConfig(setup, ctx, cwd, auto) {
328
328
  autoApproveTools: childAutoApprove(ctx),
329
329
  ...(ctx.permissionRules ? { permissionRules: ctx.permissionRules } : {}),
330
330
  ...(ctx.toolSandbox ? { toolSandbox: ctx.toolSandbox } : {}),
331
+ // The same budget object, not a copy: a child that started its own four
332
+ // would be a way around the limit the parent is under (RB-14).
333
+ ...(ctx.askBudget ? { askBudget: ctx.askBudget } : {}),
331
334
  // The child's toolset is the built-in set minus sub_agent, narrowed by the agent file when one is named.
332
335
  disableBuiltins: true,
333
336
  extraTools: setup.tools,
@@ -7,26 +7,14 @@ import type { TodoItem, ToolDefinition } from '../types.js';
7
7
  declare const writeParams: z.ZodObject<{
8
8
  todos: z.ZodArray<z.ZodObject<{
9
9
  content: z.ZodString;
10
- status: z.ZodEnum<["pending", "in_progress", "completed"]>;
11
- }, "strip", z.ZodTypeAny, {
12
- status: "pending" | "in_progress" | "completed";
13
- content: string;
14
- }, {
15
- status: "pending" | "in_progress" | "completed";
16
- content: string;
17
- }>, "many">;
18
- }, "strip", z.ZodTypeAny, {
19
- todos: {
20
- status: "pending" | "in_progress" | "completed";
21
- content: string;
22
- }[];
23
- }, {
24
- todos: {
25
- status: "pending" | "in_progress" | "completed";
26
- content: string;
27
- }[];
28
- }>;
29
- declare const readParams: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
10
+ status: z.ZodEnum<{
11
+ pending: "pending";
12
+ in_progress: "in_progress";
13
+ completed: "completed";
14
+ }>;
15
+ }, z.core.$strip>>;
16
+ }, z.core.$strip>;
17
+ declare const readParams: z.ZodObject<{}, z.core.$strip>;
30
18
  export declare const todoWriteTool: ToolDefinition<z.infer<typeof writeParams>, {
31
19
  todos: TodoItem[];
32
20
  }>;
@@ -39,13 +39,7 @@ export declare function searchWeb(cfg: WebSearchConfig, query: string, count: nu
39
39
  declare const params: z.ZodObject<{
40
40
  query: z.ZodString;
41
41
  max_results: z.ZodOptional<z.ZodNumber>;
42
- }, "strip", z.ZodTypeAny, {
43
- query: string;
44
- max_results?: number | undefined;
45
- }, {
46
- query: string;
47
- max_results?: number | undefined;
48
- }>;
42
+ }, z.core.$strip>;
49
43
  export interface WebSearchToolResult {
50
44
  provider: WebSearchProvider;
51
45
  query: string;
@@ -3,13 +3,7 @@ import type { ToolDefinition } from '../types.js';
3
3
  declare const params: z.ZodObject<{
4
4
  path: z.ZodString;
5
5
  content: z.ZodString;
6
- }, "strip", z.ZodTypeAny, {
7
- path: string;
8
- content: string;
9
- }, {
10
- path: string;
11
- content: string;
12
- }>;
6
+ }, z.core.$strip>;
13
7
  export interface WriteFileResult {
14
8
  path: string;
15
9
  bytes: number;
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { ModelMessage, LanguageModel } from 'ai';
2
2
  import type { z } from 'zod';
3
3
  import type { BackgroundAgents } from './agent/background.js';
4
4
  import type { Attachment } from './attachments.js';
5
+ import type { Answer } from './journey/types.js';
5
6
  import type { SkillRegistry } from './skills/types.js';
6
7
  /**
7
8
  * The summarizer takes a chunk of messages and returns a structured
@@ -114,6 +115,15 @@ export interface ToolContext {
114
115
  maxOutputChars?: number;
115
116
  /** Asks the person a question (`ask_user`); absent when no surface can answer. */
116
117
  askUser?: (question: UserQuestion, signal?: AbortSignal) => Promise<string>;
118
+ /**
119
+ * How many questions this run may still ask (a guided journey's interview
120
+ * budget). Mutated in place as questions are asked, and handed to a child
121
+ * agent so a child cannot start a fresh four (RB-14). Absent means no limit.
122
+ */
123
+ askBudget?: {
124
+ max: number;
125
+ used: number;
126
+ };
117
127
  /** The run's todo list. `set` also tells the UI (`todo_updated`). Supplied by the Agent. */
118
128
  todos?: {
119
129
  get(): TodoItem[];
@@ -554,6 +564,8 @@ export interface AgentConfig {
554
564
  * be surprising.
555
565
  */
556
566
  disableMemory?: boolean;
567
+ /** Leave out the `<stack>` block (the versions the workspace's files state). Default: included. */
568
+ disableStackFacts?: boolean;
557
569
  /**
558
570
  * Skip injecting `AGENTS.md` / `CLAUDE.md` / `CONVENTIONS.md` from the
559
571
  * working directory into the system prompt.
@@ -570,6 +582,13 @@ export interface AgentConfig {
570
582
  * this project is checked and built. Added to the system prompt after the project instructions.
571
583
  */
572
584
  projectCommands?: string;
585
+ /**
586
+ * Answers the person gave in a guided journey's interview, rendered into the
587
+ * system prompt as a `<journey-answers>` block. The interview runs before the
588
+ * first agent run, because the blocks are assembled only on a session's first
589
+ * turn (see `buildInitialMessages`), so answers that arrive later cannot enter.
590
+ */
591
+ journeyAnswers?: Answer[];
573
592
  /**
574
593
  * Override the byte budget for memory injected into the system prompt.
575
594
  * Default 8 KB. Larger budgets use more context window but surface more
@@ -734,6 +753,14 @@ export interface AgentConfig {
734
753
  * Answers `ask_user`. When absent, or when `auto` is on, the model is not offered the tool.
735
754
  */
736
755
  askUser?: (question: UserQuestion, signal?: AbortSignal) => Promise<string>;
756
+ /**
757
+ * How many `ask_user` questions this run may ask. Reaches tools as
758
+ * `ToolContext.askBudget` and is handed down to sub-agents. Absent means no limit.
759
+ */
760
+ askBudget?: {
761
+ max: number;
762
+ used: number;
763
+ };
737
764
  /** The model `sub_agent` children run on; the parent's model when unset. */
738
765
  subAgentModel?: ModelConfig;
739
766
  /** Where background sub-agents are kept between messages. Without it `sub_agent { background: true }` runs the child to completion. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikarmic/forge-core",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Agent engine for IKarmic AI Forge. Model loop, tools, MCP, sandbox, memory, compaction, plan mode, skills, hooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -56,13 +56,13 @@
56
56
  "tree-sitter-wasms": "^0.1.13",
57
57
  "undici": "^7.30.0",
58
58
  "web-tree-sitter": "0.20.8",
59
- "zod": "^3.23.0"
59
+ "zod": "^4.6.7"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@ai-sdk/provider": "^4.0.0",
63
63
  "@types/node": "^22.7.0",
64
64
  "typescript": "^5.6.3",
65
- "vitest": "^5.0.2"
65
+ "vitest": "^5.0.5"
66
66
  },
67
67
  "scripts": {
68
68
  "build": "tsc -p tsconfig.json",