@jmanuelcorral/openteam 0.2.0 → 0.2.2

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 (42) hide show
  1. package/README.es.md +5 -5
  2. package/README.md +5 -5
  3. package/dist/cli/consoleServe.d.ts +9 -0
  4. package/dist/cli/consoleServe.d.ts.map +1 -1
  5. package/dist/cli/graphViewProvider.d.ts +30 -0
  6. package/dist/cli/graphViewProvider.d.ts.map +1 -0
  7. package/dist/cli.js +1271 -240
  8. package/dist/commands/dispatch.d.ts +1 -0
  9. package/dist/commands/dispatch.d.ts.map +1 -1
  10. package/dist/commands/orchestratorAgent.d.ts.map +1 -1
  11. package/dist/config/graphFeatureGate.d.ts +8 -3
  12. package/dist/config/graphFeatureGate.d.ts.map +1 -1
  13. package/dist/config/schema.d.ts +5 -0
  14. package/dist/config/schema.d.ts.map +1 -1
  15. package/dist/context/redaction.d.ts +8 -0
  16. package/dist/context/redaction.d.ts.map +1 -1
  17. package/dist/graph/certificate.d.ts +12 -2
  18. package/dist/graph/certificate.d.ts.map +1 -1
  19. package/dist/graph/soakLedger.d.ts +25 -2
  20. package/dist/graph/soakLedger.d.ts.map +1 -1
  21. package/dist/index.d.ts +11 -5
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3028 -1678
  24. package/dist/orchestrator/coordinator.d.ts +37 -2
  25. package/dist/orchestrator/coordinator.d.ts.map +1 -1
  26. package/dist/orchestrator/graphIngress.d.ts +1 -1
  27. package/dist/orchestrator/graphIngress.d.ts.map +1 -1
  28. package/dist/orchestrator/ledger.d.ts +11 -42
  29. package/dist/orchestrator/ledger.d.ts.map +1 -1
  30. package/dist/orchestrator/sddCompiler.d.ts +25 -1
  31. package/dist/orchestrator/sddCompiler.d.ts.map +1 -1
  32. package/dist/plugin/orchestrateTool.d.ts +197 -0
  33. package/dist/plugin/orchestrateTool.d.ts.map +1 -0
  34. package/dist/telemetry/events.d.ts +37 -0
  35. package/dist/telemetry/events.d.ts.map +1 -1
  36. package/dist/version.d.ts +3 -0
  37. package/dist/version.d.ts.map +1 -0
  38. package/package.json +1 -1
  39. package/dist/orchestrator/sdd.d.ts +0 -180
  40. package/dist/orchestrator/sdd.d.ts.map +0 -1
  41. package/dist/storage/graph/migrateLegacyBriefs.d.ts +0 -32
  42. package/dist/storage/graph/migrateLegacyBriefs.d.ts.map +0 -1
package/dist/cli.js CHANGED
@@ -10,11 +10,187 @@ import { promisify } from "node:util";
10
10
  // src/cli/consoleServe.ts
11
11
  import { randomBytes } from "node:crypto";
12
12
 
13
- // src/console/protocol.ts
13
+ // src/config/schema.ts
14
14
  import { z } from "zod";
15
+ var ModelRefSchema = z.object({
16
+ providerID: z.string().min(1),
17
+ modelID: z.string().min(1)
18
+ });
19
+ var RouterModeSchema = z.enum(["economy", "balanced", "quality"]);
20
+ var PrivacyModeSchema = z.enum([
21
+ "forceLocalOnSensitive",
22
+ "consentBeforeFrontier",
23
+ "off"
24
+ ]);
25
+ var BaselineModeSchema = z.enum(["auto", "pinned"]);
26
+ var GraphModeSchema = z.enum(["off", "shadow", "active"]);
27
+ var DEFAULT_GRAPH_JOURNAL_ROOT = ".opencode/openteam/graph/runs";
28
+ var GraphConfigSchema = z.object({
29
+ mode: GraphModeSchema.default("off"),
30
+ killSwitch: z.boolean().default(false),
31
+ journalRoot: z.string().min(1).default(DEFAULT_GRAPH_JOURNAL_ROOT),
32
+ operatorApproval: z.boolean().default(false),
33
+ worktrees: z.object({
34
+ enabled: z.boolean().default(false)
35
+ }).default({ enabled: false })
36
+ });
37
+ var ConsoleHostSchema = z.enum(["127.0.0.1", "localhost"]);
38
+ var ConsoleConfigSchema = z.object({
39
+ host: ConsoleHostSchema.default("127.0.0.1"),
40
+ port: z.number().int().min(1024).max(65535).default(4599),
41
+ autoPortFallback: z.boolean().default(true),
42
+ refreshMs: z.number().int().min(250).default(2000),
43
+ recentRoutes: z.number().int().positive().default(50),
44
+ openBrowser: z.boolean().default(false),
45
+ remoteStorage: z.boolean().default(false),
46
+ terminal: z.object({
47
+ enabled: z.boolean().default(true),
48
+ pty: z.boolean().optional()
49
+ }).default({ enabled: true }),
50
+ graphView: z.object({
51
+ enabled: z.boolean().default(false)
52
+ }).optional()
53
+ }).default({
54
+ host: "127.0.0.1",
55
+ port: 4599,
56
+ autoPortFallback: true,
57
+ refreshMs: 2000,
58
+ recentRoutes: 50,
59
+ openBrowser: false,
60
+ remoteStorage: false,
61
+ terminal: { enabled: true }
62
+ });
63
+ var StorageConfigSchema = z.object({
64
+ sqliteIndex: z.object({
65
+ enabled: z.boolean().default(false),
66
+ path: z.string().min(1).default(".opencode/openteam/index.sqlite")
67
+ }).default({ enabled: false, path: ".opencode/openteam/index.sqlite" })
68
+ }).default({
69
+ sqliteIndex: { enabled: false, path: ".opencode/openteam/index.sqlite" }
70
+ });
71
+ var defaultLocalModel = {
72
+ providerID: "ollama",
73
+ modelID: "qwen3:8b"
74
+ };
75
+ var defaultFrontierModel = {
76
+ providerID: "anthropic",
77
+ modelID: "claude-sonnet-4-5"
78
+ };
79
+ var LocalRuntimeSchema = z.object({
80
+ id: z.enum(["ollama", "lmstudio", "foundry-local"]),
81
+ enabled: z.boolean().default(true),
82
+ baseURL: z.string().url().optional(),
83
+ discovery: z.enum(["cli", "sdk", "manual"]).optional(),
84
+ defaultModel: ModelRefSchema
85
+ });
86
+ var MemoryScopeSchema = z.enum(["project", "user"]);
87
+ var MemoryExtractionModeSchema = z.enum([
88
+ "local",
89
+ "localWithFrontierFallback"
90
+ ]);
91
+ var MemoryEmbeddingsProviderSchema = z.enum(["local", "none"]);
92
+ var MemorySemanticSchema = z.object({
93
+ enabled: z.boolean().default(false),
94
+ storeContent: z.boolean().default(false),
95
+ logPath: z.string().min(1).default(".opencode/openteam/memory/records.jsonl"),
96
+ indexPath: z.string().min(1).default(".opencode/openteam/memory/index.sqlite"),
97
+ scope: MemoryScopeSchema.default("project"),
98
+ extraction: z.object({
99
+ mode: MemoryExtractionModeSchema.default("local"),
100
+ model: ModelRefSchema.nullable().default(null)
101
+ }).default({ mode: "local", model: null }),
102
+ embeddings: z.object({
103
+ provider: MemoryEmbeddingsProviderSchema.default("local"),
104
+ model: ModelRefSchema.nullable().default(null),
105
+ dim: z.number().int().positive().default(768)
106
+ }).default({ provider: "local", model: null, dim: 768 }),
107
+ recall: z.object({
108
+ maxResults: z.number().int().positive().default(8),
109
+ minSimilarity: z.number().min(0).max(1).default(0.2)
110
+ }).default({ maxResults: 8, minSimilarity: 0.2 }),
111
+ injection: z.object({
112
+ enabled: z.boolean().default(false),
113
+ maxChars: z.number().int().positive().default(1200),
114
+ maxItems: z.number().int().positive().default(8)
115
+ }).default({ enabled: false, maxChars: 1200, maxItems: 8 })
116
+ }).default({
117
+ enabled: false,
118
+ storeContent: false,
119
+ logPath: ".opencode/openteam/memory/records.jsonl",
120
+ indexPath: ".opencode/openteam/memory/index.sqlite",
121
+ scope: "project",
122
+ extraction: { mode: "local", model: null },
123
+ embeddings: { provider: "local", model: null, dim: 768 },
124
+ recall: { maxResults: 8, minSimilarity: 0.2 },
125
+ injection: { enabled: false, maxChars: 1200, maxItems: 8 }
126
+ });
127
+ var MemoryConfigSchema = z.object({
128
+ semantic: MemorySemanticSchema
129
+ });
130
+ var OpenTeamConfigObjectSchema = z.object({
131
+ baseline: z.object({
132
+ mode: BaselineModeSchema.default("auto"),
133
+ pinnedModel: ModelRefSchema.nullable().default(null),
134
+ hardDefault: ModelRefSchema.default(defaultFrontierModel)
135
+ }).default({
136
+ mode: "auto",
137
+ pinnedModel: null,
138
+ hardDefault: defaultFrontierModel
139
+ }),
140
+ router: z.object({
141
+ mode: RouterModeSchema.default("balanced"),
142
+ localDefault: ModelRefSchema.default(defaultLocalModel),
143
+ trivialPromptMaxChars: z.number().int().positive().default(280),
144
+ frontierPromptMinChars: z.number().int().positive().default(2000),
145
+ frontierOnly: z.boolean().default(false)
146
+ }).default({
147
+ mode: "balanced",
148
+ localDefault: defaultLocalModel,
149
+ trivialPromptMaxChars: 280,
150
+ frontierPromptMinChars: 2000,
151
+ frontierOnly: false
152
+ }),
153
+ local: z.object({
154
+ runtimes: z.array(LocalRuntimeSchema).min(1).default([
155
+ {
156
+ id: "ollama",
157
+ enabled: true,
158
+ baseURL: "http://localhost:11434/v1",
159
+ defaultModel: { providerID: "ollama", modelID: "qwen3:8b" }
160
+ }
161
+ ])
162
+ }).default({
163
+ runtimes: [
164
+ {
165
+ id: "ollama",
166
+ enabled: true,
167
+ baseURL: "http://localhost:11434/v1",
168
+ defaultModel: defaultLocalModel
169
+ }
170
+ ]
171
+ }),
172
+ budgets: z.object({
173
+ sessionUSD: z.number().positive().optional(),
174
+ monthlyUSD: z.number().positive().optional(),
175
+ frontierTokensPerSession: z.number().int().positive().optional(),
176
+ hardStopOnBudgetExhaustion: z.boolean().default(false)
177
+ }).default({ hardStopOnBudgetExhaustion: false }),
178
+ privacyMode: PrivacyModeSchema.default("forceLocalOnSensitive"),
179
+ console: ConsoleConfigSchema,
180
+ storage: StorageConfigSchema,
181
+ memory: MemoryConfigSchema.optional(),
182
+ graph: GraphConfigSchema.optional()
183
+ });
184
+ var OpenTeamConfigSchema = OpenTeamConfigObjectSchema;
185
+ function resolveMemorySemantic(config) {
186
+ return config.memory?.semantic ?? MemorySemanticSchema.parse(undefined);
187
+ }
188
+
189
+ // src/console/protocol.ts
190
+ import { z as z2 } from "zod";
15
191
  var MAX_INPUT_CHARS = 1e5;
16
- var SessionInputSchema = z.object({
17
- text: z.string().min(1).max(MAX_INPUT_CHARS)
192
+ var SessionInputSchema = z2.object({
193
+ text: z2.string().min(1).max(MAX_INPUT_CHARS)
18
194
  });
19
195
  function parseSessionInput(raw) {
20
196
  const result = SessionInputSchema.safeParse(raw);
@@ -623,214 +799,40 @@ function splitVirtualPath(path) {
623
799
  import { z as z4 } from "zod";
624
800
 
625
801
  // src/capabilities/types.ts
626
- import { z as z2 } from "zod";
627
- var CapabilityTierSchema = z2.union([
628
- z2.literal(0),
629
- z2.literal(1),
630
- z2.literal(2),
631
- z2.literal(3),
632
- z2.literal(4),
633
- z2.literal(5)
802
+ import { z as z3 } from "zod";
803
+ var CapabilityTierSchema = z3.union([
804
+ z3.literal(0),
805
+ z3.literal(1),
806
+ z3.literal(2),
807
+ z3.literal(3),
808
+ z3.literal(4),
809
+ z3.literal(5)
634
810
  ]);
635
- var ComplexityTierSchema = z2.enum([
811
+ var ComplexityTierSchema = z3.enum([
636
812
  "trivial",
637
813
  "simple",
638
814
  "moderate",
639
815
  "hard"
640
816
  ]);
641
- var ModelCapabilityProfileSchema = z2.object({
642
- ref: z2.object({
643
- providerID: z2.string().min(1),
644
- modelID: z2.string().min(1)
817
+ var ModelCapabilityProfileSchema = z3.object({
818
+ ref: z3.object({
819
+ providerID: z3.string().min(1),
820
+ modelID: z3.string().min(1)
645
821
  }),
646
- kind: z2.enum(["local", "frontier", "router"]),
647
- contextWindow: z2.number().int().positive(),
648
- maxOutputTokens: z2.number().int().positive(),
649
- supportsToolCalling: z2.boolean(),
650
- supportsVision: z2.boolean(),
822
+ kind: z3.enum(["local", "frontier", "router"]),
823
+ contextWindow: z3.number().int().positive(),
824
+ maxOutputTokens: z3.number().int().positive(),
825
+ supportsToolCalling: z3.boolean(),
826
+ supportsVision: z3.boolean(),
651
827
  reasoningTier: CapabilityTierSchema,
652
828
  codeQualityTier: CapabilityTierSchema,
653
- costPer1M: z2.object({
654
- inputUSD: z2.number().min(0),
655
- outputUSD: z2.number().min(0)
829
+ costPer1M: z3.object({
830
+ inputUSD: z3.number().min(0),
831
+ outputUSD: z3.number().min(0)
656
832
  }),
657
- availability: z2.enum(["available", "degraded", "unavailable"])
833
+ availability: z3.enum(["available", "degraded", "unavailable"])
658
834
  });
659
835
 
660
- // src/config/schema.ts
661
- import { z as z3 } from "zod";
662
- var ModelRefSchema = z3.object({
663
- providerID: z3.string().min(1),
664
- modelID: z3.string().min(1)
665
- });
666
- var RouterModeSchema = z3.enum(["economy", "balanced", "quality"]);
667
- var PrivacyModeSchema = z3.enum([
668
- "forceLocalOnSensitive",
669
- "consentBeforeFrontier",
670
- "off"
671
- ]);
672
- var BaselineModeSchema = z3.enum(["auto", "pinned"]);
673
- var GraphModeSchema = z3.enum(["off", "shadow", "active"]);
674
- var GraphConfigSchema = z3.object({
675
- mode: GraphModeSchema.default("off"),
676
- killSwitch: z3.boolean().default(false),
677
- operatorApproval: z3.boolean().default(false),
678
- worktrees: z3.object({
679
- enabled: z3.boolean().default(false)
680
- }).default({ enabled: false })
681
- });
682
- var ConsoleHostSchema = z3.enum(["127.0.0.1", "localhost"]);
683
- var ConsoleConfigSchema = z3.object({
684
- host: ConsoleHostSchema.default("127.0.0.1"),
685
- port: z3.number().int().min(1024).max(65535).default(4599),
686
- autoPortFallback: z3.boolean().default(true),
687
- refreshMs: z3.number().int().min(250).default(2000),
688
- recentRoutes: z3.number().int().positive().default(50),
689
- openBrowser: z3.boolean().default(false),
690
- remoteStorage: z3.boolean().default(false),
691
- terminal: z3.object({
692
- enabled: z3.boolean().default(true),
693
- pty: z3.boolean().optional()
694
- }).default({ enabled: true }),
695
- graphView: z3.object({
696
- enabled: z3.boolean().default(false)
697
- }).optional()
698
- }).default({
699
- host: "127.0.0.1",
700
- port: 4599,
701
- autoPortFallback: true,
702
- refreshMs: 2000,
703
- recentRoutes: 50,
704
- openBrowser: false,
705
- remoteStorage: false,
706
- terminal: { enabled: true }
707
- });
708
- var StorageConfigSchema = z3.object({
709
- sqliteIndex: z3.object({
710
- enabled: z3.boolean().default(false),
711
- path: z3.string().min(1).default(".opencode/openteam/index.sqlite")
712
- }).default({ enabled: false, path: ".opencode/openteam/index.sqlite" })
713
- }).default({
714
- sqliteIndex: { enabled: false, path: ".opencode/openteam/index.sqlite" }
715
- });
716
- var defaultLocalModel = {
717
- providerID: "ollama",
718
- modelID: "qwen3:8b"
719
- };
720
- var defaultFrontierModel = {
721
- providerID: "anthropic",
722
- modelID: "claude-sonnet-4-5"
723
- };
724
- var LocalRuntimeSchema = z3.object({
725
- id: z3.enum(["ollama", "lmstudio", "foundry-local"]),
726
- enabled: z3.boolean().default(true),
727
- baseURL: z3.string().url().optional(),
728
- discovery: z3.enum(["cli", "sdk", "manual"]).optional(),
729
- defaultModel: ModelRefSchema
730
- });
731
- var MemoryScopeSchema = z3.enum(["project", "user"]);
732
- var MemoryExtractionModeSchema = z3.enum([
733
- "local",
734
- "localWithFrontierFallback"
735
- ]);
736
- var MemoryEmbeddingsProviderSchema = z3.enum(["local", "none"]);
737
- var MemorySemanticSchema = z3.object({
738
- enabled: z3.boolean().default(false),
739
- storeContent: z3.boolean().default(false),
740
- logPath: z3.string().min(1).default(".opencode/openteam/memory/records.jsonl"),
741
- indexPath: z3.string().min(1).default(".opencode/openteam/memory/index.sqlite"),
742
- scope: MemoryScopeSchema.default("project"),
743
- extraction: z3.object({
744
- mode: MemoryExtractionModeSchema.default("local"),
745
- model: ModelRefSchema.nullable().default(null)
746
- }).default({ mode: "local", model: null }),
747
- embeddings: z3.object({
748
- provider: MemoryEmbeddingsProviderSchema.default("local"),
749
- model: ModelRefSchema.nullable().default(null),
750
- dim: z3.number().int().positive().default(768)
751
- }).default({ provider: "local", model: null, dim: 768 }),
752
- recall: z3.object({
753
- maxResults: z3.number().int().positive().default(8),
754
- minSimilarity: z3.number().min(0).max(1).default(0.2)
755
- }).default({ maxResults: 8, minSimilarity: 0.2 }),
756
- injection: z3.object({
757
- enabled: z3.boolean().default(false),
758
- maxChars: z3.number().int().positive().default(1200),
759
- maxItems: z3.number().int().positive().default(8)
760
- }).default({ enabled: false, maxChars: 1200, maxItems: 8 })
761
- }).default({
762
- enabled: false,
763
- storeContent: false,
764
- logPath: ".opencode/openteam/memory/records.jsonl",
765
- indexPath: ".opencode/openteam/memory/index.sqlite",
766
- scope: "project",
767
- extraction: { mode: "local", model: null },
768
- embeddings: { provider: "local", model: null, dim: 768 },
769
- recall: { maxResults: 8, minSimilarity: 0.2 },
770
- injection: { enabled: false, maxChars: 1200, maxItems: 8 }
771
- });
772
- var MemoryConfigSchema = z3.object({
773
- semantic: MemorySemanticSchema
774
- });
775
- var OpenTeamConfigObjectSchema = z3.object({
776
- baseline: z3.object({
777
- mode: BaselineModeSchema.default("auto"),
778
- pinnedModel: ModelRefSchema.nullable().default(null),
779
- hardDefault: ModelRefSchema.default(defaultFrontierModel)
780
- }).default({
781
- mode: "auto",
782
- pinnedModel: null,
783
- hardDefault: defaultFrontierModel
784
- }),
785
- router: z3.object({
786
- mode: RouterModeSchema.default("balanced"),
787
- localDefault: ModelRefSchema.default(defaultLocalModel),
788
- trivialPromptMaxChars: z3.number().int().positive().default(280),
789
- frontierPromptMinChars: z3.number().int().positive().default(2000),
790
- frontierOnly: z3.boolean().default(false)
791
- }).default({
792
- mode: "balanced",
793
- localDefault: defaultLocalModel,
794
- trivialPromptMaxChars: 280,
795
- frontierPromptMinChars: 2000,
796
- frontierOnly: false
797
- }),
798
- local: z3.object({
799
- runtimes: z3.array(LocalRuntimeSchema).min(1).default([
800
- {
801
- id: "ollama",
802
- enabled: true,
803
- baseURL: "http://localhost:11434/v1",
804
- defaultModel: { providerID: "ollama", modelID: "qwen3:8b" }
805
- }
806
- ])
807
- }).default({
808
- runtimes: [
809
- {
810
- id: "ollama",
811
- enabled: true,
812
- baseURL: "http://localhost:11434/v1",
813
- defaultModel: defaultLocalModel
814
- }
815
- ]
816
- }),
817
- budgets: z3.object({
818
- sessionUSD: z3.number().positive().optional(),
819
- monthlyUSD: z3.number().positive().optional(),
820
- frontierTokensPerSession: z3.number().int().positive().optional(),
821
- hardStopOnBudgetExhaustion: z3.boolean().default(false)
822
- }).default({ hardStopOnBudgetExhaustion: false }),
823
- privacyMode: PrivacyModeSchema.default("forceLocalOnSensitive"),
824
- console: ConsoleConfigSchema,
825
- storage: StorageConfigSchema,
826
- memory: MemoryConfigSchema.optional(),
827
- graph: GraphConfigSchema.optional()
828
- });
829
- var OpenTeamConfigSchema = OpenTeamConfigObjectSchema;
830
- function resolveMemorySemantic(config) {
831
- return config.memory?.semantic ?? MemorySemanticSchema.parse(undefined);
832
- }
833
-
834
836
  // src/telemetry/events.ts
835
837
  var EVENT_SCHEMA_VERSION = 1;
836
838
  var EventBaseSchema = z4.object({
@@ -910,6 +912,17 @@ var SessionEndpointEventSchema = EventBaseSchema.extend({
910
912
  worktree: z4.string().min(1).optional(),
911
913
  title: z4.string().min(1).optional()
912
914
  });
915
+ var ShadowDiagnosticEventSchema = EventBaseSchema.extend({
916
+ type: z4.literal("shadow-diagnostic"),
917
+ batchID: z4.string().min(1),
918
+ failureClass: z4.enum([
919
+ "invalid-node-id",
920
+ "journal-create-failed",
921
+ "journal-append-failed",
922
+ "observation-failed",
923
+ "unknown"
924
+ ])
925
+ });
913
926
  var OpenTeamEventSchema = z4.discriminatedUnion("type", [
914
927
  RouteEventSchema,
915
928
  MessageEventSchema,
@@ -917,7 +930,8 @@ var OpenTeamEventSchema = z4.discriminatedUnion("type", [
917
930
  MeetingEventSchema,
918
931
  DecisionEventSchema,
919
932
  ActivityEventSchema,
920
- SessionEndpointEventSchema
933
+ SessionEndpointEventSchema,
934
+ ShadowDiagnosticEventSchema
921
935
  ]);
922
936
 
923
937
  // src/storage/fsStorageProvider.ts
@@ -3301,6 +3315,875 @@ async function createConsoleRuntime(deps) {
3301
3315
  };
3302
3316
  }
3303
3317
 
3318
+ // src/cli/graphViewProvider.ts
3319
+ import { readdirSync, statSync } from "node:fs";
3320
+ import { join as join3 } from "node:path";
3321
+
3322
+ // src/storage/graph/fsGraphJournal.ts
3323
+ import { join as join2 } from "node:path";
3324
+
3325
+ // src/context/redaction.ts
3326
+ import { createHash } from "node:crypto";
3327
+
3328
+ class RedactionError extends Error {
3329
+ code;
3330
+ key;
3331
+ constructor(key) {
3332
+ super(`raw content field is not allowed: "${key}"`);
3333
+ this.name = "RedactionError";
3334
+ this.code = "raw-content";
3335
+ this.key = key;
3336
+ }
3337
+ }
3338
+ function sha256Hex(input) {
3339
+ return createHash("sha256").update(input, "utf8").digest("hex");
3340
+ }
3341
+ function redactedRef(ref) {
3342
+ return { uri: ref.uri, sha256: ref.sha256, bytes: ref.bytes };
3343
+ }
3344
+ var FORBIDDEN_RAW_KEYS = new Set([
3345
+ "content",
3346
+ "text",
3347
+ "brief",
3348
+ "prompt",
3349
+ "raw",
3350
+ "body",
3351
+ "output",
3352
+ "findings",
3353
+ "message",
3354
+ "source"
3355
+ ]);
3356
+ function walkForbiddenKeys(value, onForbidden) {
3357
+ if (Array.isArray(value)) {
3358
+ for (const item of value) {
3359
+ walkForbiddenKeys(item, onForbidden);
3360
+ }
3361
+ return;
3362
+ }
3363
+ if (value === null || typeof value !== "object") {
3364
+ return;
3365
+ }
3366
+ for (const [key, child] of Object.entries(value)) {
3367
+ if (FORBIDDEN_RAW_KEYS.has(key)) {
3368
+ const shouldStop = onForbidden(key);
3369
+ if (shouldStop)
3370
+ return;
3371
+ }
3372
+ walkForbiddenKeys(child, onForbidden);
3373
+ }
3374
+ }
3375
+ function assertReferenceOnly(value) {
3376
+ walkForbiddenKeys(value, (key) => {
3377
+ throw new RedactionError(key);
3378
+ });
3379
+ }
3380
+
3381
+ // src/graph/types.ts
3382
+ var TERMINAL_NODE_STATUSES = new Set([
3383
+ "succeeded",
3384
+ "cancelled"
3385
+ ]);
3386
+ var TERMINAL_RUN_STATUSES = new Set([
3387
+ "completed",
3388
+ "failed",
3389
+ "cancelled"
3390
+ ]);
3391
+
3392
+ // src/graph/reducer.ts
3393
+ class ReducerError extends Error {
3394
+ code;
3395
+ detail;
3396
+ constructor(code, detail) {
3397
+ super(`${code}: ${detail}`);
3398
+ this.name = "ReducerError";
3399
+ this.code = code;
3400
+ this.detail = detail;
3401
+ }
3402
+ }
3403
+ function initialState(spec) {
3404
+ const nodes = {};
3405
+ for (const node of spec.nodes) {
3406
+ nodes[node.id] = { status: "pending", attempts: 0 };
3407
+ }
3408
+ return { runID: spec.runID, status: "running", seq: -1, nodes };
3409
+ }
3410
+ function withNode(state, nodeID, next) {
3411
+ return {
3412
+ ...state,
3413
+ nodes: { ...state.nodes, [nodeID]: next },
3414
+ seq: state.seq
3415
+ };
3416
+ }
3417
+ function specNode(spec, nodeID) {
3418
+ return spec.nodes.find((node) => node.id === nodeID);
3419
+ }
3420
+ function applyRunStarted(state, seq, specDigest) {
3421
+ if (state.specDigest !== undefined) {
3422
+ if (state.specDigest === specDigest) {
3423
+ return state;
3424
+ }
3425
+ throw new ReducerError("run-started-conflict", specDigest);
3426
+ }
3427
+ return { ...state, specDigest, seq };
3428
+ }
3429
+ function applyDispatched(spec, state, event) {
3430
+ const node = specNode(spec, event.nodeID);
3431
+ const current = state.nodes[event.nodeID];
3432
+ if (node === undefined || current === undefined) {
3433
+ throw new ReducerError("unknown-node", event.nodeID);
3434
+ }
3435
+ for (const dep of node.dependsOn) {
3436
+ if (state.nodes[dep]?.status !== "succeeded") {
3437
+ throw new ReducerError("dependency-not-satisfied", `${event.nodeID} <- ${dep}`);
3438
+ }
3439
+ }
3440
+ const running = {
3441
+ status: "running",
3442
+ attempts: current.attempts + 1,
3443
+ operationID: event.operationID,
3444
+ attemptID: event.attemptID
3445
+ };
3446
+ if (current.status === "pending") {
3447
+ return withNode({ ...state, seq: event.seq }, event.nodeID, running);
3448
+ }
3449
+ if (current.status === "failed") {
3450
+ if (current.operationID !== event.operationID) {
3451
+ throw new ReducerError("dispatch-conflict", event.nodeID);
3452
+ }
3453
+ return withNode({ ...state, seq: event.seq }, event.nodeID, running);
3454
+ }
3455
+ if (current.status === "running") {
3456
+ if (current.operationID === event.operationID && current.attemptID === event.attemptID) {
3457
+ return state;
3458
+ }
3459
+ throw new ReducerError("dispatch-conflict", event.nodeID);
3460
+ }
3461
+ throw new ReducerError("illegal-transition", `dispatch ${current.status}`);
3462
+ }
3463
+ function applySucceeded(state, event) {
3464
+ const current = state.nodes[event.nodeID];
3465
+ if (current === undefined) {
3466
+ throw new ReducerError("unknown-node", event.nodeID);
3467
+ }
3468
+ if (current.status === "succeeded") {
3469
+ if (current.operationID === event.operationID && current.artifactSha256 === event.artifact.sha256) {
3470
+ return state;
3471
+ }
3472
+ throw new ReducerError("receipt-conflict", event.nodeID);
3473
+ }
3474
+ if (current.status !== "running") {
3475
+ throw new ReducerError("illegal-transition", `succeed ${current.status}`);
3476
+ }
3477
+ if (current.operationID !== event.operationID || current.attemptID !== event.attemptID) {
3478
+ throw new ReducerError("receipt-conflict", event.nodeID);
3479
+ }
3480
+ return withNode({ ...state, seq: event.seq }, event.nodeID, {
3481
+ status: "succeeded",
3482
+ attempts: current.attempts,
3483
+ operationID: event.operationID,
3484
+ attemptID: event.attemptID,
3485
+ artifactSha256: event.artifact.sha256
3486
+ });
3487
+ }
3488
+ function applyFailed(state, event) {
3489
+ const current = state.nodes[event.nodeID];
3490
+ if (current === undefined) {
3491
+ throw new ReducerError("unknown-node", event.nodeID);
3492
+ }
3493
+ if (current.status === "failed") {
3494
+ if (current.operationID === event.operationID && current.attemptID === event.attemptID) {
3495
+ return state;
3496
+ }
3497
+ throw new ReducerError("receipt-conflict", event.nodeID);
3498
+ }
3499
+ if (current.status !== "running") {
3500
+ throw new ReducerError("illegal-transition", `fail ${current.status}`);
3501
+ }
3502
+ if (current.operationID !== event.operationID || current.attemptID !== event.attemptID) {
3503
+ throw new ReducerError("receipt-conflict", event.nodeID);
3504
+ }
3505
+ return withNode({ ...state, seq: event.seq }, event.nodeID, {
3506
+ status: "failed",
3507
+ attempts: current.attempts,
3508
+ operationID: event.operationID,
3509
+ attemptID: event.attemptID
3510
+ });
3511
+ }
3512
+ function applyCancelled(state, event) {
3513
+ const current = state.nodes[event.nodeID];
3514
+ if (current === undefined) {
3515
+ throw new ReducerError("unknown-node", event.nodeID);
3516
+ }
3517
+ if (current.status === "cancelled") {
3518
+ return state;
3519
+ }
3520
+ if (current.status === "succeeded") {
3521
+ throw new ReducerError("illegal-transition", "cancel succeeded");
3522
+ }
3523
+ return withNode({ ...state, seq: event.seq }, event.nodeID, {
3524
+ ...current,
3525
+ status: "cancelled"
3526
+ });
3527
+ }
3528
+ function applyRunCompleted(state, seq) {
3529
+ for (const node of Object.values(state.nodes)) {
3530
+ if (node.status !== "succeeded" && node.status !== "cancelled") {
3531
+ throw new ReducerError("incomplete-run", node.status);
3532
+ }
3533
+ }
3534
+ return { ...state, status: "completed", seq };
3535
+ }
3536
+ function applyEvent(spec, state, event) {
3537
+ if (event.runID !== state.runID) {
3538
+ throw new ReducerError("run-mismatch", event.runID);
3539
+ }
3540
+ if (TERMINAL_RUN_STATUSES.has(state.status)) {
3541
+ if (event.type === "run.completed" && state.status === "completed" || event.type === "run.failed" && state.status === "failed" || event.type === "run.cancelled" && state.status === "cancelled") {
3542
+ return state;
3543
+ }
3544
+ throw new ReducerError("post-terminal", event.type);
3545
+ }
3546
+ switch (event.type) {
3547
+ case "run.started":
3548
+ return applyRunStarted(state, event.seq, event.specDigest);
3549
+ case "node.dispatched":
3550
+ return applyDispatched(spec, state, event);
3551
+ case "node.succeeded":
3552
+ return applySucceeded(state, event);
3553
+ case "node.failed":
3554
+ return applyFailed(state, event);
3555
+ case "node.cancelled":
3556
+ return applyCancelled(state, event);
3557
+ case "run.completed":
3558
+ return applyRunCompleted(state, event.seq);
3559
+ case "run.failed":
3560
+ return { ...state, status: "failed", seq: event.seq };
3561
+ case "run.cancelled":
3562
+ return { ...state, status: "cancelled", seq: event.seq };
3563
+ }
3564
+ }
3565
+
3566
+ // src/graph/replay.ts
3567
+ class ReplayError extends Error {
3568
+ code;
3569
+ detail;
3570
+ constructor(detail) {
3571
+ super(`sequence-gap: ${detail}`);
3572
+ this.name = "ReplayError";
3573
+ this.code = "sequence-gap";
3574
+ this.detail = detail;
3575
+ }
3576
+ }
3577
+ function replay(spec, events) {
3578
+ let state = initialState(spec);
3579
+ events.forEach((event, index) => {
3580
+ if (event.seq !== index) {
3581
+ throw new ReplayError(`expected ${index}, got ${event.seq}`);
3582
+ }
3583
+ state = applyEvent(spec, state, event);
3584
+ });
3585
+ return state;
3586
+ }
3587
+
3588
+ // src/graph/schema.ts
3589
+ import { z as z7 } from "zod";
3590
+
3591
+ // src/context/schema.ts
3592
+ import { z as z6 } from "zod";
3593
+ var PrivacyClassSchema = z6.enum(["public", "internal", "sensitive"]);
3594
+ var Sha256Schema = z6.string().regex(/^[0-9a-f]{64}$/, "expected lowercase hex sha-256");
3595
+ var IdentifierSchema = z6.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "invalid identifier");
3596
+ var TaskAnchorSchema = z6.object({
3597
+ taskID: IdentifierSchema,
3598
+ specDigest: Sha256Schema
3599
+ }).strict();
3600
+ var ContextRefSchema = z6.object({
3601
+ uri: z6.string().min(1).max(1024),
3602
+ sha256: Sha256Schema,
3603
+ bytes: z6.number().int().nonnegative(),
3604
+ mediaType: z6.string().min(1).max(128).optional()
3605
+ }).strict();
3606
+ var ManifestEntrySchema = z6.object({
3607
+ label: IdentifierSchema,
3608
+ sha256: Sha256Schema,
3609
+ bytes: z6.number().int().nonnegative(),
3610
+ ref: ContextRefSchema.optional()
3611
+ }).strict();
3612
+ var ArtifactManifestSchema = z6.object({
3613
+ version: z6.literal(1),
3614
+ taskID: IdentifierSchema,
3615
+ privacyClass: PrivacyClassSchema,
3616
+ entries: z6.array(ManifestEntrySchema)
3617
+ }).strict();
3618
+ var NodeContextContractSchema = z6.object({
3619
+ version: z6.literal(1),
3620
+ refs: z6.array(ContextRefSchema),
3621
+ privacyClass: PrivacyClassSchema,
3622
+ maxInputTokens: z6.number().int().positive().optional()
3623
+ }).strict();
3624
+
3625
+ // src/graph/schema.ts
3626
+ var GRAPH_SPEC_VERSION = 1;
3627
+ var GRAPH_EVENT_VERSION = 1;
3628
+ var NodeIDSchema = z7.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "invalid node id");
3629
+ var NodeRoleSchema = z7.enum(["implementer", "reviewer"]);
3630
+ var OperationIDSchema = z7.string().regex(/^[0-9a-f]{8,64}$/, "invalid operation id");
3631
+ var AttemptIDSchema = z7.string().regex(/^[0-9a-f]{8,64}$/, "invalid attempt id");
3632
+ var ErrorClassSchema = z7.enum([
3633
+ "transient",
3634
+ "permanent",
3635
+ "timeout",
3636
+ "cancelled",
3637
+ "unknown"
3638
+ ]);
3639
+ var GraphNodeSchema = z7.object({
3640
+ id: NodeIDSchema,
3641
+ role: NodeRoleSchema,
3642
+ dependsOn: z7.array(NodeIDSchema).default([]),
3643
+ anchor: TaskAnchorSchema,
3644
+ reviews: NodeIDSchema.optional()
3645
+ }).strict();
3646
+ var GraphSpecV1Schema = z7.object({
3647
+ version: z7.literal(GRAPH_SPEC_VERSION),
3648
+ runID: NodeIDSchema,
3649
+ nodes: z7.array(GraphNodeSchema).min(1)
3650
+ }).strict();
3651
+ var eventEnvelope = {
3652
+ v: z7.literal(GRAPH_EVENT_VERSION),
3653
+ seq: z7.number().int().nonnegative(),
3654
+ runID: NodeIDSchema
3655
+ };
3656
+ var RunStartedEventSchema = z7.object({
3657
+ ...eventEnvelope,
3658
+ type: z7.literal("run.started"),
3659
+ specDigest: Sha256Schema
3660
+ }).strict();
3661
+ var NodeDispatchedEventSchema = z7.object({
3662
+ ...eventEnvelope,
3663
+ type: z7.literal("node.dispatched"),
3664
+ nodeID: NodeIDSchema,
3665
+ operationID: OperationIDSchema,
3666
+ attemptID: AttemptIDSchema
3667
+ }).strict();
3668
+ var NodeSucceededEventSchema = z7.object({
3669
+ ...eventEnvelope,
3670
+ type: z7.literal("node.succeeded"),
3671
+ nodeID: NodeIDSchema,
3672
+ operationID: OperationIDSchema,
3673
+ attemptID: AttemptIDSchema,
3674
+ artifact: ContextRefSchema
3675
+ }).strict();
3676
+ var NodeFailedEventSchema = z7.object({
3677
+ ...eventEnvelope,
3678
+ type: z7.literal("node.failed"),
3679
+ nodeID: NodeIDSchema,
3680
+ operationID: OperationIDSchema,
3681
+ attemptID: AttemptIDSchema,
3682
+ errorClass: ErrorClassSchema
3683
+ }).strict();
3684
+ var NodeCancelledEventSchema = z7.object({
3685
+ ...eventEnvelope,
3686
+ type: z7.literal("node.cancelled"),
3687
+ nodeID: NodeIDSchema
3688
+ }).strict();
3689
+ var RunCompletedEventSchema = z7.object({ ...eventEnvelope, type: z7.literal("run.completed") }).strict();
3690
+ var RunFailedEventSchema = z7.object({ ...eventEnvelope, type: z7.literal("run.failed") }).strict();
3691
+ var RunCancelledEventSchema = z7.object({ ...eventEnvelope, type: z7.literal("run.cancelled") }).strict();
3692
+ var GraphEventV1Schema = z7.discriminatedUnion("type", [
3693
+ RunStartedEventSchema,
3694
+ NodeDispatchedEventSchema,
3695
+ NodeSucceededEventSchema,
3696
+ NodeFailedEventSchema,
3697
+ NodeCancelledEventSchema,
3698
+ RunCompletedEventSchema,
3699
+ RunFailedEventSchema,
3700
+ RunCancelledEventSchema
3701
+ ]);
3702
+
3703
+ class GraphSchemaError extends Error {
3704
+ code;
3705
+ issues;
3706
+ constructor(code, error) {
3707
+ super(`${code}: ${error.issues.map((issue) => issue.message).join("; ")}`);
3708
+ this.name = "GraphSchemaError";
3709
+ this.code = code;
3710
+ this.issues = error.issues.map((issue) => issue.message);
3711
+ }
3712
+ }
3713
+ function parseGraphSpec(input) {
3714
+ const result = GraphSpecV1Schema.safeParse(input);
3715
+ if (!result.success) {
3716
+ throw new GraphSchemaError("invalid-spec", result.error);
3717
+ }
3718
+ return result.data;
3719
+ }
3720
+ function parseGraphEvent(input) {
3721
+ const result = GraphEventV1Schema.safeParse(input);
3722
+ if (!result.success) {
3723
+ throw new GraphSchemaError("invalid-event", result.error);
3724
+ }
3725
+ return result.data;
3726
+ }
3727
+
3728
+ // src/storage/graph/codec.ts
3729
+ var CODEC_VERSION = 1;
3730
+ var GENESIS_DIGEST = sha256Hex("openteam/graph-journal/genesis/v1");
3731
+ var NUL = "\x00";
3732
+ var NEWLINE = `
3733
+ `;
3734
+ function canonical(value) {
3735
+ if (value === null || typeof value !== "object") {
3736
+ return JSON.stringify(value);
3737
+ }
3738
+ const record = value;
3739
+ const entries = Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`);
3740
+ return `{${entries.join(",")}}`;
3741
+ }
3742
+ function frameDigest(prev, event) {
3743
+ return sha256Hex(`${prev}${NUL}${canonical(event)}`);
3744
+ }
3745
+
3746
+ class JournalCodecError extends Error {
3747
+ code;
3748
+ detail;
3749
+ constructor(code, detail) {
3750
+ super(`${code}: ${detail}`);
3751
+ this.name = "JournalCodecError";
3752
+ this.code = code;
3753
+ this.detail = detail;
3754
+ }
3755
+ }
3756
+ function encodeFrame(prev, seq, event) {
3757
+ const sum = frameDigest(prev, event);
3758
+ const line = canonical({ v: CODEC_VERSION, seq, prev, sum, event });
3759
+ return { line, digest: sum };
3760
+ }
3761
+ function decodeFrame(raw, index, expectedPrev) {
3762
+ let parsed;
3763
+ try {
3764
+ parsed = JSON.parse(raw);
3765
+ } catch {
3766
+ throw new JournalCodecError("bad-frame", `unparseable frame ${index}`);
3767
+ }
3768
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
3769
+ throw new JournalCodecError("bad-frame", `frame ${index} is not an object`);
3770
+ }
3771
+ const frame = parsed;
3772
+ if (frame.v !== CODEC_VERSION) {
3773
+ throw new JournalCodecError("bad-version", `frame ${index}`);
3774
+ }
3775
+ if (typeof frame.seq !== "number" || typeof frame.prev !== "string" || typeof frame.sum !== "string") {
3776
+ throw new JournalCodecError("bad-frame", `frame ${index} header`);
3777
+ }
3778
+ let event;
3779
+ try {
3780
+ event = parseGraphEvent(frame.event);
3781
+ } catch {
3782
+ throw new JournalCodecError("bad-frame", `frame ${index} event`);
3783
+ }
3784
+ if (frame.seq !== index) {
3785
+ throw new JournalCodecError("bad-sequence", `expected ${index}, got ${frame.seq}`);
3786
+ }
3787
+ if (frame.prev !== expectedPrev) {
3788
+ throw new JournalCodecError("chain-break", `frame ${index}`);
3789
+ }
3790
+ if (frame.sum !== frameDigest(frame.prev, event)) {
3791
+ throw new JournalCodecError("bad-checksum", `frame ${index}`);
3792
+ }
3793
+ return { event, digest: frame.sum };
3794
+ }
3795
+ function decodeJournal(text) {
3796
+ const segments = text.split(NEWLINE);
3797
+ const trailing = segments.pop() ?? "";
3798
+ const partialTail = trailing !== "";
3799
+ const events = [];
3800
+ let prev = GENESIS_DIGEST;
3801
+ segments.forEach((raw, index) => {
3802
+ const { event, digest } = decodeFrame(raw, index, prev);
3803
+ events.push(event);
3804
+ prev = digest;
3805
+ });
3806
+ return { events, digest: prev, partialTail };
3807
+ }
3808
+
3809
+ // src/storage/graph/provider.ts
3810
+ class JournalError extends Error {
3811
+ code;
3812
+ detail;
3813
+ constructor(code, detail) {
3814
+ super(`${code}: ${detail}`);
3815
+ this.name = "JournalError";
3816
+ this.code = code;
3817
+ this.detail = detail;
3818
+ }
3819
+ }
3820
+
3821
+ // src/storage/graph/writer.ts
3822
+ import {
3823
+ closeSync,
3824
+ existsSync,
3825
+ fsyncSync,
3826
+ mkdirSync,
3827
+ openSync,
3828
+ readFileSync,
3829
+ realpathSync,
3830
+ writeSync
3831
+ } from "node:fs";
3832
+ function ensureDir(dir) {
3833
+ mkdirSync(dir, { recursive: true });
3834
+ }
3835
+ function writeDurable(file, content) {
3836
+ const fd = openSync(file, "w");
3837
+ try {
3838
+ writeSync(fd, content);
3839
+ fsyncSync(fd);
3840
+ } finally {
3841
+ closeSync(fd);
3842
+ }
3843
+ }
3844
+ function appendDurable(file, content) {
3845
+ const fd = openSync(file, "a");
3846
+ try {
3847
+ writeSync(fd, content);
3848
+ fsyncSync(fd);
3849
+ } finally {
3850
+ closeSync(fd);
3851
+ }
3852
+ }
3853
+ function readText(file) {
3854
+ if (!existsSync(file)) {
3855
+ return;
3856
+ }
3857
+ return readFileSync(file, "utf8");
3858
+ }
3859
+ function pathExists(path) {
3860
+ return existsSync(path);
3861
+ }
3862
+
3863
+ // src/storage/graph/fsGraphJournal.ts
3864
+ var NUL2 = "\x00";
3865
+ var JOURNAL_FILE = "journal.ndjson";
3866
+ var OWNER_FILE = "owner";
3867
+ var SPEC_FILE = "spec.json";
3868
+ function createFsGraphJournal(root) {
3869
+ let counter = 0;
3870
+ const runDir = (runID) => join2(root, runID);
3871
+ const journalPath = (runID) => join2(runDir(runID), JOURNAL_FILE);
3872
+ const ownerPath = (runID) => join2(runDir(runID), OWNER_FILE);
3873
+ const specPath = (runID) => join2(runDir(runID), SPEC_FILE);
3874
+ const issueToken = (runID, prev) => {
3875
+ const token = sha256Hex(`writer${NUL2}${runID}${NUL2}${prev}${NUL2}${counter}`).slice(0, 32);
3876
+ counter += 1;
3877
+ return token;
3878
+ };
3879
+ const readDecoded = (runID) => {
3880
+ const text = readText(journalPath(runID)) ?? "";
3881
+ try {
3882
+ return decodeJournal(text);
3883
+ } catch (error) {
3884
+ throw new JournalError("corrupt", error.message);
3885
+ }
3886
+ };
3887
+ return {
3888
+ async create(spec) {
3889
+ const parsed = parseGraphSpec(structuredClone(spec));
3890
+ if (pathExists(runDir(parsed.runID))) {
3891
+ throw new JournalError("already-exists", parsed.runID);
3892
+ }
3893
+ ensureDir(runDir(parsed.runID));
3894
+ writeDurable(specPath(parsed.runID), JSON.stringify(parsed));
3895
+ writeDurable(journalPath(parsed.runID), "");
3896
+ const token = issueToken(parsed.runID, GENESIS_DIGEST);
3897
+ writeDurable(ownerPath(parsed.runID), token);
3898
+ return { runID: parsed.runID, writerToken: token };
3899
+ },
3900
+ async takeOver(runID) {
3901
+ if (!pathExists(runDir(runID))) {
3902
+ throw new JournalError("not-found", runID);
3903
+ }
3904
+ const prev = readText(ownerPath(runID)) ?? GENESIS_DIGEST;
3905
+ const token = issueToken(runID, prev);
3906
+ writeDurable(ownerPath(runID), token);
3907
+ return { runID, writerToken: token };
3908
+ },
3909
+ async append(handle, event, expectedSeq) {
3910
+ if (!pathExists(runDir(handle.runID))) {
3911
+ throw new JournalError("not-found", handle.runID);
3912
+ }
3913
+ if (readText(ownerPath(handle.runID)) !== handle.writerToken) {
3914
+ throw new JournalError("writer-conflict", handle.runID);
3915
+ }
3916
+ const decoded = readDecoded(handle.runID);
3917
+ if (decoded.partialTail) {
3918
+ throw new JournalError("corrupt", "partial tail; recovery required");
3919
+ }
3920
+ const head = decoded.events.length;
3921
+ if (event.seq < head) {
3922
+ throw new JournalError("duplicate-event", `seq ${event.seq}`);
3923
+ }
3924
+ if (event.seq !== head || expectedSeq !== head) {
3925
+ throw new JournalError("sequence-mismatch", `head=${head} expected=${expectedSeq} event=${event.seq}`);
3926
+ }
3927
+ const frame = encodeFrame(decoded.digest, head, event);
3928
+ appendDurable(journalPath(handle.runID), `${frame.line}
3929
+ `);
3930
+ },
3931
+ async load(runID) {
3932
+ if (!pathExists(runDir(runID))) {
3933
+ throw new JournalError("not-found", runID);
3934
+ }
3935
+ const decoded = readDecoded(runID);
3936
+ const specText = readText(specPath(runID));
3937
+ if (specText === undefined) {
3938
+ throw new JournalError("corrupt", "missing spec");
3939
+ }
3940
+ let spec;
3941
+ try {
3942
+ spec = parseGraphSpec(JSON.parse(specText));
3943
+ } catch (error) {
3944
+ throw new JournalError("corrupt", error.message);
3945
+ }
3946
+ let loaded;
3947
+ try {
3948
+ loaded = {
3949
+ spec,
3950
+ events: decoded.events,
3951
+ state: replay(spec, decoded.events)
3952
+ };
3953
+ } catch (error) {
3954
+ throw new JournalError("corrupt", error.message);
3955
+ }
3956
+ return loaded;
3957
+ },
3958
+ async exists(runID) {
3959
+ return pathExists(runDir(runID));
3960
+ }
3961
+ };
3962
+ }
3963
+
3964
+ // src/telemetry/graphProjection.ts
3965
+ function projectGraphEvent(event) {
3966
+ const record = {
3967
+ v: event.v,
3968
+ seq: event.seq,
3969
+ runID: event.runID,
3970
+ type: event.type,
3971
+ ..."nodeID" in event ? { nodeID: event.nodeID } : {},
3972
+ ..."operationID" in event ? { operationID: event.operationID } : {},
3973
+ ..."attemptID" in event ? { attemptID: event.attemptID } : {},
3974
+ ..."errorClass" in event ? { errorClass: event.errorClass } : {},
3975
+ ..."specDigest" in event ? { specDigest: event.specDigest } : {},
3976
+ ..."artifact" in event ? { artifact: redactedRef(event.artifact) } : {}
3977
+ };
3978
+ assertReferenceOnly(record);
3979
+ return record;
3980
+ }
3981
+
3982
+ // src/telemetry/graphRuntimeHealth.ts
3983
+ var RUN_TERMINAL_TYPES = new Set([
3984
+ "run.completed",
3985
+ "run.failed",
3986
+ "run.cancelled"
3987
+ ]);
3988
+ var NODE_TERMINAL_TYPES = new Set([
3989
+ "node.succeeded",
3990
+ "node.failed",
3991
+ "node.cancelled"
3992
+ ]);
3993
+ function isRecoveryRequired(journal, unknownEffects) {
3994
+ return journal === "corrupt" || unknownEffects > 0;
3995
+ }
3996
+ function computeGraphRuntimeHealth(input) {
3997
+ const dispatched = new Set;
3998
+ const resolved = new Set;
3999
+ let runTerminalSeq = Number.POSITIVE_INFINITY;
4000
+ const staleAttempts = new Set;
4001
+ for (const event of input.events) {
4002
+ if (event.type === "node.dispatched") {
4003
+ dispatched.add(event.attemptID);
4004
+ } else if (NODE_TERMINAL_TYPES.has(event.type)) {
4005
+ if ("attemptID" in event && event.attemptID !== undefined) {
4006
+ resolved.add(event.attemptID);
4007
+ if (event.seq > runTerminalSeq) {
4008
+ staleAttempts.add(event.attemptID);
4009
+ }
4010
+ }
4011
+ }
4012
+ if (RUN_TERMINAL_TYPES.has(event.type)) {
4013
+ if (event.seq < runTerminalSeq) {
4014
+ runTerminalSeq = event.seq;
4015
+ }
4016
+ }
4017
+ }
4018
+ let unknownEffects = 0;
4019
+ for (const attemptID of dispatched) {
4020
+ if (!resolved.has(attemptID)) {
4021
+ unknownEffects++;
4022
+ }
4023
+ }
4024
+ const staleCompletions = staleAttempts.size;
4025
+ const recoveryRequired = isRecoveryRequired(input.journal, unknownEffects);
4026
+ let conflicts = 0;
4027
+ if (input.lease !== undefined && !input.lease.released && input.lease.holder !== input.holder) {
4028
+ conflicts++;
4029
+ }
4030
+ if (input.worktrees !== undefined) {
4031
+ conflicts += input.worktrees.blocked;
4032
+ }
4033
+ const health = {
4034
+ recoveryRequired,
4035
+ unknownEffects,
4036
+ staleCompletions,
4037
+ conflicts,
4038
+ killSwitch: input.killSwitch
4039
+ };
4040
+ assertReferenceOnly(health);
4041
+ return health;
4042
+ }
4043
+
4044
+ // src/telemetry/graphView.ts
4045
+ function isReady(node, state) {
4046
+ return node.dependsOn.every((dep) => state.nodes[dep]?.status === "succeeded");
4047
+ }
4048
+ function toViewState(node, status, state) {
4049
+ if (status === "running") {
4050
+ return "active";
4051
+ }
4052
+ if (status === "pending") {
4053
+ return isReady(node, state) ? "ready" : "pending";
4054
+ }
4055
+ return status;
4056
+ }
4057
+ function deriveVerdict(status) {
4058
+ if (status === "succeeded") {
4059
+ return "approved";
4060
+ }
4061
+ if (status === "failed") {
4062
+ return "rejected";
4063
+ }
4064
+ return "inconclusive";
4065
+ }
4066
+ function indexTelemetry(telemetry) {
4067
+ const lastError = new Map;
4068
+ const lastArtifact = new Map;
4069
+ for (const record of telemetry) {
4070
+ if (record.nodeID === undefined) {
4071
+ continue;
4072
+ }
4073
+ if (record.type === "node.failed" && record.errorClass !== undefined) {
4074
+ lastError.set(record.nodeID, record.errorClass);
4075
+ }
4076
+ if (record.type === "node.succeeded" && record.artifact !== undefined) {
4077
+ lastArtifact.set(record.nodeID, record.artifact);
4078
+ }
4079
+ }
4080
+ return { lastError, lastArtifact };
4081
+ }
4082
+ function buildNodeView(node, input, lastError, lastArtifact) {
4083
+ const runtime = input.state.nodes[node.id];
4084
+ const status = runtime?.status ?? "pending";
4085
+ const attempts = runtime?.attempts ?? 0;
4086
+ const errorClass = lastError.get(node.id);
4087
+ const artifact = lastArtifact.get(node.id);
4088
+ const sessionRef = input.sessions?.[node.id];
4089
+ const review = node.role === "reviewer" && node.reviews !== undefined ? { verdict: deriveVerdict(status), reassigned: attempts > 1 } : undefined;
4090
+ return {
4091
+ nodeID: node.id,
4092
+ role: node.role,
4093
+ state: toViewState(node, status, input.state),
4094
+ attempts,
4095
+ ...errorClass !== undefined ? { lastErrorClass: errorClass } : {},
4096
+ ...review !== undefined ? { review } : {},
4097
+ ...node.reviews !== undefined ? { revisionOf: node.reviews } : {},
4098
+ ...artifact !== undefined ? { artifact } : {},
4099
+ ...sessionRef !== undefined ? { sessionRef } : {}
4100
+ };
4101
+ }
4102
+ function buildEdges(spec) {
4103
+ return spec.nodes.flatMap((node) => node.dependsOn.map((from) => ({ from, to: node.id })));
4104
+ }
4105
+ function buildGraphView(input) {
4106
+ const { lastError, lastArtifact } = indexTelemetry(input.telemetry);
4107
+ const nodes = input.spec.nodes.map((node) => buildNodeView(node, input, lastError, lastArtifact));
4108
+ const projection = {
4109
+ version: 1,
4110
+ runID: input.spec.runID,
4111
+ nodes,
4112
+ edges: buildEdges(input.spec),
4113
+ health: input.health
4114
+ };
4115
+ assertReferenceOnly(projection);
4116
+ return projection;
4117
+ }
4118
+
4119
+ // src/cli/graphViewProvider.ts
4120
+ function selectMostRecentRun(journalRoot) {
4121
+ if (!pathExists(journalRoot)) {
4122
+ return;
4123
+ }
4124
+ let entries;
4125
+ try {
4126
+ entries = readdirSync(journalRoot);
4127
+ } catch {
4128
+ return;
4129
+ }
4130
+ if (entries.length === 0) {
4131
+ return;
4132
+ }
4133
+ let best;
4134
+ for (const name of entries) {
4135
+ const specFile = join3(journalRoot, name, "spec.json");
4136
+ let mtime;
4137
+ try {
4138
+ mtime = statSync(specFile).mtimeMs;
4139
+ } catch {
4140
+ continue;
4141
+ }
4142
+ if (best === undefined || mtime > best.mtime || mtime === best.mtime && name > best.runID) {
4143
+ best = { runID: name, mtime };
4144
+ }
4145
+ }
4146
+ return best?.runID;
4147
+ }
4148
+ function createGraphViewProvider(deps) {
4149
+ const selectRun = deps.selectRun ?? selectMostRecentRun;
4150
+ const journal = createFsGraphJournal(deps.journalRoot);
4151
+ return {
4152
+ async readView() {
4153
+ const runID = selectRun(deps.journalRoot);
4154
+ if (runID === undefined) {
4155
+ return null;
4156
+ }
4157
+ try {
4158
+ const loaded = await journal.load(runID);
4159
+ const telemetry = loaded.events.map(projectGraphEvent);
4160
+ const health = computeGraphRuntimeHealth({
4161
+ events: loaded.events,
4162
+ journal: "clean",
4163
+ lease: undefined,
4164
+ holder: "console",
4165
+ killSwitch: deps.killSwitch
4166
+ });
4167
+ return buildGraphView({
4168
+ spec: loaded.spec,
4169
+ state: loaded.state,
4170
+ telemetry,
4171
+ health
4172
+ });
4173
+ } catch (error) {
4174
+ if (error instanceof JournalError && error.code === "corrupt") {
4175
+ deps.log(`Graph view: journal for run "${runID}" is corrupt (${error.detail}); skipping.`);
4176
+ return null;
4177
+ }
4178
+ if (error instanceof JournalError && error.code === "not-found") {
4179
+ return null;
4180
+ }
4181
+ throw error;
4182
+ }
4183
+ }
4184
+ };
4185
+ }
4186
+
3304
4187
  // src/cli/consoleServe.ts
3305
4188
  function parseConsoleServeArgs(rest) {
3306
4189
  return {
@@ -3323,6 +4206,14 @@ async function runConsoleServe(deps, options) {
3323
4206
  endpoint,
3324
4207
  ...deps.serverPassword !== undefined ? { password: deps.serverPassword } : {}
3325
4208
  }));
4209
+ const graphMode = config.graph?.mode ?? "off";
4210
+ const graphViewEnabled = config.console.graphView?.enabled === true;
4211
+ const buildGraphView2 = deps.createGraphViewProvider ?? createGraphViewProvider;
4212
+ const graphViewProvider = graphMode !== "off" && graphViewEnabled ? buildGraphView2({
4213
+ journalRoot: config.graph?.journalRoot ?? DEFAULT_GRAPH_JOURNAL_ROOT,
4214
+ killSwitch: config.graph?.killSwitch ?? false,
4215
+ log: deps.log
4216
+ }) : undefined;
3326
4217
  let runtime;
3327
4218
  try {
3328
4219
  runtime = await start({
@@ -3343,6 +4234,7 @@ async function runConsoleServe(deps, options) {
3343
4234
  createClient: makeClient,
3344
4235
  createPtyClient: makePtyClient
3345
4236
  },
4237
+ ...graphViewProvider !== undefined ? { graphView: graphViewProvider } : {},
3346
4238
  ...config.console.remoteStorage ? {
3347
4239
  storageApi: {
3348
4240
  storage: deps.storage,
@@ -4535,8 +5427,11 @@ function buildOrchestratorAgent(frontier, options = {}) {
4535
5427
  "con `mode: subagent` (usa `read`/`glob`/`list`).",
4536
5428
  "",
4537
5429
  "- **Si el equipo YA existe** → actúa como coordinador: entiende la tarea,",
4538
- " repártela entre los subagentes adecuados con la herramienta `task` y",
4539
- " reutiliza el reparto existente. No vuelvas a castear ni recrear agentes.",
5430
+ " identifica qué roles del roster la cubren y **delega la distribución a la",
5431
+ " herramienta `openteam-orchestrate`** con las asignaciones correspondientes.",
5432
+ " openteam se encarga del routing de modelo, la creación de subsesiones y la",
5433
+ " telemetría — tú no necesitas usar `task` directamente para roles del roster.",
5434
+ " Reutiliza el reparto existente. No vuelvas a castear ni recrear agentes.",
4540
5435
  "- **Si NO existe equipo** (sin `openteam-roster.md` ni subagentes): **no pidas",
4541
5436
  " permiso para crearlo**. Entiende primero las tareas que implica la",
4542
5437
  " petición, diseña el equipo mínimo necesario, **créalo a demanda** y luego",
@@ -4637,6 +5532,39 @@ function buildOrchestratorAgent(frontier, options = {}) {
4637
5532
  "Explica brevemente al usuario tu plan (qué va en paralelo y qué en serie, y",
4638
5533
  "por qué) antes o mientras lanzas las tareas.",
4639
5534
  "",
5535
+ "## Distribución de trabajo con `openteam-orchestrate`",
5536
+ "",
5537
+ "Cuando el roster existe, **usa la herramienta `openteam-orchestrate`** para",
5538
+ "distribuir el trabajo entre los roles del equipo. Esta herramienta delega a",
5539
+ "nuestro código el routing de modelo por rol, la creación de subsesiones y la",
5540
+ "telemetría — no improvises estos pasos manualmente con `task`.",
5541
+ "",
5542
+ "Payload (las claves son estrictas — claves desconocidas se rechazan):",
5543
+ "",
5544
+ "```json",
5545
+ "{",
5546
+ ' "assignments": [',
5547
+ ' { "roleID": "<rol-del-roster>", "prompt": "<tarea accionable>", "title": "<título opcional>" },',
5548
+ ' { "roleID": "<otro-rol>", "prompt": "<otra tarea>" }',
5549
+ " ],",
5550
+ ' "parentSessionID": "<sesión actual, opcional>",',
5551
+ ' "directory": "<directorio de trabajo, opcional>"',
5552
+ "}",
5553
+ "```",
5554
+ "",
5555
+ "- `assignments` (obligatorio): lista de asignaciones. Cada una tiene un",
5556
+ " `roleID` (debe coincidir con un rol del roster) y un `prompt` accionable.",
5557
+ " `title` es opcional y solo para legibilidad.",
5558
+ "- `parentSessionID` (opcional): la sesión actual, para que las subsesiones",
5559
+ " se vinculen como hijas.",
5560
+ "- `directory` (opcional): directorio de trabajo si difiere del actual.",
5561
+ "",
5562
+ "La herramienta devuelve un resumen por rol: modelo seleccionado, éxito o",
5563
+ "fallo, y sesión creada. Si un rol falla, el resto sigue ejecutándose.",
5564
+ "",
5565
+ "**Usa `task` directamente** solo para subagentes ad-hoc que no estén en el",
5566
+ "roster (p. ej. un agente creado a demanda para un trabajo puntual).",
5567
+ "",
4640
5568
  "## Lista de tareas con responsable visible",
4641
5569
  "",
4642
5570
  "Mantén la lista de tareas de la sesión con `todowrite` y **haz visible quién",
@@ -4658,8 +5586,9 @@ function buildOrchestratorAgent(frontier, options = {}) {
4658
5586
  "",
4659
5587
  "- **Empieza siempre comprobando el equipo** (roster + subagentes) antes de",
4660
5588
  " delegar; si falta, créalo antes de repartir el trabajo.",
4661
- "- Delega el trabajo con la herramienta `task` al subagente adecuado; tú te",
4662
- " mantienes como coordinador y no implementas lo que puede hacer un subagente.",
5589
+ "- Delega el trabajo del roster con `openteam-orchestrate`; usa `task` solo",
5590
+ " para subagentes ad-hoc que no tengan rol en el roster. te mantienes como",
5591
+ " coordinador y no implementas lo que puede hacer un subagente.",
4663
5592
  "- **Lanza en un solo turno las tareas independientes** para que corran en",
4664
5593
  " paralelo; secuencia solo las que dependen de un resultado previo.",
4665
5594
  "- Crea subagentes **justo cuando el trabajo lo pide**, nunca “por si acaso”.",
@@ -4953,7 +5882,10 @@ async function runCli(argv, deps) {
4953
5882
  const config = await deps.loadConfig(configPath);
4954
5883
  return { exitCode: 0, stdout: renderConsoleStatus(config.console) };
4955
5884
  }
4956
- if (command === undefined || command === "help" || command === "--help") {
5885
+ if (command === "--version" || command === "-v") {
5886
+ return { exitCode: 0, stdout: deps.version };
5887
+ }
5888
+ if (command === undefined || command === "help" || command === "--help" || command === "-h") {
4957
5889
  return { exitCode: 0, stdout: HELP };
4958
5890
  }
4959
5891
  return {
@@ -5560,54 +6492,54 @@ function loadOpenTeamConfig(raw) {
5560
6492
  }
5561
6493
 
5562
6494
  // src/memory/types.ts
5563
- import { z as z6 } from "zod";
6495
+ import { z as z8 } from "zod";
5564
6496
  var SHARED_OWNER_KEY = "*";
5565
- var OwnerKeySchema = z6.string().min(1);
5566
- var MemoryKindSchema = z6.enum(["fact", "preference", "entity"]);
5567
- var MemoryBaseSchema = z6.object({
5568
- id: z6.string().min(1),
6497
+ var OwnerKeySchema = z8.string().min(1);
6498
+ var MemoryKindSchema = z8.enum(["fact", "preference", "entity"]);
6499
+ var MemoryBaseSchema = z8.object({
6500
+ id: z8.string().min(1),
5569
6501
  ownerKey: OwnerKeySchema,
5570
- confidence: z6.number().min(0).max(1),
5571
- validFrom: z6.number().finite(),
5572
- validUntil: z6.number().finite().nullable().default(null),
5573
- createdAt: z6.number().finite(),
5574
- invalidatedAt: z6.number().finite().nullable().default(null),
5575
- sourceHash: z6.string().min(1),
5576
- supersededBy: z6.string().min(1).nullable().default(null)
6502
+ confidence: z8.number().min(0).max(1),
6503
+ validFrom: z8.number().finite(),
6504
+ validUntil: z8.number().finite().nullable().default(null),
6505
+ createdAt: z8.number().finite(),
6506
+ invalidatedAt: z8.number().finite().nullable().default(null),
6507
+ sourceHash: z8.string().min(1),
6508
+ supersededBy: z8.string().min(1).nullable().default(null)
5577
6509
  });
5578
6510
  var FactSchema = MemoryBaseSchema.extend({
5579
- kind: z6.literal("fact"),
5580
- subject: z6.string().min(1),
5581
- predicate: z6.string().min(1),
5582
- object: z6.string().min(1),
5583
- category: z6.string().min(1).nullable().default(null)
6511
+ kind: z8.literal("fact"),
6512
+ subject: z8.string().min(1),
6513
+ predicate: z8.string().min(1),
6514
+ object: z8.string().min(1),
6515
+ category: z8.string().min(1).nullable().default(null)
5584
6516
  });
5585
6517
  var PreferenceSchema = MemoryBaseSchema.extend({
5586
- kind: z6.literal("preference"),
5587
- category: z6.string().min(1),
5588
- preference: z6.string().min(1),
5589
- context: z6.string().min(1).nullable().default(null),
5590
- lastAccessedAt: z6.number().finite().nullable().default(null),
5591
- accessCount: z6.number().int().min(0).default(0)
6518
+ kind: z8.literal("preference"),
6519
+ category: z8.string().min(1),
6520
+ preference: z8.string().min(1),
6521
+ context: z8.string().min(1).nullable().default(null),
6522
+ lastAccessedAt: z8.number().finite().nullable().default(null),
6523
+ accessCount: z8.number().int().min(0).default(0)
5592
6524
  });
5593
6525
  var EntitySchema = MemoryBaseSchema.extend({
5594
- kind: z6.literal("entity"),
5595
- canonicalName: z6.string().min(1),
5596
- type: z6.string().min(1),
5597
- aliases: z6.array(z6.string().min(1)).default([])
6526
+ kind: z8.literal("entity"),
6527
+ canonicalName: z8.string().min(1),
6528
+ type: z8.string().min(1),
6529
+ aliases: z8.array(z8.string().min(1)).default([])
5598
6530
  });
5599
- var MemoryRecordSchema = z6.discriminatedUnion("kind", [
6531
+ var MemoryRecordSchema = z8.discriminatedUnion("kind", [
5600
6532
  FactSchema,
5601
6533
  PreferenceSchema,
5602
6534
  EntitySchema
5603
6535
  ]);
5604
- var RecallQuerySchema = z6.object({
6536
+ var RecallQuerySchema = z8.object({
5605
6537
  ownerKey: OwnerKeySchema,
5606
- kinds: z6.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
5607
- asOf: z6.number().finite().nullable().default(null),
5608
- limit: z6.number().int().positive().default(8),
5609
- minSimilarity: z6.number().min(0).max(1).default(0.2),
5610
- includeShared: z6.boolean().default(true)
6538
+ kinds: z8.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
6539
+ asOf: z8.number().finite().nullable().default(null),
6540
+ limit: z8.number().int().positive().default(8),
6541
+ minSimilarity: z8.number().min(0).max(1).default(0.2),
6542
+ includeShared: z8.boolean().default(true)
5611
6543
  });
5612
6544
 
5613
6545
  // src/memory/rank.ts
@@ -6516,6 +7448,104 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
6516
7448
  return;
6517
7449
  }
6518
7450
  }
7451
+ // package.json
7452
+ var package_default = {
7453
+ name: "@jmanuelcorral/openteam",
7454
+ version: "0.2.2",
7455
+ packageManager: "bun@1.3.14",
7456
+ description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
7457
+ license: "MIT",
7458
+ author: "Jose Manuel Corral",
7459
+ repository: {
7460
+ type: "git",
7461
+ url: "git+https://github.com/jmanuelcorral/openteam.git"
7462
+ },
7463
+ homepage: "https://github.com/jmanuelcorral/openteam#readme",
7464
+ bugs: {
7465
+ url: "https://github.com/jmanuelcorral/openteam/issues"
7466
+ },
7467
+ keywords: [
7468
+ "opencode",
7469
+ "opencode-plugin",
7470
+ "llm",
7471
+ "routing",
7472
+ "local-llm",
7473
+ "ollama",
7474
+ "lm-studio",
7475
+ "foundry-local",
7476
+ "cost-optimization",
7477
+ "multi-agent"
7478
+ ],
7479
+ engines: {
7480
+ bun: ">=1.3",
7481
+ node: "^22.22.2 || ^24.15.0 || >=26.0.0"
7482
+ },
7483
+ type: "module",
7484
+ main: "./dist/index.js",
7485
+ module: "./dist/index.js",
7486
+ types: "./dist/index.d.ts",
7487
+ bin: {
7488
+ openteam: "./dist/cli.js"
7489
+ },
7490
+ exports: {
7491
+ ".": {
7492
+ types: "./dist/index.d.ts",
7493
+ import: "./dist/index.js"
7494
+ },
7495
+ "./package.json": "./package.json"
7496
+ },
7497
+ files: [
7498
+ "dist",
7499
+ "README.md",
7500
+ "LICENSE",
7501
+ "AGENTS.md",
7502
+ ".opencode/openteam.example.json",
7503
+ ".opencode/command/openteam.md"
7504
+ ],
7505
+ publishConfig: {
7506
+ access: "public",
7507
+ registry: "https://registry.npmjs.org/"
7508
+ },
7509
+ trustedDependencies: [],
7510
+ sideEffects: false,
7511
+ scripts: {
7512
+ prebuild: "bun run clean",
7513
+ build: "bun run build:js && bun run build:cli && bun run build:types",
7514
+ "build:js": "bun build ./src/index.ts --target=node --format=esm --outfile=dist/index.js --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod",
7515
+ "build:cli": 'bun build ./src/cli.ts --target=node --format=esm --outfile=dist/cli.js --banner "#!/usr/bin/env node" --external @opencode-ai/plugin --external @opencode-ai/sdk --external zod --external @clack/prompts',
7516
+ "build:types": "tsc -p tsconfig.build.json",
7517
+ clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
7518
+ test: "bun test",
7519
+ "test:cov": "bun test --coverage",
7520
+ "certify:shadow": "bun test tests/certification/graph-shadow.test.ts",
7521
+ "certify:release": "bun test tests/certification/graph-release.test.ts",
7522
+ "coverage:check": "node scripts/check-coverage.mjs",
7523
+ typecheck: "tsc --noEmit",
7524
+ lint: "biome check .",
7525
+ "format:check": "biome format .",
7526
+ "docs:install": "cd docs && bun install --frozen-lockfile --ignore-scripts",
7527
+ "docs:dev": "cd docs && bun run docs:dev",
7528
+ "docs:build": "cd docs && bun run docs:build",
7529
+ "docs:preview": "cd docs && bun run docs:preview",
7530
+ prepublishOnly: "bun run build",
7531
+ "link:local": "bun run build && npm link",
7532
+ "hooks:install": "git config core.hooksPath .githooks"
7533
+ },
7534
+ dependencies: {
7535
+ "@clack/prompts": "1.7.0",
7536
+ "@opencode-ai/plugin": "1.18.18",
7537
+ "@opencode-ai/sdk": "1.18.18",
7538
+ zod: "4.4.3"
7539
+ },
7540
+ devDependencies: {
7541
+ "@biomejs/biome": "2.5.9",
7542
+ "@types/bun": "1.3.14",
7543
+ typescript: "7.0.2"
7544
+ }
7545
+ };
7546
+
7547
+ // src/version.ts
7548
+ var PACKAGE_VERSION = package_default.version;
6519
7549
 
6520
7550
  // src/web/git.ts
6521
7551
  function createGitLastCommit(exec) {
@@ -6623,7 +7653,8 @@ var deps = {
6623
7653
  telemetryPath: DEFAULT_TELEMETRY_PATH,
6624
7654
  opencodeConfigPath: OPENCODE_CONFIG_PATH,
6625
7655
  orchestratorAgentPath: ORCHESTRATOR_AGENT_PATH,
6626
- agentDir: AGENT_DIR
7656
+ agentDir: AGENT_DIR,
7657
+ version: PACKAGE_VERSION
6627
7658
  };
6628
7659
  function createSetupDeps() {
6629
7660
  return {