oh-my-opencode-slim 1.0.7 โ†’ 1.1.1

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 (38) hide show
  1. package/README.md +16 -6
  2. package/dist/cli/config-io.d.ts +1 -0
  3. package/dist/cli/index.js +170 -52
  4. package/dist/goal/index.d.ts +3 -0
  5. package/dist/goal/manager.d.ts +41 -0
  6. package/dist/goal/prompts.d.ts +4 -0
  7. package/dist/goal/store.d.ts +15 -0
  8. package/dist/goal/types.d.ts +28 -0
  9. package/dist/hooks/index.d.ts +1 -0
  10. package/dist/hooks/session-goal/index.d.ts +38 -0
  11. package/dist/index.js +1135 -369
  12. package/dist/multiplexer/session-manager.d.ts +3 -1
  13. package/dist/tools/fork/command.d.ts +28 -0
  14. package/dist/tools/fork/files.d.ts +33 -0
  15. package/dist/tools/fork/index.d.ts +10 -0
  16. package/dist/tools/fork/state.d.ts +7 -0
  17. package/dist/tools/fork/tools.d.ts +23 -0
  18. package/dist/tools/fork/vendor.d.ts +28 -0
  19. package/dist/tools/handoff/command.d.ts +29 -0
  20. package/dist/tools/handoff/files.d.ts +33 -0
  21. package/dist/tools/handoff/index.d.ts +10 -0
  22. package/dist/tools/handoff/state.d.ts +7 -0
  23. package/dist/tools/handoff/tools.d.ts +23 -0
  24. package/dist/tools/handoff/vendor.d.ts +28 -0
  25. package/dist/tools/index.d.ts +2 -0
  26. package/dist/tools/subtask/command.d.ts +30 -0
  27. package/dist/tools/subtask/files.d.ts +34 -0
  28. package/dist/tools/subtask/index.d.ts +11 -0
  29. package/dist/tools/subtask/state.d.ts +7 -0
  30. package/dist/tools/subtask/tools.d.ts +23 -0
  31. package/dist/tools/subtask/vendor.d.ts +27 -0
  32. package/dist/tui.js +56 -0
  33. package/dist/utils/session.d.ts +2 -1
  34. package/package.json +1 -1
  35. package/src/skills/clonedeps/README.md +23 -0
  36. package/src/skills/clonedeps/SKILL.md +237 -0
  37. package/src/skills/clonedeps/codemap.md +41 -0
  38. package/src/skills/codemap.md +8 -5
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  <div align="center">
2
- <img src="img/team.jpeg" alt="Pantheon agents" style="border-radius: 10px;">
3
- <p><i>Seven divine beings emerged from the dawn of code, each an immortal master of their craft await your command to forge order from chaos and build what was once thought impossible.</i></p>
2
+ <a href="https://github.com/alvinunreal/oh-my-opencode-slim/stargazers">
3
+ <img src="img/4k.png" alt="4K GitHub Stars Milestone" style="border-radius: 10px;">
4
+ </a>
5
+ <h3>๐ŸŽ‰ 4,000+ Stars! Thank you! ๐ŸŽ‰</h3>
6
+ <p><i>We are incredibly grateful to our community for helping us reach this milestone.<br>The Pantheon grows stronger every day because of your feedback, contributions, and support!</i></p>
7
+
4
8
  <p><b>Open Multi Agent Suite</b> ยท Mix any models ยท Auto delegate tasks</p>
5
9
 
6
10
  <p><sub>by <b>Boring Dystopia Development</b></sub></p>
@@ -39,8 +43,10 @@ bunx oh-my-opencode-slim@latest install
39
43
 
40
44
  The installer also registers the companion TUI plugin in OpenCode's
41
45
  `tui.json`, which adds a small sidebar showing specialist-agent status plus
42
- active/reusable task sessions. For manual setups, add `oh-my-opencode-slim` to
43
- the `plugin` array in both `opencode.json` and `tui.json`.
46
+ active/reusable task sessions. It also warms OpenCode's plugin cache so bunx
47
+ installs keep loading even after temporary directories are cleaned up. For
48
+ manual setups, add `oh-my-opencode-slim` to the `plugin` array in both
49
+ `opencode.json` and `tui.json`.
44
50
 
45
51
  ### Getting Started
46
52
 
@@ -486,9 +492,12 @@ Use this section as a map: start with installation, then jump to features, confi
486
492
  | **[Council](docs/council.md)** | Run multiple models in parallel and synthesize a single answer with `@council` |
487
493
  | **[Multiplexer Integration](docs/multiplexer-integration.md)** | Watch agents work live in Tmux or Zellij panes |
488
494
  | **[Session Management](docs/session-management.md)** | Reuse recent child-agent sessions with short aliases instead of starting over |
495
+ | **[Session Goal](docs/session-goal.md)** | Pin a session objective with `/goal` so todos, delegation, and verification stay aligned |
489
496
  | **[Todo Continuation](docs/todo-continuation.md)** | Auto-continue orchestrator sessions with cooldowns and safety checks |
490
497
  | **[Preset Switching](docs/preset-switching.md)** | Switch agent model presets at runtime with `/preset` |
498
+ | **[Subtask](docs/subtask.md)** | Run a bounded child worker with `/subtask` and return a structured summary to the main session |
491
499
  | **[Codemap](docs/codemap.md)** | Generate hierarchical codemaps to understand large codebases faster |
500
+ | **[Clonedeps](docs/clonedeps.md)** | Clone selected dependency source into an ignored local workspace for inspection |
492
501
  | **[Interview](docs/interview.md)** | Turn rough ideas into a structured markdown spec through a browser-based Q&A flow |
493
502
  | **[Divoom Display](docs/divoom.md)** | Mirror orchestrator and specialist-agent activity to a Divoom MiniToo Bluetooth display |
494
503
 
@@ -498,7 +507,7 @@ Use this section as a map: start with installation, then jump to features, confi
498
507
  |-----|----------------|
499
508
  | **[Configuration](docs/configuration.md)** | Config file locations, JSONC support, prompt overrides, and full option reference |
500
509
  | **[Maintainer Guide](docs/maintainers.md)** | Issue triage rules, label meanings, support routing, and repo maintenance workflow |
501
- | **[Skills](docs/skills.md)** | Built-in and recommended skills such as `simplify`, `agent-browser`, and `codemap` |
510
+ | **[Skills](docs/skills.md)** | Built-in and recommended skills such as `simplify`, `agent-browser`, `codemap`, and `clonedeps` |
502
511
  | **[MCPs](docs/mcps.md)** | `websearch`, `context7`, `grep_app`, and how MCP permissions work per agent |
503
512
  | **[Tools](docs/tools.md)** | Built-in tool capabilities like `webfetch`, LSP tools, code search, and formatters |
504
513
 
@@ -519,7 +528,7 @@ Use this section as a map: start with installation, then jump to features, confi
519
528
  <p><sub>Every merged contribution leaves a mark on the realm.</sub></p>
520
529
 
521
530
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
522
- [![All Contributors](https://img.shields.io/badge/all_contributors-45-orange.svg?style=flat-square)](#contributors-)
531
+ [![All Contributors](https://img.shields.io/badge/all_contributors-46-orange.svg?style=flat-square)](#contributors-)
523
532
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
524
533
  </div>
525
534
 
@@ -590,6 +599,7 @@ Use this section as a map: start with installation, then jump to features, confi
590
599
  <td align="center" valign="top" width="16.66%"><a href="https://github.com/gustavocaiano"><img src="https://avatars.githubusercontent.com/u/104129313?v=4?s=100" width="100px;" alt="Gustavo Caiano"/><br /><sub><b>Gustavo Caiano</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=gustavocaiano" title="Code">๐Ÿ’ป</a></td>
591
600
  <td align="center" valign="top" width="16.66%"><a href="https://github.com/ThomasMldr"><img src="https://avatars.githubusercontent.com/u/6631765?v=4?s=100" width="100px;" alt="Thomas Mulder"/><br /><sub><b>Thomas Mulder</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=ThomasMldr" title="Code">๐Ÿ’ป</a></td>
592
601
  <td align="center" valign="top" width="16.66%"><a href="https://github.com/maou-shonen"><img src="https://avatars.githubusercontent.com/u/22576780?v=4?s=100" width="100px;" alt="้ญ”็Ž‹ๅฐ‘ๅนด(maou shonen)"/><br /><sub><b>้ญ”็Ž‹ๅฐ‘ๅนด(maou shonen)</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=maou-shonen" title="Code">๐Ÿ’ป</a></td>
602
+ <td align="center" valign="top" width="16.66%"><a href="https://github.com/jelasin"><img src="https://avatars.githubusercontent.com/u/97788570?v=4?s=100" width="100px;" alt=" Jelasin"/><br /><sub><b> Jelasin</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=jelasin" title="Code">๐Ÿ’ป</a></td>
593
603
  </tr>
594
604
  </tbody>
595
605
  </table>
@@ -1,4 +1,5 @@
1
1
  import type { ConfigMergeResult, DetectedConfig, InstallConfig, OpenCodeConfig } from './types';
2
+ export declare function warmOpenCodePluginCache(): Promise<ConfigMergeResult | null>;
2
3
  /**
3
4
  * Strip JSON comments (single-line // and multi-line) and trailing commas for JSONC support.
4
5
  */
package/dist/cli/index.js CHANGED
@@ -15,13 +15,61 @@ import * as path from "node:path";
15
15
  import {
16
16
  copyFileSync as copyFileSync2,
17
17
  existsSync as existsSync3,
18
+ mkdirSync as mkdirSync3,
18
19
  readFileSync,
19
20
  renameSync,
20
21
  statSync as statSync2,
21
22
  writeFileSync
22
23
  } from "node:fs";
24
+ import { homedir as homedir2 } from "node:os";
23
25
  import { dirname as dirname3, join as join3 } from "node:path";
24
26
 
27
+ // src/utils/compat.ts
28
+ import { spawn as nodeSpawn } from "node:child_process";
29
+ var isBun = typeof globalThis.Bun !== "undefined";
30
+ function collectStream(stream) {
31
+ if (!stream)
32
+ return () => Promise.resolve("");
33
+ const chunks = [];
34
+ stream.on("data", (chunk) => chunks.push(chunk));
35
+ return () => new Promise((resolve, reject) => {
36
+ if (!stream.readable) {
37
+ resolve(Buffer.concat(chunks).toString("utf-8"));
38
+ return;
39
+ }
40
+ stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
41
+ stream.on("error", reject);
42
+ });
43
+ }
44
+ function crossSpawn(command, options) {
45
+ const [cmd, ...args] = command;
46
+ const proc = nodeSpawn(cmd, args, {
47
+ stdio: [
48
+ options?.stdin ?? "ignore",
49
+ options?.stdout ?? "pipe",
50
+ options?.stderr ?? "pipe"
51
+ ],
52
+ cwd: options?.cwd,
53
+ env: options?.env
54
+ });
55
+ const stdoutCollector = collectStream(proc.stdout);
56
+ const stderrCollector = collectStream(proc.stderr);
57
+ const exited = new Promise((resolve, reject) => {
58
+ proc.on("error", reject);
59
+ proc.on("close", (code) => resolve(code ?? 1));
60
+ });
61
+ return {
62
+ proc,
63
+ stdout: stdoutCollector,
64
+ stderr: stderrCollector,
65
+ exited,
66
+ kill: (signal) => proc.kill(signal),
67
+ get exitCode() {
68
+ return proc.exitCode;
69
+ }
70
+ };
71
+ }
72
+
25
73
  // src/cli/paths.ts
26
74
  import { existsSync, mkdirSync } from "node:fs";
27
75
  import { homedir } from "node:os";
@@ -419,6 +467,12 @@ var CUSTOM_SKILLS = [
419
467
  description: "Repository understanding and hierarchical codemap generation",
420
468
  allowedAgents: ["orchestrator"],
421
469
  sourcePath: "src/skills/codemap"
470
+ },
471
+ {
472
+ name: "clonedeps",
473
+ description: "Clone important dependency source for local inspection",
474
+ allowedAgents: ["orchestrator"],
475
+ sourcePath: "src/skills/clonedeps"
422
476
  }
423
477
  ];
424
478
  function getCustomSkillsDir() {
@@ -658,10 +712,6 @@ function findPackageRoot(startPath) {
658
712
  currentPath = parentPath;
659
713
  }
660
714
  }
661
- function isPackageManagerInstall(path) {
662
- const normalizedPath = normalizePathForMatch(path);
663
- return normalizedPath.includes(`/node_modules/${PACKAGE_NAME}`);
664
- }
665
715
  function isLocalPackageRootEntry(entry) {
666
716
  if (!entry || entry.startsWith("file://")) {
667
717
  return false;
@@ -677,6 +727,10 @@ function isLocalPackageRootEntry(entry) {
677
727
  return false;
678
728
  }
679
729
  }
730
+ function isPackageManagerInstall(path) {
731
+ const normalizedPath = normalizePathForMatch(path);
732
+ return normalizedPath.includes(`/node_modules/${PACKAGE_NAME}`);
733
+ }
680
734
  function isPluginEntry(entry) {
681
735
  return entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`) || entry.startsWith("file://") && entry.includes(PACKAGE_NAME) || isLocalPackageRootEntry(entry);
682
736
  }
@@ -699,6 +753,104 @@ function getPluginEntry() {
699
753
  return PACKAGE_NAME;
700
754
  }
701
755
  }
756
+ function getOpenCodePluginCacheDir() {
757
+ const cacheDir = process.env.XDG_CACHE_HOME?.trim() || join3(homedir2(), ".cache");
758
+ return join3(cacheDir, "opencode", "packages", `${PACKAGE_NAME}@latest`);
759
+ }
760
+ function writeOpenCodePluginCacheManifest(cacheDir) {
761
+ try {
762
+ writeFileSync(join3(cacheDir, "package.json"), JSON.stringify({
763
+ name: `${PACKAGE_NAME}-cache`,
764
+ private: true,
765
+ dependencies: {
766
+ [PACKAGE_NAME]: "latest"
767
+ }
768
+ }, null, 2));
769
+ return null;
770
+ } catch (err) {
771
+ return {
772
+ success: false,
773
+ configPath: cacheDir,
774
+ error: `Failed to write cache package.json: ${err}`
775
+ };
776
+ }
777
+ }
778
+ function verifyOpenCodePluginCache(cacheDir) {
779
+ const pluginPackageJsonPath = join3(cacheDir, "node_modules", PACKAGE_NAME, "package.json");
780
+ if (!existsSync3(pluginPackageJsonPath)) {
781
+ return {
782
+ success: false,
783
+ configPath: cacheDir,
784
+ error: `Cached plugin package not found at ${pluginPackageJsonPath}`
785
+ };
786
+ }
787
+ try {
788
+ const packageJson = JSON.parse(readFileSync(pluginPackageJsonPath, "utf-8"));
789
+ if (packageJson.name !== PACKAGE_NAME) {
790
+ return {
791
+ success: false,
792
+ configPath: cacheDir,
793
+ error: `Cached plugin package has unexpected name: ${packageJson.name}`
794
+ };
795
+ }
796
+ } catch (err) {
797
+ return {
798
+ success: false,
799
+ configPath: cacheDir,
800
+ error: `Failed to verify cached plugin package: ${err}`
801
+ };
802
+ }
803
+ return null;
804
+ }
805
+ async function warmOpenCodePluginCache() {
806
+ const cliEntryPath = process.argv[1];
807
+ if (!cliEntryPath) {
808
+ return null;
809
+ }
810
+ const packageRoot = findPackageRoot(cliEntryPath);
811
+ if (!packageRoot || !isPackageManagerInstall(packageRoot)) {
812
+ return null;
813
+ }
814
+ const cacheDir = getOpenCodePluginCacheDir();
815
+ try {
816
+ mkdirSync3(cacheDir, { recursive: true });
817
+ } catch (err) {
818
+ return {
819
+ success: false,
820
+ configPath: cacheDir,
821
+ error: `Failed to create OpenCode cache directory: ${err}`
822
+ };
823
+ }
824
+ const manifestError = writeOpenCodePluginCacheManifest(cacheDir);
825
+ if (manifestError)
826
+ return manifestError;
827
+ try {
828
+ const proc = crossSpawn(["bun", "install", "--ignore-scripts"], {
829
+ cwd: cacheDir,
830
+ stdout: "pipe",
831
+ stderr: "pipe"
832
+ });
833
+ await proc.exited;
834
+ if (proc.exitCode !== 0) {
835
+ const stderr = (await proc.stderr()).trim();
836
+ return {
837
+ success: false,
838
+ configPath: cacheDir,
839
+ error: stderr || `bun install exited with code ${proc.exitCode}`
840
+ };
841
+ }
842
+ const verificationError = verifyOpenCodePluginCache(cacheDir);
843
+ if (verificationError)
844
+ return verificationError;
845
+ return { success: true, configPath: cacheDir };
846
+ } catch (err) {
847
+ return {
848
+ success: false,
849
+ configPath: cacheDir,
850
+ error: `Failed to warm OpenCode cache: ${err}`
851
+ };
852
+ }
853
+ }
702
854
  function stripJsonComments(json) {
703
855
  const commentPattern = /\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g;
704
856
  const trailingCommaPattern = /\\"|"(?:\\"|[^"])*"|(,)(\s*[}\]])/g;
@@ -1205,54 +1357,6 @@ import { createInterface } from "node:readline/promises";
1205
1357
  // src/cli/system.ts
1206
1358
  import { spawnSync as spawnSync2 } from "node:child_process";
1207
1359
  import { statSync as statSync4 } from "node:fs";
1208
-
1209
- // src/utils/compat.ts
1210
- import { spawn as nodeSpawn } from "node:child_process";
1211
- var isBun = typeof globalThis.Bun !== "undefined";
1212
- function collectStream(stream) {
1213
- if (!stream)
1214
- return () => Promise.resolve("");
1215
- const chunks = [];
1216
- stream.on("data", (chunk) => chunks.push(chunk));
1217
- return () => new Promise((resolve, reject) => {
1218
- if (!stream.readable) {
1219
- resolve(Buffer.concat(chunks).toString("utf-8"));
1220
- return;
1221
- }
1222
- stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
1223
- stream.on("error", reject);
1224
- });
1225
- }
1226
- function crossSpawn(command, options) {
1227
- const [cmd, ...args] = command;
1228
- const proc = nodeSpawn(cmd, args, {
1229
- stdio: [
1230
- options?.stdin ?? "ignore",
1231
- options?.stdout ?? "pipe",
1232
- options?.stderr ?? "pipe"
1233
- ],
1234
- cwd: options?.cwd,
1235
- env: options?.env
1236
- });
1237
- const stdoutCollector = collectStream(proc.stdout);
1238
- const stderrCollector = collectStream(proc.stderr);
1239
- const exited = new Promise((resolve, reject) => {
1240
- proc.on("error", reject);
1241
- proc.on("close", (code) => resolve(code ?? 1));
1242
- });
1243
- return {
1244
- proc,
1245
- stdout: stdoutCollector,
1246
- stderr: stderrCollector,
1247
- exited,
1248
- kill: (signal) => proc.kill(signal),
1249
- get exitCode() {
1250
- return proc.exitCode;
1251
- }
1252
- };
1253
- }
1254
-
1255
- // src/cli/system.ts
1256
1360
  var cachedOpenCodePath = null;
1257
1361
  function resolvePathCommand(command) {
1258
1362
  try {
@@ -1478,6 +1582,7 @@ async function runInstall(config) {
1478
1582
  totalSteps += 1;
1479
1583
  if (config.installCustomSkills)
1480
1584
  totalSteps += 1;
1585
+ totalSteps += 1;
1481
1586
  let step = 1;
1482
1587
  printStep(step++, totalSteps, "Checking OpenCode installation...");
1483
1588
  if (config.dryRun) {
@@ -1506,6 +1611,19 @@ async function runInstall(config) {
1506
1611
  handleStepResult(tuiResult, "TUI badge added");
1507
1612
  }
1508
1613
  }
1614
+ printStep(step++, totalSteps, "Warming OpenCode plugin cache...");
1615
+ if (config.dryRun) {
1616
+ printInfo("Dry run mode - skipping cache warm-up");
1617
+ } else {
1618
+ const cacheResult = await warmOpenCodePluginCache();
1619
+ if (cacheResult === null) {
1620
+ printInfo("Local development install - cache warm-up not required");
1621
+ } else if (!cacheResult.success) {
1622
+ printInfo(`Skipped cache warm-up: ${cacheResult.error}`);
1623
+ } else {
1624
+ handleStepResult(cacheResult, "OpenCode cache warmed");
1625
+ }
1626
+ }
1509
1627
  printStep(step++, totalSteps, "Disabling OpenCode default agents...");
1510
1628
  if (config.dryRun) {
1511
1629
  printInfo("Dry run mode - skipping agent disabling");
@@ -0,0 +1,3 @@
1
+ export { createGoalManager, type GoalManager } from './manager';
2
+ export { GoalStore, getGoalStorePath } from './store';
3
+ export type { GoalCheckpoint, GoalConfig, GoalRecord, GoalStatus, } from './types';
@@ -0,0 +1,41 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ import type { GoalConfig } from './types';
3
+ interface MessagePart {
4
+ type?: string;
5
+ text?: string;
6
+ [key: string]: unknown;
7
+ }
8
+ interface ChatTransformMessage {
9
+ info: {
10
+ role?: string;
11
+ agent?: string;
12
+ sessionID?: string;
13
+ };
14
+ parts: MessagePart[];
15
+ }
16
+ export declare function createGoalManager(ctx: PluginInput, config?: GoalConfig): {
17
+ registerCommand: (opencodeConfig: Record<string, unknown>) => void;
18
+ handleCommandExecuteBefore: (input: {
19
+ command: string;
20
+ sessionID: string;
21
+ arguments: string;
22
+ }, output: {
23
+ parts: Array<{
24
+ type: string;
25
+ text?: string;
26
+ }>;
27
+ }) => Promise<void>;
28
+ handleMessagesTransform: (output: {
29
+ messages: ChatTransformMessage[];
30
+ }) => Promise<void>;
31
+ handleEvent: (input: {
32
+ event: {
33
+ type: string;
34
+ properties?: Record<string, unknown>;
35
+ };
36
+ }) => Promise<void>;
37
+ hasActiveGoal: (sessionID: string) => boolean;
38
+ hasRunningGoal: (sessionID: string) => boolean;
39
+ };
40
+ export type GoalManager = ReturnType<typeof createGoalManager>;
41
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { GoalRecord } from './types';
2
+ export declare function buildGoalContext(goal: GoalRecord): string;
3
+ export declare function buildGoalContinuationPrompt(goal: GoalRecord): string;
4
+ export declare function buildGoalStartPrompt(goal: GoalRecord): string;
@@ -0,0 +1,15 @@
1
+ import type { GoalRecord } from './types';
2
+ interface GoalStoreSnapshot {
3
+ version: 1;
4
+ goals: GoalRecord[];
5
+ }
6
+ export declare function getGoalStorePath(): string;
7
+ export declare class GoalStore {
8
+ read(): GoalStoreSnapshot;
9
+ write(snapshot: GoalStoreSnapshot): void;
10
+ list(): GoalRecord[];
11
+ save(goal: GoalRecord): void;
12
+ findActiveBySession(sessionID: string): GoalRecord | undefined;
13
+ findLatestByDirectory(directory: string): GoalRecord | undefined;
14
+ }
15
+ export {};
@@ -0,0 +1,28 @@
1
+ export type GoalStatus = 'running' | 'paused' | 'blocked' | 'completed' | 'archived';
2
+ export interface GoalCheckpoint {
3
+ id: string;
4
+ createdAt: string;
5
+ note: string;
6
+ }
7
+ export interface GoalRecord {
8
+ version: 1;
9
+ id: string;
10
+ directory: string;
11
+ sessionID: string;
12
+ objective: string;
13
+ stopCondition?: string;
14
+ validationCommands: string[];
15
+ artifacts: string[];
16
+ status: GoalStatus;
17
+ createdAt: string;
18
+ updatedAt: string;
19
+ maxCycles: number;
20
+ completedCycles: number;
21
+ checkpoints: GoalCheckpoint[];
22
+ lastError?: string;
23
+ }
24
+ export interface GoalConfig {
25
+ maxCycles?: number;
26
+ cooldownMs?: number;
27
+ shouldManageSession?: (sessionID: string) => boolean;
28
+ }
@@ -9,5 +9,6 @@ export { processImageAttachments } from './image-hook';
9
9
  export { createJsonErrorRecoveryHook } from './json-error-recovery';
10
10
  export { createPhaseReminderHook } from './phase-reminder';
11
11
  export { createPostFileToolNudgeHook } from './post-file-tool-nudge';
12
+ export { createSessionGoalHook } from './session-goal';
12
13
  export { createTaskSessionManagerHook } from './task-session-manager';
13
14
  export { createTodoContinuationHook } from './todo-continuation';
@@ -0,0 +1,38 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ import type { PluginConfig } from '../../config';
3
+ interface GoalState {
4
+ text: string;
5
+ source?: 'manual' | 'interview';
6
+ sourcePath?: string;
7
+ inheritedFrom?: string;
8
+ createdAt: number;
9
+ }
10
+ interface SystemTransformOutput {
11
+ system: string[];
12
+ }
13
+ export declare function createSessionGoalHook(ctx: PluginInput, config: PluginConfig, options?: {
14
+ getAgentName?: (sessionID: string) => string | undefined;
15
+ }): {
16
+ registerCommand: (config: Record<string, unknown>) => void;
17
+ handleCommandExecuteBefore: (input: {
18
+ command: string;
19
+ sessionID: string;
20
+ arguments: string;
21
+ }, output: {
22
+ parts: Array<{
23
+ type: string;
24
+ text?: string;
25
+ }>;
26
+ }) => Promise<void>;
27
+ handleEvent: (input: {
28
+ event: {
29
+ type: string;
30
+ properties?: Record<string, unknown>;
31
+ };
32
+ }) => void;
33
+ handleSystemTransform: (input: {
34
+ sessionID?: string;
35
+ }, output: SystemTransformOutput) => void;
36
+ getGoal: (sessionID: string) => GoalState | undefined;
37
+ };
38
+ export {};