@hilbras/omninode 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,33 @@
1
1
  import { z } from 'zod';
2
2
 
3
+ /** Structured report format so reports can be processed programmatically (§16). */
4
+ type Confidence = "low" | "medium" | "high";
5
+ type FindingSeverity = "info" | "low" | "medium" | "high" | "critical";
6
+ interface Finding {
7
+ id: string;
8
+ title: string;
9
+ detail: string;
10
+ severity?: FindingSeverity;
11
+ evidence?: string[];
12
+ /** File path or conceptual location the finding refers to. */
13
+ location?: string;
14
+ tags?: string[];
15
+ }
16
+ interface Report {
17
+ id: string;
18
+ taskId: string;
19
+ /** Agent name from the agent registry. */
20
+ agent: string;
21
+ /** Model id used, if known. */
22
+ model?: string;
23
+ summary: string;
24
+ findings: Finding[];
25
+ recommendations: string[];
26
+ confidence?: Confidence;
27
+ createdAt: string;
28
+ metadata?: Record<string, unknown>;
29
+ }
30
+
3
31
  /** Role system: what an AI is supposed to do, independent of any provider (§11). */
4
32
  interface RoleDefinition {
5
33
  /** Slug identifier, e.g. "architecture-reviewer". */
@@ -19,6 +47,8 @@ interface RoleDefinition {
19
47
 
20
48
  type AgentIntegrationType = "native" | "process" | "custom";
21
49
  type AgentStatus = "registered" | "ready" | "running" | "busy" | "stopped" | "error";
50
+ /** How the task payload reaches a process agent (§9). */
51
+ type AgentInputMode = "stdin" | "arg" | "protocol";
22
52
  interface AgentConfig {
23
53
  name: string;
24
54
  integration: AgentIntegrationType;
@@ -27,6 +57,10 @@ interface AgentConfig {
27
57
  args?: string[];
28
58
  cwd?: string;
29
59
  env?: Record<string, string>;
60
+ /** How the task is delivered: prompt on stdin, as last argument, or the §21 JSON-lines protocol. */
61
+ inputMode?: AgentInputMode;
62
+ /** Per-task timeout in milliseconds; the process is killed when exceeded. */
63
+ timeoutMs?: number;
30
64
  /** Models (as "provider:model-id") this agent may use, if restricted. */
31
65
  allowedModels?: string[];
32
66
  metadata?: Record<string, unknown>;
@@ -57,6 +91,8 @@ interface AgentTaskOutput {
57
91
  rawOutput?: string;
58
92
  exitCode?: number;
59
93
  logs?: string[];
94
+ /** Structured reports extracted from protocol-mode runs (§16, §21). */
95
+ reports?: Report[];
60
96
  error?: string;
61
97
  }
62
98
  /** Contract every agent adapter implements (Phase 3+). */
@@ -215,34 +251,6 @@ interface PipelineRun {
215
251
  stepRuns: PipelineStepRun[];
216
252
  }
217
253
 
218
- /** Structured report format so reports can be processed programmatically (§16). */
219
- type Confidence = "low" | "medium" | "high";
220
- type FindingSeverity = "info" | "low" | "medium" | "high" | "critical";
221
- interface Finding {
222
- id: string;
223
- title: string;
224
- detail: string;
225
- severity?: FindingSeverity;
226
- evidence?: string[];
227
- /** File path or conceptual location the finding refers to. */
228
- location?: string;
229
- tags?: string[];
230
- }
231
- interface Report {
232
- id: string;
233
- taskId: string;
234
- /** Agent name from the agent registry. */
235
- agent: string;
236
- /** Model id used, if known. */
237
- model?: string;
238
- summary: string;
239
- findings: Finding[];
240
- recommendations: string[];
241
- confidence?: Confidence;
242
- createdAt: string;
243
- metadata?: Record<string, unknown>;
244
- }
245
-
246
254
  /** Agent ↔ OmniNode communication protocol (§21). */
247
255
 
248
256
  interface EnvelopeMeta {
@@ -495,15 +503,19 @@ declare const agentConfigSchema: z.ZodObject<{
495
503
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
496
504
  cwd: z.ZodOptional<z.ZodString>;
497
505
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
506
+ input_mode: z.ZodDefault<z.ZodEnum<["stdin", "arg", "protocol"]>>;
507
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
498
508
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
499
509
  }, "strict", z.ZodTypeAny, {
500
510
  name: string;
501
511
  type: "native" | "process" | "cli";
512
+ input_mode: "stdin" | "arg" | "protocol";
502
513
  metadata?: Record<string, unknown> | undefined;
503
514
  command?: string | undefined;
504
515
  args?: string[] | undefined;
505
516
  cwd?: string | undefined;
506
517
  env?: Record<string, string> | undefined;
518
+ timeout_ms?: number | undefined;
507
519
  }, {
508
520
  name: string;
509
521
  type?: "native" | "process" | "cli" | undefined;
@@ -512,6 +524,8 @@ declare const agentConfigSchema: z.ZodObject<{
512
524
  args?: string[] | undefined;
513
525
  cwd?: string | undefined;
514
526
  env?: Record<string, string> | undefined;
527
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
528
+ timeout_ms?: number | undefined;
515
529
  }>;
516
530
  declare const roleConfigSchema: z.ZodObject<{
517
531
  id: z.ZodString;
@@ -576,15 +590,19 @@ declare const projectConfigSchema: z.ZodObject<{
576
590
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
577
591
  cwd: z.ZodOptional<z.ZodString>;
578
592
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
593
+ input_mode: z.ZodDefault<z.ZodEnum<["stdin", "arg", "protocol"]>>;
594
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
579
595
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
580
596
  }, "strict", z.ZodTypeAny, {
581
597
  name: string;
582
598
  type: "native" | "process" | "cli";
599
+ input_mode: "stdin" | "arg" | "protocol";
583
600
  metadata?: Record<string, unknown> | undefined;
584
601
  command?: string | undefined;
585
602
  args?: string[] | undefined;
586
603
  cwd?: string | undefined;
587
604
  env?: Record<string, string> | undefined;
605
+ timeout_ms?: number | undefined;
588
606
  }, {
589
607
  name: string;
590
608
  type?: "native" | "process" | "cli" | undefined;
@@ -593,6 +611,8 @@ declare const projectConfigSchema: z.ZodObject<{
593
611
  args?: string[] | undefined;
594
612
  cwd?: string | undefined;
595
613
  env?: Record<string, string> | undefined;
614
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
615
+ timeout_ms?: number | undefined;
596
616
  }>, "many">>;
597
617
  roles: z.ZodDefault<z.ZodArray<z.ZodObject<{
598
618
  id: z.ZodString;
@@ -643,11 +663,13 @@ declare const projectConfigSchema: z.ZodObject<{
643
663
  agents: {
644
664
  name: string;
645
665
  type: "native" | "process" | "cli";
666
+ input_mode: "stdin" | "arg" | "protocol";
646
667
  metadata?: Record<string, unknown> | undefined;
647
668
  command?: string | undefined;
648
669
  args?: string[] | undefined;
649
670
  cwd?: string | undefined;
650
671
  env?: Record<string, string> | undefined;
672
+ timeout_ms?: number | undefined;
651
673
  }[];
652
674
  roles: {
653
675
  name: string;
@@ -681,6 +703,8 @@ declare const projectConfigSchema: z.ZodObject<{
681
703
  args?: string[] | undefined;
682
704
  cwd?: string | undefined;
683
705
  env?: Record<string, string> | undefined;
706
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
707
+ timeout_ms?: number | undefined;
684
708
  }[] | undefined;
685
709
  roles?: {
686
710
  name: string;
@@ -732,15 +756,19 @@ declare const appConfigSchema: z.ZodObject<{
732
756
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
733
757
  cwd: z.ZodOptional<z.ZodString>;
734
758
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
759
+ input_mode: z.ZodDefault<z.ZodEnum<["stdin", "arg", "protocol"]>>;
760
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
735
761
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
736
762
  }, "strict", z.ZodTypeAny, {
737
763
  name: string;
738
764
  type: "native" | "process" | "cli";
765
+ input_mode: "stdin" | "arg" | "protocol";
739
766
  metadata?: Record<string, unknown> | undefined;
740
767
  command?: string | undefined;
741
768
  args?: string[] | undefined;
742
769
  cwd?: string | undefined;
743
770
  env?: Record<string, string> | undefined;
771
+ timeout_ms?: number | undefined;
744
772
  }, {
745
773
  name: string;
746
774
  type?: "native" | "process" | "cli" | undefined;
@@ -749,6 +777,8 @@ declare const appConfigSchema: z.ZodObject<{
749
777
  args?: string[] | undefined;
750
778
  cwd?: string | undefined;
751
779
  env?: Record<string, string> | undefined;
780
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
781
+ timeout_ms?: number | undefined;
752
782
  }>, "many">>;
753
783
  roles: z.ZodDefault<z.ZodArray<z.ZodObject<{
754
784
  id: z.ZodString;
@@ -799,11 +829,13 @@ declare const appConfigSchema: z.ZodObject<{
799
829
  agents: {
800
830
  name: string;
801
831
  type: "native" | "process" | "cli";
832
+ input_mode: "stdin" | "arg" | "protocol";
802
833
  metadata?: Record<string, unknown> | undefined;
803
834
  command?: string | undefined;
804
835
  args?: string[] | undefined;
805
836
  cwd?: string | undefined;
806
837
  env?: Record<string, string> | undefined;
838
+ timeout_ms?: number | undefined;
807
839
  }[];
808
840
  roles: {
809
841
  name: string;
@@ -837,6 +869,8 @@ declare const appConfigSchema: z.ZodObject<{
837
869
  args?: string[] | undefined;
838
870
  cwd?: string | undefined;
839
871
  env?: Record<string, string> | undefined;
872
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
873
+ timeout_ms?: number | undefined;
840
874
  }[] | undefined;
841
875
  roles?: {
842
876
  name: string;
@@ -855,9 +889,9 @@ declare const appConfigSchema: z.ZodObject<{
855
889
  logging: z.ZodOptional<z.ZodObject<{
856
890
  level: z.ZodEnum<["debug", "info", "warn", "error"]>;
857
891
  }, "strict", z.ZodTypeAny, {
858
- level: "error" | "info" | "debug" | "warn";
892
+ level: "info" | "error" | "debug" | "warn";
859
893
  }, {
860
- level: "error" | "info" | "debug" | "warn";
894
+ level: "info" | "error" | "debug" | "warn";
861
895
  }>>;
862
896
  }, "strict", z.ZodTypeAny, {
863
897
  project: {
@@ -874,11 +908,13 @@ declare const appConfigSchema: z.ZodObject<{
874
908
  agents: {
875
909
  name: string;
876
910
  type: "native" | "process" | "cli";
911
+ input_mode: "stdin" | "arg" | "protocol";
877
912
  metadata?: Record<string, unknown> | undefined;
878
913
  command?: string | undefined;
879
914
  args?: string[] | undefined;
880
915
  cwd?: string | undefined;
881
916
  env?: Record<string, string> | undefined;
917
+ timeout_ms?: number | undefined;
882
918
  }[];
883
919
  roles: {
884
920
  name: string;
@@ -895,7 +931,7 @@ declare const appConfigSchema: z.ZodObject<{
895
931
  } | undefined;
896
932
  };
897
933
  logging?: {
898
- level: "error" | "info" | "debug" | "warn";
934
+ level: "info" | "error" | "debug" | "warn";
899
935
  } | undefined;
900
936
  }, {
901
937
  project: {
@@ -917,6 +953,8 @@ declare const appConfigSchema: z.ZodObject<{
917
953
  args?: string[] | undefined;
918
954
  cwd?: string | undefined;
919
955
  env?: Record<string, string> | undefined;
956
+ input_mode?: "stdin" | "arg" | "protocol" | undefined;
957
+ timeout_ms?: number | undefined;
920
958
  }[] | undefined;
921
959
  roles?: {
922
960
  name: string;
@@ -933,7 +971,7 @@ declare const appConfigSchema: z.ZodObject<{
933
971
  } | undefined;
934
972
  };
935
973
  logging?: {
936
- level: "error" | "info" | "debug" | "warn";
974
+ level: "info" | "error" | "debug" | "warn";
937
975
  } | undefined;
938
976
  }>;
939
977
  type ProviderConfigYaml = z.infer<typeof providerConfigSchema>;
@@ -1048,6 +1086,30 @@ declare class OmniHilbrasProvider extends OpenAICompatibleProvider {
1048
1086
  connect(registry?: ModelRegistry): Promise<OmniHilbrasConnectionResult>;
1049
1087
  }
1050
1088
 
1051
- declare const OMNINODE_VERSION = "0.3.0";
1089
+ declare function composeTaskText(input: AgentTaskInput): string;
1090
+ declare class ProcessAgent implements IAgent {
1091
+ readonly config: AgentConfig;
1092
+ readonly info: AgentInfo;
1093
+ private readonly log;
1094
+ private readonly running;
1095
+ constructor(config: AgentConfig, log?: Logger);
1096
+ run(input: AgentTaskInput): Promise<AgentTaskOutput>;
1097
+ /** Ask the agent to stop current work (SIGTERM). */
1098
+ cancel(taskId: string): Promise<void>;
1099
+ runningTaskIds(): string[];
1100
+ }
1101
+
1102
+ declare function createAgent(config: AgentConfig): IAgent;
1103
+
1104
+ /** Agent registry (§10): the set of agents connected to OmniNode. */
1105
+
1106
+ declare class AgentRegistry {
1107
+ private readonly agents;
1108
+ register(agent: IAgent): void;
1109
+ get(name: string): IAgent | undefined;
1110
+ list(): IAgent[];
1111
+ }
1112
+
1113
+ declare const OMNINODE_VERSION = "0.4.0";
1052
1114
 
1053
- export { type AgentConfig, type AgentConfigYaml, AgentError, type AgentInfo, type AgentIntegrationType, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AppConfig, type AppConfigYaml, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatUsage, type Confidence, ConfigError, ConsoleLogSink, type DiscoveryResult, type EnvelopeMeta, type Finding, type FindingSeverity, type HttpRequestOptions, type HttpResponse, type IAgent, type IChatProvider, type IMemoryProvider, type IProvider, type LoadConfigOptions, type LogLevel, type LogSink, Logger, type LoggerOptions, type MemoryEntry, MemoryError, type MemoryQuery, type MemoryScope, type MessageEnvelope, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, type PipelineDefinition, PipelineError, type PipelineRun, type PipelineRunStatus, type PipelineStep, type PipelineStepCondition, type PipelineStepKind, type PipelineStepRun, type Project, type ProjectConfigYaml, ProtocolError, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderHealth, type ProviderStatus, type ProviderType, type Report, type RoleConfigYaml, type RoleDefinition, type Task, type TaskContext, TaskError, type TaskResult, type TaskStatus, type WritableLike, agentConfigSchema, appConfigSchema, authHeaders, createProvider, defaultProjectConfigYaml, expandEnvRefs, findConfigFile, isOmniNodeError, loadConfig, logger, projectConfigSchema, providerConfigSchema, registryKey, requestJson, resolveApiKey, roleConfigSchema };
1115
+ export { type AgentConfig, type AgentConfigYaml, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AppConfig, type AppConfigYaml, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatUsage, type Confidence, ConfigError, ConsoleLogSink, type DiscoveryResult, type EnvelopeMeta, type Finding, type FindingSeverity, type HttpRequestOptions, type HttpResponse, type IAgent, type IChatProvider, type IMemoryProvider, type IProvider, type LoadConfigOptions, type LogLevel, type LogSink, Logger, type LoggerOptions, type MemoryEntry, MemoryError, type MemoryQuery, type MemoryScope, type MessageEnvelope, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, type PipelineDefinition, PipelineError, type PipelineRun, type PipelineRunStatus, type PipelineStep, type PipelineStepCondition, type PipelineStepKind, type PipelineStepRun, ProcessAgent, type Project, type ProjectConfigYaml, ProtocolError, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderHealth, type ProviderStatus, type ProviderType, type Report, type RoleConfigYaml, type RoleDefinition, type Task, type TaskContext, TaskError, type TaskResult, type TaskStatus, type WritableLike, agentConfigSchema, appConfigSchema, authHeaders, composeTaskText, createAgent, createProvider, defaultProjectConfigYaml, expandEnvRefs, findConfigFile, isOmniNodeError, loadConfig, logger, projectConfigSchema, providerConfigSchema, registryKey, requestJson, resolveApiKey, roleConfigSchema };
package/dist/index.js CHANGED
@@ -123,6 +123,8 @@ var agentConfigSchema = z.object({
123
123
  args: z.array(z.string()).optional(),
124
124
  cwd: z.string().optional(),
125
125
  env: z.record(z.string()).optional(),
126
+ input_mode: z.enum(["stdin", "arg", "protocol"]).default("stdin"),
127
+ timeout_ms: z.number().int().positive().optional(),
126
128
  metadata: z.record(z.unknown()).optional()
127
129
  }).strict();
128
130
  var roleConfigSchema = z.object({
@@ -234,6 +236,8 @@ function toAgentConfig(raw) {
234
236
  args: raw.args,
235
237
  cwd: raw.cwd,
236
238
  env: raw.env,
239
+ inputMode: raw.input_mode,
240
+ timeoutMs: raw.timeout_ms,
237
241
  metadata: raw.metadata
238
242
  };
239
243
  }
@@ -591,10 +595,290 @@ var ModelRegistry = class {
591
595
  }
592
596
  };
593
597
 
598
+ // src/agents/process/index.ts
599
+ import { spawn } from "child_process";
600
+ var DEFAULT_TIMEOUT_MS2 = 6e5;
601
+ var KILL_GRACE_MS = 5e3;
602
+ function composeTaskText(input) {
603
+ const sections = [`# Objective
604
+ ${input.objective}`];
605
+ if (input.role) {
606
+ const lines = ["# Role", `${input.role.name} (${input.role.id})`];
607
+ if (input.role.responsibilities.length > 0) {
608
+ lines.push("", "Responsibilities:", ...input.role.responsibilities.map((r) => `- ${r}`));
609
+ }
610
+ if (input.role.expectedOutputs.length > 0) {
611
+ lines.push("", "Expected outputs:", ...input.role.expectedOutputs.map((o) => `- ${o}`));
612
+ }
613
+ sections.push(lines.join("\n"));
614
+ }
615
+ if (input.context) sections.push(`# Context
616
+ ${input.context}`);
617
+ if (input.instruction) sections.push(`# Instruction
618
+ ${input.instruction}`);
619
+ return sections.join("\n\n");
620
+ }
621
+ function buildProtocolMessages(input, agentName) {
622
+ const meta = {
623
+ taskId: input.taskId,
624
+ agent: agentName,
625
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
626
+ };
627
+ const messages = [
628
+ { type: "TASK", payload: { taskId: input.taskId, objective: input.objective } }
629
+ ];
630
+ if (input.role) messages.push({ type: "ROLE", payload: input.role });
631
+ if (input.context) messages.push({ type: "CONTEXT", payload: { body: input.context } });
632
+ if (input.instruction) messages.push({ type: "INSTRUCTION", payload: { text: input.instruction } });
633
+ return messages.map((message) => JSON.stringify({ meta, message }));
634
+ }
635
+ var ProcessAgent = class {
636
+ config;
637
+ info;
638
+ log;
639
+ running = /* @__PURE__ */ new Map();
640
+ constructor(config, log = logger) {
641
+ if (!config.command) {
642
+ throw new AgentError("AGENT_NOT_FOUND", `Agent "${config.name}" has no command configured.`);
643
+ }
644
+ this.config = config;
645
+ this.log = log.child({ agent: config.name });
646
+ this.info = {
647
+ name: config.name,
648
+ integration: "process",
649
+ command: config.command,
650
+ cwd: config.cwd,
651
+ status: "ready",
652
+ capabilities: [config.inputMode ?? "stdin"]
653
+ };
654
+ }
655
+ async run(input) {
656
+ const command = this.config.command;
657
+ if (!command) {
658
+ throw new AgentError("AGENT_NOT_FOUND", `Agent "${this.config.name}" has no command configured.`);
659
+ }
660
+ const mode = this.config.inputMode ?? "stdin";
661
+ const timeoutMs = this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
662
+ return new Promise((resolve, reject) => {
663
+ const child = spawn(
664
+ command,
665
+ [...this.config.args ?? [], ...mode === "arg" ? [composeTaskText(input)] : []],
666
+ {
667
+ cwd: this.config.cwd,
668
+ env: { ...process.env, ...this.config.env },
669
+ stdio: ["pipe", "pipe", "pipe"]
670
+ }
671
+ );
672
+ this.running.set(input.taskId, child);
673
+ let stdout = "";
674
+ let stderr = "";
675
+ let timedOut = false;
676
+ let settled = false;
677
+ const timer = setTimeout(() => {
678
+ timedOut = true;
679
+ this.log.warn(`Task ${input.taskId} exceeded ${timeoutMs}ms \u2014 killing process.`);
680
+ child.kill("SIGTERM");
681
+ setTimeout(() => child.kill("SIGKILL"), KILL_GRACE_MS).unref();
682
+ }, timeoutMs);
683
+ const settle = (finish) => {
684
+ if (settled) return;
685
+ settled = true;
686
+ clearTimeout(timer);
687
+ this.running.delete(input.taskId);
688
+ finish();
689
+ };
690
+ child.stdout?.on("data", (chunk) => {
691
+ stdout += chunk.toString();
692
+ });
693
+ child.stderr?.on("data", (chunk) => {
694
+ stderr += chunk.toString();
695
+ });
696
+ child.stdin?.on("error", () => {
697
+ });
698
+ if (mode !== "arg") {
699
+ const payload = mode === "protocol" ? buildProtocolMessages(input, this.config.name).join("\n") + "\n" : composeTaskText(input) + "\n";
700
+ child.stdin?.write(payload);
701
+ child.stdin?.end();
702
+ }
703
+ child.on("error", (error) => {
704
+ settle(() => {
705
+ if (error.code === "ENOENT") {
706
+ reject(
707
+ new AgentError(
708
+ "AGENT_NOT_FOUND",
709
+ `Agent "${this.config.name}": command "${command}" was not found. Is it installed and on PATH?`,
710
+ { cause: error }
711
+ )
712
+ );
713
+ return;
714
+ }
715
+ reject(
716
+ new AgentError("AGENT_FAILED", `Agent "${this.config.name}" failed to start: ${error.message}.`, {
717
+ cause: error
718
+ })
719
+ );
720
+ });
721
+ });
722
+ child.on("close", (code, signal) => {
723
+ settle(() => {
724
+ if (timedOut) {
725
+ reject(
726
+ new AgentError(
727
+ "AGENT_TIMEOUT",
728
+ `Agent "${this.config.name}" timed out after ${timeoutMs}ms and was killed.`,
729
+ { details: { taskId: input.taskId, stdout: stdout.slice(0, 4e3), stderr: stderr.slice(0, 2e3) } }
730
+ )
731
+ );
732
+ return;
733
+ }
734
+ const logs = stderr.trim().length > 0 ? stderr.split("\n") : void 0;
735
+ if (mode === "protocol") {
736
+ try {
737
+ resolve(
738
+ interpretProtocolRun({
739
+ input,
740
+ agentName: this.config.name,
741
+ stdout,
742
+ exitCode: code,
743
+ logs
744
+ })
745
+ );
746
+ } catch (error) {
747
+ reject(error);
748
+ }
749
+ return;
750
+ }
751
+ const trimmed = stdout.trim();
752
+ resolve({
753
+ taskId: input.taskId,
754
+ status: code === 0 ? "completed" : "failed",
755
+ summary: trimmed.length > 0 ? firstLine(trimmed) : void 0,
756
+ rawOutput: trimmed.length > 0 ? trimmed : void 0,
757
+ exitCode: code ?? void 0,
758
+ logs,
759
+ error: code === 0 ? void 0 : `Process exited with code ${code ?? "unknown"}${signal ? ` (signal: ${signal})` : ""}`
760
+ });
761
+ });
762
+ });
763
+ });
764
+ }
765
+ /** Ask the agent to stop current work (SIGTERM). */
766
+ async cancel(taskId) {
767
+ const child = this.running.get(taskId);
768
+ if (child) child.kill("SIGTERM");
769
+ }
770
+ runningTaskIds() {
771
+ return [...this.running.keys()];
772
+ }
773
+ };
774
+ function interpretProtocolRun({ input, agentName, stdout, exitCode, logs }) {
775
+ const reports = [];
776
+ let summary;
777
+ let error;
778
+ let sawProtocolMessage = false;
779
+ for (const line of stdout.split("\n")) {
780
+ const trimmed2 = line.trim();
781
+ if (trimmed2.length === 0) continue;
782
+ const message = parseAgentMessage(trimmed2);
783
+ if (!message) continue;
784
+ sawProtocolMessage = true;
785
+ if (message.type === "REPORT") {
786
+ const report = normalizeReport(message.payload, input.taskId, agentName, reports.length);
787
+ if (report) reports.push(report);
788
+ } else if (message.type === "COMPLETION") {
789
+ const payload = message.payload;
790
+ if (typeof payload?.summary === "string") summary = payload.summary;
791
+ } else if (message.type === "ERROR") {
792
+ const payload = message.payload;
793
+ const detail = typeof payload?.message === "string" ? payload.message : "unknown error";
794
+ const code = typeof payload?.code === "string" ? ` [${payload.code}]` : "";
795
+ error = `Agent error${code}: ${detail}`;
796
+ }
797
+ }
798
+ if (!sawProtocolMessage && exitCode === 0) {
799
+ throw new ProtocolError(
800
+ `Agent "${agentName}" produced no protocol messages on stdout (input mode "protocol").`,
801
+ { details: { taskId: input.taskId, stdout: stdout.slice(0, 2e3) } }
802
+ );
803
+ }
804
+ const trimmed = stdout.trim();
805
+ return {
806
+ taskId: input.taskId,
807
+ status: error !== void 0 || exitCode !== 0 ? "failed" : "completed",
808
+ summary: summary ?? reports[0]?.summary,
809
+ rawOutput: trimmed.length > 0 ? trimmed : void 0,
810
+ exitCode: exitCode ?? void 0,
811
+ logs,
812
+ reports: reports.length > 0 ? reports : void 0,
813
+ error: error ?? (exitCode !== 0 ? `Process exited with code ${exitCode ?? "unknown"}` : void 0)
814
+ };
815
+ }
816
+ function parseAgentMessage(line) {
817
+ try {
818
+ const parsed = JSON.parse(line);
819
+ if (typeof parsed.type === "string") {
820
+ return { type: parsed.type, payload: parsed.payload };
821
+ }
822
+ const inner = parsed.message;
823
+ if (inner && typeof inner.type === "string") {
824
+ return { type: inner.type, payload: inner.payload };
825
+ }
826
+ } catch {
827
+ }
828
+ return void 0;
829
+ }
830
+ function normalizeReport(payload, taskId, agentName, index) {
831
+ if (payload === null || typeof payload !== "object") return void 0;
832
+ const raw = payload;
833
+ if (typeof raw.summary !== "string") return void 0;
834
+ return {
835
+ id: typeof raw.id === "string" ? raw.id : `${taskId}-report-${index}`,
836
+ taskId: typeof raw.taskId === "string" ? raw.taskId : taskId,
837
+ agent: typeof raw.agent === "string" ? raw.agent : agentName,
838
+ summary: raw.summary,
839
+ findings: Array.isArray(raw.findings) ? raw.findings : [],
840
+ recommendations: Array.isArray(raw.recommendations) ? raw.recommendations : [],
841
+ createdAt: typeof raw.createdAt === "string" ? raw.createdAt : (/* @__PURE__ */ new Date()).toISOString()
842
+ };
843
+ }
844
+ function firstLine(text, maxLength = 200) {
845
+ const line = text.split("\n", 1)[0] ?? text;
846
+ return line.length > maxLength ? `${line.slice(0, maxLength)}\u2026` : line;
847
+ }
848
+
849
+ // src/agents/factory.ts
850
+ function createAgent(config) {
851
+ if (config.integration === "process") {
852
+ return new ProcessAgent(config);
853
+ }
854
+ if (config.integration === "native") {
855
+ throw new OmniNodeError(
856
+ "NOT_IMPLEMENTED",
857
+ `Native agent adapters are planned for a later phase. Use input over stdin/stdout (type "cli") for "${config.name}" for now.`
858
+ );
859
+ }
860
+ throw new OmniNodeError("NOT_IMPLEMENTED", `Agent integration "${config.integration}" has no adapter yet.`);
861
+ }
862
+
863
+ // src/agents/registry.ts
864
+ var AgentRegistry = class {
865
+ agents = /* @__PURE__ */ new Map();
866
+ register(agent) {
867
+ this.agents.set(agent.info.name, agent);
868
+ }
869
+ get(name) {
870
+ return this.agents.get(name);
871
+ }
872
+ list() {
873
+ return [...this.agents.values()].sort((a, b) => a.info.name.localeCompare(b.info.name));
874
+ }
875
+ };
876
+
594
877
  // src/version.ts
595
- var OMNINODE_VERSION = "0.3.0";
878
+ var OMNINODE_VERSION = "0.4.0";
596
879
  export {
597
880
  AgentError,
881
+ AgentRegistry,
598
882
  ConfigError,
599
883
  ConsoleLogSink,
600
884
  Logger,
@@ -606,12 +890,15 @@ export {
606
890
  OmniNodeError,
607
891
  OpenAICompatibleProvider,
608
892
  PipelineError,
893
+ ProcessAgent,
609
894
  ProtocolError,
610
895
  ProviderError,
611
896
  TaskError,
612
897
  agentConfigSchema,
613
898
  appConfigSchema,
614
899
  authHeaders,
900
+ composeTaskText,
901
+ createAgent,
615
902
  createProvider,
616
903
  defaultProjectConfigYaml,
617
904
  expandEnvRefs,