@agimon-ai/doompi-loop 0.0.1-alpha.81 → 0.0.1-alpha.82

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 (146) hide show
  1. package/dist/{src/schemas/apiContracts.cjs → apiContracts.cjs} +5 -1
  2. package/dist/apiContracts.cjs.map +1 -0
  3. package/dist/{src/schemas/apiContracts.d.mts.map → apiContracts.d.mts.map} +1 -1
  4. package/dist/{src/schemas/apiContracts.mjs → apiContracts.mjs} +1 -1
  5. package/dist/apiContracts.mjs.map +1 -0
  6. package/dist/extensions/pi.cjs +596 -13
  7. package/dist/extensions/pi.cjs.map +1 -1
  8. package/dist/extensions/pi.d.mts +1 -1
  9. package/dist/extensions/pi.d.mts.map +1 -1
  10. package/dist/extensions/pi.mjs +590 -7
  11. package/dist/extensions/pi.mjs.map +1 -1
  12. package/dist/extensions/server.cjs +326 -14
  13. package/dist/extensions/server.cjs.map +1 -1
  14. package/dist/extensions/server.d.mts +1 -1
  15. package/dist/extensions/server.d.mts.map +1 -1
  16. package/dist/extensions/server.mjs +320 -8
  17. package/dist/extensions/server.mjs.map +1 -1
  18. package/dist/index.d.mts +1 -1
  19. package/dist/{src/schemas/loopLaunchers.cjs → loopLaunchers-BtcLH_xN.cjs} +19 -4
  20. package/dist/loopLaunchers-BtcLH_xN.cjs.map +1 -0
  21. package/dist/{src/schemas/loopLaunchers.d.cts → loopLaunchers-CPUUrDzQ.d.mts} +12 -11
  22. package/dist/loopLaunchers-CPUUrDzQ.d.mts.map +1 -0
  23. package/dist/{src/schemas/loopLaunchers.mjs → loopLaunchers-cCniFbVA.mjs} +2 -2
  24. package/dist/loopLaunchers-cCniFbVA.mjs.map +1 -0
  25. package/dist/loopLaunchers.cjs +1 -1
  26. package/dist/loopLaunchers.d.mts +1 -1
  27. package/dist/loopLaunchers.mjs +1 -1
  28. package/dist/{src/services/loopLaunchers/index.mjs → loopView-CLIBhqYC.cjs} +64 -2
  29. package/dist/loopView-CLIBhqYC.cjs.map +1 -0
  30. package/dist/{src/services/loopLaunchers/index.cjs → loopView-CmuIEbUa.mjs} +23 -2
  31. package/dist/loopView-CmuIEbUa.mjs.map +1 -0
  32. package/package.json +13 -12
  33. package/dist/api-contracts.cjs +0 -7
  34. package/dist/api-contracts.d.cts +0 -2
  35. package/dist/api-contracts.d.mts +0 -2
  36. package/dist/api-contracts.mjs +0 -2
  37. package/dist/extensions/pi.d.cts +0 -5
  38. package/dist/extensions/pi.d.cts.map +0 -1
  39. package/dist/extensions/server.d.cts +0 -5
  40. package/dist/extensions/server.d.cts.map +0 -1
  41. package/dist/index.d.cts +0 -2
  42. package/dist/loopLaunchers.d.cts +0 -2
  43. package/dist/src/constants/loop.cjs +0 -12
  44. package/dist/src/constants/loop.cjs.map +0 -1
  45. package/dist/src/constants/loop.mjs +0 -9
  46. package/dist/src/constants/loop.mjs.map +0 -1
  47. package/dist/src/constants/piLoop.cjs +0 -16
  48. package/dist/src/constants/piLoop.cjs.map +0 -1
  49. package/dist/src/constants/piLoop.mjs +0 -11
  50. package/dist/src/constants/piLoop.mjs.map +0 -1
  51. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.cli.cjs +0 -26
  52. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.cli.cjs.map +0 -1
  53. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.cli.mjs +0 -26
  54. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.cli.mjs.map +0 -1
  55. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.server.cjs +0 -7
  56. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.server.cjs.map +0 -1
  57. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.server.mjs +0 -7
  58. package/dist/src/extensions/workspaces/sessions/(backend)/_lib/runtime.server.mjs.map +0 -1
  59. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.cli.cjs +0 -6
  60. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.cli.cjs.map +0 -1
  61. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.cli.mjs +0 -7
  62. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.cli.mjs.map +0 -1
  63. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.server.cjs +0 -6
  64. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.server.cjs.map +0 -1
  65. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.server.mjs +0 -7
  66. package/dist/src/extensions/workspaces/sessions/(backend)/command/loop.server.mjs.map +0 -1
  67. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.cli.cjs +0 -6
  68. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.cli.cjs.map +0 -1
  69. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.cli.mjs +0 -7
  70. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.cli.mjs.map +0 -1
  71. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.server.cjs +0 -6
  72. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.server.cjs.map +0 -1
  73. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.server.mjs +0 -7
  74. package/dist/src/extensions/workspaces/sessions/(backend)/command/loops.server.mjs.map +0 -1
  75. package/dist/src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.cjs +0 -6
  76. package/dist/src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.cjs.map +0 -1
  77. package/dist/src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.mjs +0 -7
  78. package/dist/src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.mjs.map +0 -1
  79. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.cjs +0 -6
  80. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.cjs.map +0 -1
  81. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.mjs +0 -7
  82. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.mjs.map +0 -1
  83. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.server.cjs +0 -6
  84. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.server.cjs.map +0 -1
  85. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.server.mjs +0 -7
  86. package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.server.mjs.map +0 -1
  87. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.cjs +0 -6
  88. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.cjs.map +0 -1
  89. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.mjs +0 -7
  90. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.mjs.map +0 -1
  91. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.server.cjs +0 -6
  92. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.server.cjs.map +0 -1
  93. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.server.mjs +0 -7
  94. package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.server.mjs.map +0 -1
  95. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs +0 -14
  96. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs.map +0 -1
  97. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs +0 -15
  98. package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs.map +0 -1
  99. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs +0 -17
  100. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs.map +0 -1
  101. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs +0 -18
  102. package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs.map +0 -1
  103. package/dist/src/schemas/apiContracts.cjs.map +0 -1
  104. package/dist/src/schemas/apiContracts.d.cts +0 -53
  105. package/dist/src/schemas/apiContracts.d.cts.map +0 -1
  106. package/dist/src/schemas/apiContracts.mjs.map +0 -1
  107. package/dist/src/schemas/loopLaunchers.cjs.map +0 -1
  108. package/dist/src/schemas/loopLaunchers.d.cts.map +0 -1
  109. package/dist/src/schemas/loopLaunchers.d.mts +0 -60
  110. package/dist/src/schemas/loopLaunchers.d.mts.map +0 -1
  111. package/dist/src/schemas/loopLaunchers.mjs.map +0 -1
  112. package/dist/src/services/defaultLoopLauncher/index.cjs +0 -92
  113. package/dist/src/services/defaultLoopLauncher/index.cjs.map +0 -1
  114. package/dist/src/services/defaultLoopLauncher/index.mjs +0 -92
  115. package/dist/src/services/defaultLoopLauncher/index.mjs.map +0 -1
  116. package/dist/src/services/loopCommand/index.cjs +0 -15
  117. package/dist/src/services/loopCommand/index.cjs.map +0 -1
  118. package/dist/src/services/loopCommand/index.mjs +0 -15
  119. package/dist/src/services/loopCommand/index.mjs.map +0 -1
  120. package/dist/src/services/loopLaunchers/index.cjs.map +0 -1
  121. package/dist/src/services/loopLaunchers/index.mjs.map +0 -1
  122. package/dist/src/services/serverRuntime/index.cjs +0 -293
  123. package/dist/src/services/serverRuntime/index.cjs.map +0 -1
  124. package/dist/src/services/serverRuntime/index.mjs +0 -293
  125. package/dist/src/services/serverRuntime/index.mjs.map +0 -1
  126. package/dist/src/tui/leader.cjs +0 -36
  127. package/dist/src/tui/leader.cjs.map +0 -1
  128. package/dist/src/tui/leader.mjs +0 -36
  129. package/dist/src/tui/leader.mjs.map +0 -1
  130. package/dist/src/tui/loopListOverlay.cjs +0 -101
  131. package/dist/src/tui/loopListOverlay.cjs.map +0 -1
  132. package/dist/src/tui/loopListOverlay.mjs +0 -100
  133. package/dist/src/tui/loopListOverlay.mjs.map +0 -1
  134. package/dist/src/tui/loopRuntime.cjs +0 -256
  135. package/dist/src/tui/loopRuntime.cjs.map +0 -1
  136. package/dist/src/tui/loopRuntime.mjs +0 -256
  137. package/dist/src/tui/loopRuntime.mjs.map +0 -1
  138. package/dist/src/tui/startLoopOverlay.cjs +0 -71
  139. package/dist/src/tui/startLoopOverlay.cjs.map +0 -1
  140. package/dist/src/tui/startLoopOverlay.mjs +0 -70
  141. package/dist/src/tui/startLoopOverlay.mjs.map +0 -1
  142. package/dist/src/types/loopView.cjs +0 -19
  143. package/dist/src/types/loopView.cjs.map +0 -1
  144. package/dist/src/types/loopView.mjs +0 -18
  145. package/dist/src/types/loopView.mjs.map +0 -1
  146. /package/dist/{src/schemas/apiContracts.d.mts → apiContracts.d.mts} +0 -0
@@ -1,6 +1,10 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
1
5
  //#region src/schemas/apiContracts.ts
2
6
  /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
3
- const apiContracts = (0, require("@agimon-ai/doompi-core/api-contracts").defineApiContract)({
7
+ const apiContracts = (0, require("@agimon-ai/doompi-core/apiContracts").defineApiContract)({
4
8
  version: 1,
5
9
  http: [],
6
10
  sockets: [],
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;;;AAGA,MAAa,gBAAA,gDAAeA,CAAAA,CAAAA,kBAAAA,CAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../../../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";;qBAGa"}
@@ -1,4 +1,4 @@
1
- import { defineApiContract } from "@agimon-ai/doompi-core/api-contracts";
1
+ import { defineApiContract } from "@agimon-ai/doompi-core/apiContracts";
2
2
  //#region src/schemas/apiContracts.ts
3
3
  /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
4
4
  const apiContracts = defineApiContract({
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/doompi-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAa,eAAe,kBAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
@@ -2,29 +2,612 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_root_cli = require("../src/extensions/workspaces/sessions/(backend)/root.cli.cjs");
6
- const require_loop_cli = require("../src/extensions/workspaces/sessions/(backend)/command/loop.cli.cjs");
7
- const require_loops_cli = require("../src/extensions/workspaces/sessions/(backend)/command/loops.cli.cjs");
8
- const require_agent_settled_cli = require("../src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.cjs");
9
- const require_doompi_use_loop_cli = require("../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.cjs");
10
- let _agimon_ai_doompi_core_pi_extension = require("@agimon-ai/doompi-core/pi-extension");
11
- let _agimon_ai_doompi_core_extension_file = require("@agimon-ai/doompi-core/extension-file");
5
+ const require_loopLaunchers = require("../loopLaunchers-BtcLH_xN.cjs");
6
+ const require_loopView = require("../loopView-CLIBhqYC.cjs");
7
+ let _agimon_ai_doompi_core_piExtension = require("@agimon-ai/doompi-core/piExtension");
8
+ let _agimon_ai_doompi_core_extensionFile = require("@agimon-ai/doompi-core/extensionFile");
9
+ let _agimon_ai_doompi_minor_mode = require("@agimon-ai/doompi-minor-mode");
10
+ let _agimon_ai_doompi_core_cordisHost = require("@agimon-ai/doompi-core/cordisHost");
11
+ let _agimon_ai_doompi_core_uiHub = require("@agimon-ai/doompi-core/uiHub");
12
+ let _agimon_ai_doompi_ui_doomOverlay = require("@agimon-ai/doompi-ui/doomOverlay");
13
+ let _earendil_works_pi_tui = require("@earendil-works/pi-tui");
14
+ //#region src/constants/piLoop.ts
15
+ const PACKAGE_SOURCE = "@agimon-ai/doompi-loop";
16
+ const STATUS_KEY = "doom-loop";
17
+ const MODE_STATUS_ID = "loop.active";
18
+ const ACTIVE_MODE_COLOR = "warning";
19
+ const NOTIFY_INFO_LEVEL = "info";
20
+ const NOTIFY_WARNING_LEVEL = "warning";
21
+ //#endregion
22
+ //#region src/services/loopCommand/index.ts
23
+ function createLoopCommands(handlers) {
24
+ return [[require_loopView.START_COMMAND_NAME, {
25
+ description: require_loopView.START_COMMAND_DESCRIPTION,
26
+ handler: async (args, ctx) => handlers.start(ctx, args)
27
+ }], [require_loopView.LIST_COMMAND_NAME, {
28
+ description: require_loopView.LIST_COMMAND_DESCRIPTION,
29
+ handler: async (_args, ctx) => handlers.list(ctx)
30
+ }]];
31
+ }
32
+ //#endregion
33
+ //#region src/services/defaultLoopLauncher/index.ts
34
+ const DEFAULT_LAUNCHER_ID = "doompi.default";
35
+ const DEFAULT_INTERVAL_SECONDS = 300;
36
+ const MIN_INTERVAL_SECONDS = 30;
37
+ const MAX_INTERVAL_SECONDS = 3600;
38
+ const MILLISECONDS_PER_SECOND = 1e3;
39
+ const PROMPT_PREVIEW_LENGTH = 80;
40
+ function intervalError(raw) {
41
+ const seconds = Number(raw);
42
+ if (!Number.isInteger(seconds)) return `Interval must be a whole number of seconds, got ${raw}.`;
43
+ if (seconds < MIN_INTERVAL_SECONDS || seconds > MAX_INTERVAL_SECONDS) return `Interval must be between ${MIN_INTERVAL_SECONDS} and ${MAX_INTERVAL_SECONDS} seconds.`;
44
+ }
45
+ async function prepareDefaultLoop(ui, signal) {
46
+ const prompt = (await ui.editor("Loop prompt", ""))?.trim();
47
+ if (!prompt || signal.aborted) return void 0;
48
+ const rawInterval = await ui.input("Loop interval in seconds", `Default: ${DEFAULT_INTERVAL_SECONDS}s`);
49
+ if (rawInterval === void 0 || signal.aborted) return void 0;
50
+ const normalizedInterval = rawInterval.trim() || String(DEFAULT_INTERVAL_SECONDS);
51
+ const error = intervalError(normalizedInterval);
52
+ if (error) {
53
+ ui.notify(error, NOTIFY_WARNING_LEVEL);
54
+ return;
55
+ }
56
+ return {
57
+ prompt,
58
+ intervalSeconds: Number(normalizedInterval)
59
+ };
60
+ }
61
+ function promptPreview(prompt) {
62
+ const oneLine = prompt.replaceAll(/\s+/gu, " ").trim();
63
+ return oneLine.length > PROMPT_PREVIEW_LENGTH ? `${oneLine.slice(0, 79)}…` : oneLine;
64
+ }
65
+ function createDefaultLoopLauncher(pi) {
66
+ const pending = /* @__PURE__ */ new Set();
67
+ const requestPass = (loop) => {
68
+ if (loop.stopped) return;
69
+ if (!loop.context.isIdle()) {
70
+ pending.add(loop);
71
+ return;
72
+ }
73
+ pending.delete(loop);
74
+ try {
75
+ pi.sendUserMessage(loop.prompt);
76
+ } catch (error) {
77
+ loop.context.ui.notify(`Default loop pass could not start: ${error instanceof Error ? error.message : String(error)}`, NOTIFY_WARNING_LEVEL);
78
+ }
79
+ };
80
+ const onAgentSettled = () => {
81
+ const next = pending.values().next().value;
82
+ if (next) requestPass(next);
83
+ };
84
+ return {
85
+ onAgentSettled,
86
+ register(ctx, launchers) {
87
+ return launchers.register({
88
+ id: DEFAULT_LAUNCHER_ID,
89
+ source: PACKAGE_SOURCE,
90
+ label: "Default loop",
91
+ description: "Run your own prompt in this session on an interval",
92
+ async launch({ instanceId, signal }) {
93
+ const prepared = await prepareDefaultLoop(ctx.ui, signal);
94
+ if (!prepared || signal.aborted) return void 0;
95
+ const loop = {
96
+ ...prepared,
97
+ context: ctx,
98
+ stopped: false
99
+ };
100
+ loop.timer = setInterval(() => requestPass(loop), loop.intervalSeconds * MILLISECONDS_PER_SECOND);
101
+ loop.timer.unref?.();
102
+ requestPass(loop);
103
+ return {
104
+ instanceId,
105
+ label: "Default loop",
106
+ detail: `every ${loop.intervalSeconds}s · ${promptPreview(loop.prompt)}`,
107
+ stop() {
108
+ if (loop.stopped) return;
109
+ loop.stopped = true;
110
+ if (loop.timer) clearInterval(loop.timer);
111
+ loop.timer = void 0;
112
+ pending.delete(loop);
113
+ }
114
+ };
115
+ }
116
+ });
117
+ }
118
+ };
119
+ }
120
+ //#endregion
121
+ //#region src/tui/leader.ts
122
+ const LOOPS_GROUP_SEGMENT = {
123
+ key: "l",
124
+ label: "loops",
125
+ detail: "recurring prompt loops",
126
+ order: 60
127
+ };
128
+ function registerLeaderContribution(hub) {
129
+ const contribution = hub.registerLeader({
130
+ source: PACKAGE_SOURCE,
131
+ bindings: [{
132
+ id: "loop.start",
133
+ path: [LOOPS_GROUP_SEGMENT, {
134
+ key: "s",
135
+ label: "start",
136
+ detail: "begin a recurring loop"
137
+ }],
138
+ command: { name: require_loopView.START_COMMAND_NAME }
139
+ }, {
140
+ id: "loop.list",
141
+ path: [LOOPS_GROUP_SEGMENT, {
142
+ key: "l",
143
+ label: "list",
144
+ detail: "loops in this session"
145
+ }],
146
+ command: { name: require_loopView.LIST_COMMAND_NAME }
147
+ }]
148
+ });
149
+ return () => contribution.dispose();
150
+ }
151
+ //#endregion
152
+ //#region src/tui/loopListOverlay.ts
153
+ const EMPTY_MESSAGE$1 = "No loop instances are active in this session.";
154
+ const STOP_SCOPE_MESSAGE = "Stopping a loop does not cancel detached work already launched.";
155
+ const STOP_REASON = "Stopped from the loop list.";
156
+ var LoopListOverlay = class extends _agimon_ai_doompi_ui_doomOverlay.DoomOverlay {
157
+ client;
158
+ done;
159
+ unsubscribe;
160
+ instances;
161
+ selected = 0;
162
+ constructor(tui, theme, client, done) {
163
+ super(tui, theme);
164
+ this.client = client;
165
+ this.done = done;
166
+ this.instances = client.listInstances();
167
+ this.unsubscribe = client.subscribe(() => this.refresh());
168
+ }
169
+ dispose() {
170
+ this.unsubscribe();
171
+ }
172
+ handleInput(data) {
173
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "escape") || (0, _earendil_works_pi_tui.matchesKey)(data, "ctrl+c") || data === "q") {
174
+ this.done(void 0);
175
+ return;
176
+ }
177
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "up") || data === "k") {
178
+ this.move(-1);
179
+ return;
180
+ }
181
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "down") || data === "j") {
182
+ this.move(1);
183
+ return;
184
+ }
185
+ if (data === "x") {
186
+ const instance = this.instances[this.selected];
187
+ if (instance) this.client.stop(instance.instanceId, STOP_REASON);
188
+ }
189
+ }
190
+ getChrome() {
191
+ return {
192
+ title: "LOOPS",
193
+ breadcrumb: "SPC › l / loops › l / list",
194
+ headerRight: `${this.instances.length} active`,
195
+ footer: `${_agimon_ai_doompi_ui_doomOverlay.DOOM_NAVIGATION_KEYS.list} move · x stop · esc close · launched detached work continues`,
196
+ footerHints: [
197
+ [_agimon_ai_doompi_ui_doomOverlay.DOOM_NAVIGATION_KEYS.list, "move"],
198
+ ["x", "stop scheduling"],
199
+ ["esc", "close"]
200
+ ],
201
+ accent: _agimon_ai_doompi_ui_doomOverlay.DOOM_OVERLAY_ACCENT
202
+ };
203
+ }
204
+ renderBody(width) {
205
+ const stopScope = this.theme.fg("dim", (0, _earendil_works_pi_tui.truncateToWidth)(STOP_SCOPE_MESSAGE, width));
206
+ if (!this.instances.length) return [
207
+ this.theme.fg("dim", EMPTY_MESSAGE$1),
208
+ "",
209
+ stopScope
210
+ ];
211
+ return [
212
+ stopScope,
213
+ "",
214
+ ...this.instances.flatMap((instance, index) => {
215
+ const marker = index === this.selected ? this.theme.fg("accent", "▸") : " ";
216
+ const name = instance.label ?? instance.launcherLabel;
217
+ const state = this.theme.fg(instance.state === "running" ? "success" : "warning", instance.state);
218
+ const line = (0, _earendil_works_pi_tui.truncateToWidth)(`${marker} ${name} · ${state}`, width);
219
+ const detail = instance.detail ?? instance.instanceId;
220
+ return [line, ` ${this.theme.fg("dim", (0, _earendil_works_pi_tui.truncateToWidth)(detail, Math.max(0, width - 4)))}`];
221
+ })
222
+ ];
223
+ }
224
+ refresh() {
225
+ this.instances = this.client.listInstances();
226
+ this.selected = Math.min(this.selected, Math.max(0, this.instances.length - 1));
227
+ this.invalidate();
228
+ }
229
+ move(delta) {
230
+ if (!this.instances.length) return;
231
+ this.selected = Math.max(0, Math.min(this.selected + delta, this.instances.length - 1));
232
+ this.invalidate();
233
+ }
234
+ };
235
+ async function openLoopListOverlay(ctx, client) {
236
+ if (ctx.mode !== "tui") {
237
+ const instances = client.listInstances();
238
+ const labels = instances.map((instance) => `${instance.label ?? instance.launcherLabel} (${instance.instanceId})`);
239
+ const selected = await ctx.ui.select("Stop loop scheduling", labels);
240
+ const instance = instances[labels.indexOf(selected ?? "")];
241
+ if (instance) await client.stop(instance.instanceId, STOP_REASON);
242
+ return;
243
+ }
244
+ await ctx.ui.custom((tui, theme, _keybindings, done) => new LoopListOverlay(tui, theme, client, done), _agimon_ai_doompi_ui_doomOverlay.DOOM_FULLSCREEN_UI_OPTIONS);
245
+ }
246
+ //#endregion
247
+ //#region src/tui/startLoopOverlay.ts
248
+ const EMPTY_MESSAGE = "No loop launchers are registered for this session.";
249
+ var StartLoopOverlay = class extends _agimon_ai_doompi_ui_doomOverlay.DoomOverlay {
250
+ launchers;
251
+ done;
252
+ selected = 0;
253
+ constructor(tui, theme, launchers, done) {
254
+ super(tui, theme);
255
+ this.launchers = launchers;
256
+ this.done = done;
257
+ }
258
+ handleInput(data) {
259
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "escape") || (0, _earendil_works_pi_tui.matchesKey)(data, "ctrl+c") || data === "q") {
260
+ this.done(void 0);
261
+ return;
262
+ }
263
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "up") || data === "k") {
264
+ this.move(-1);
265
+ return;
266
+ }
267
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "down") || data === "j") {
268
+ this.move(1);
269
+ return;
270
+ }
271
+ if ((0, _earendil_works_pi_tui.matchesKey)(data, "enter")) this.done(this.launchers[this.selected]?.id);
272
+ }
273
+ getChrome() {
274
+ return {
275
+ title: "START LOOP",
276
+ breadcrumb: "SPC › l / loops › s / start",
277
+ footer: `${_agimon_ai_doompi_ui_doomOverlay.DOOM_NAVIGATION_KEYS.list} move · enter launch · esc close`,
278
+ footerHints: [
279
+ [_agimon_ai_doompi_ui_doomOverlay.DOOM_NAVIGATION_KEYS.list, "move"],
280
+ ["enter", "launch"],
281
+ ["esc", "close"]
282
+ ],
283
+ accent: _agimon_ai_doompi_ui_doomOverlay.DOOM_OVERLAY_ACCENT
284
+ };
285
+ }
286
+ renderBody(width) {
287
+ if (!this.launchers.length) return [this.theme.fg("dim", EMPTY_MESSAGE)];
288
+ return this.launchers.flatMap((launcher, index) => {
289
+ const selected = index === this.selected;
290
+ const marker = selected ? this.theme.fg("accent", "▸") : " ";
291
+ const label = selected ? this.theme.bold(launcher.label) : launcher.label;
292
+ const lines = [`${marker} ${(0, _earendil_works_pi_tui.truncateToWidth)(label, Math.max(0, width - 2))}`];
293
+ if (launcher.description) lines.push(` ${this.theme.fg("dim", (0, _earendil_works_pi_tui.truncateToWidth)(launcher.description, Math.max(0, width - 4)))}`);
294
+ return lines;
295
+ });
296
+ }
297
+ move(delta) {
298
+ if (!this.launchers.length) return;
299
+ this.selected = Math.max(0, Math.min(this.selected + delta, this.launchers.length - 1));
300
+ this.invalidate();
301
+ }
302
+ };
303
+ async function openStartLoopOverlay(ctx, launchers) {
304
+ if (ctx.mode !== "tui") {
305
+ const labels = launchers.map((launcher) => launcher.label);
306
+ const selected = await ctx.ui.select("Start loop", labels);
307
+ return launchers[labels.indexOf(selected ?? "")]?.id;
308
+ }
309
+ return ctx.ui.custom((tui, theme, _keybindings, done) => new StartLoopOverlay(tui, theme, launchers, done), _agimon_ai_doompi_ui_doomOverlay.DOOM_FULLSCREEN_UI_OPTIONS);
310
+ }
311
+ //#endregion
312
+ //#region src/tui/loopRuntime.ts
313
+ const MODE_ACTION_START = "start";
314
+ const MODE_ACTION_STOP = "stop";
315
+ const SESSION_REPLACED_REASON = "Pi session replaced.";
316
+ const SESSION_SHUTDOWN_REASON = "Pi session shut down.";
317
+ function loopModeState(launchers, instances) {
318
+ const active = instances.length > 0;
319
+ return {
320
+ activation: active ? "active" : "inactive",
321
+ condition: instances.some(({ state }) => state === "starting" || state === "stopping") ? "queued" : "ready",
322
+ ...active ? {
323
+ detail: `${instances.length} active`,
324
+ color: ACTIVE_MODE_COLOR
325
+ } : {},
326
+ actions: [...launchers.length > 0 ? [{
327
+ id: MODE_ACTION_START,
328
+ enabled: true
329
+ }] : [{
330
+ id: MODE_ACTION_START,
331
+ enabled: false,
332
+ disabledReason: "No loop launchers are registered."
333
+ }], ...active ? [{
334
+ id: MODE_ACTION_STOP,
335
+ enabled: true
336
+ }] : [{
337
+ id: MODE_ACTION_STOP,
338
+ enabled: false,
339
+ disabledReason: "No loops are active."
340
+ }]]
341
+ };
342
+ }
343
+ /** Install Loop state and external resources into its host-owned Cordis plugin fiber. */
344
+ function createLoopPiRuntime(pi) {
345
+ let active = true;
346
+ let activeSession;
347
+ let mode;
348
+ let disposeLeader;
349
+ const launchesInProgress = /* @__PURE__ */ new WeakSet();
350
+ const currentSession = (context) => {
351
+ const binding = activeSession;
352
+ if (!active || !binding || binding.context.sessionManager !== context.sessionManager || binding.hostSession.sessionId !== context.sessionManager.getSessionId()) return;
353
+ return binding;
354
+ };
355
+ const clearStatuses = (binding) => {
356
+ binding.context.ui?.setStatus(STATUS_KEY, void 0);
357
+ if (binding.context.mode !== "tui") binding.context.ui?.setStatus(require_loopView.LOOP_VIEW_STATUS_KEY, void 0);
358
+ };
359
+ const publishStatus = (binding) => {
360
+ if (!active || activeSession !== binding) return;
361
+ const instances = binding.launchers.listInstances();
362
+ binding.context.ui?.setStatus(STATUS_KEY, instances.length ? `loops: ${instances.length}` : void 0);
363
+ if (binding.context.mode !== "tui") binding.context.ui?.setStatus(require_loopView.LOOP_VIEW_STATUS_KEY, require_loopView.formatLoopStatusView(instances));
364
+ mode?.publish();
365
+ };
366
+ const defaultLauncher = createDefaultLoopLauncher(pi);
367
+ mode = (0, _agimon_ai_doompi_minor_mode.defineMinorMode)({
368
+ descriptor: {
369
+ source: PACKAGE_SOURCE,
370
+ id: MODE_STATUS_ID,
371
+ label: "Loop",
372
+ description: "Session-scoped recurring prompt loops.",
373
+ order: 60,
374
+ actions: [{
375
+ id: MODE_ACTION_START,
376
+ label: "Start",
377
+ description: "Start a loop with a registered launcher.",
378
+ contexts: ["tui", "headless"],
379
+ parameters: [{
380
+ name: "launcherId",
381
+ label: "Launcher",
382
+ kind: "string",
383
+ required: true,
384
+ minLength: 1
385
+ }, {
386
+ name: "instanceId",
387
+ label: "Instance ID",
388
+ kind: "string",
389
+ required: false,
390
+ minLength: 1
391
+ }]
392
+ }, {
393
+ id: MODE_ACTION_STOP,
394
+ label: "Stop",
395
+ description: "Stop one active loop instance.",
396
+ contexts: ["tui", "headless"],
397
+ parameters: [{
398
+ name: "instanceId",
399
+ label: "Instance ID",
400
+ kind: "string",
401
+ required: true,
402
+ minLength: 1
403
+ }, {
404
+ name: "reason",
405
+ label: "Reason",
406
+ kind: "string",
407
+ required: false,
408
+ minLength: 1
409
+ }]
410
+ }]
411
+ },
412
+ state: () => activeSession ? loopModeState(activeSession.launchers.listLaunchers(), activeSession.launchers.listInstances()) : loopModeState([], []),
413
+ async handleAction(_runtime, actionId, argumentsValue, { signal }) {
414
+ signal.throwIfAborted();
415
+ const binding = activeSession ? currentSession(activeSession.context) : void 0;
416
+ if (!binding) throw new Error("Loop launchers are unavailable for the active session.");
417
+ if (actionId === MODE_ACTION_START) {
418
+ const instance = await binding.launchers.launch(argumentsValue.launcherId, argumentsValue.instanceId ? { instanceId: argumentsValue.instanceId } : {});
419
+ if (activeSession !== binding) throw new Error("Loop action became stale.");
420
+ return { message: instance ? `Loop '${instance.instanceId}' started.` : "Loop launch was cancelled." };
421
+ }
422
+ if (actionId === MODE_ACTION_STOP) {
423
+ const stopped = await binding.launchers.stop(argumentsValue.instanceId, argumentsValue.reason ?? "Stopped through minor_mode.");
424
+ if (activeSession !== binding) throw new Error("Loop action became stale.");
425
+ return { message: stopped ? "Loop stopped." : "Loop instance was not active." };
426
+ }
427
+ throw new Error(`Unknown loop mode action: ${actionId}`);
428
+ }
429
+ }).createOwner(void 0);
430
+ return {
431
+ onAgentSettled: defaultLauncher.onAgentSettled,
432
+ services: [(cordis) => {
433
+ cordis.inject([_agimon_ai_doompi_core_uiHub.DOOM_UI_HUB_SERVICE], (uiContext) => {
434
+ const dispose = registerLeaderContribution((0, _agimon_ai_doompi_core_uiHub.requireDoomUiHub)(uiContext));
435
+ disposeLeader = dispose;
436
+ return () => {
437
+ dispose();
438
+ if (disposeLeader === dispose) disposeLeader = void 0;
439
+ };
440
+ });
441
+ cordis.inject([_agimon_ai_doompi_core_cordisHost.DOOM_CORDIS_SESSION_SERVICE], async (sessionContext) => {
442
+ const hostSession = sessionContext.get(_agimon_ai_doompi_core_cordisHost.DOOM_CORDIS_SESSION_SERVICE);
443
+ const launchers = require_loopView.createDoomLoopLaunchersService({
444
+ generation: `${hostSession.generation}:loop-launchers`,
445
+ createInstanceId: () => crypto.randomUUID(),
446
+ timestamp: () => (/* @__PURE__ */ new Date()).toISOString()
447
+ });
448
+ const binding = {
449
+ context: hostSession.context,
450
+ hostSession,
451
+ launchers
452
+ };
453
+ activeSession = binding;
454
+ const provider = cordis.plugin((providerContext) => {
455
+ providerContext.provide(require_loopLaunchers.DOOM_LOOP_LAUNCHERS_SERVICE, launchers);
456
+ });
457
+ let defaultRegistration;
458
+ let unsubscribe;
459
+ try {
460
+ defaultRegistration = defaultLauncher.register(hostSession.context, launchers);
461
+ unsubscribe = launchers.subscribe(() => publishStatus(binding));
462
+ publishStatus(binding);
463
+ } catch (error) {
464
+ if (activeSession === binding) activeSession = void 0;
465
+ await launchers.dispose(SESSION_REPLACED_REASON);
466
+ await provider.dispose();
467
+ throw error;
468
+ }
469
+ return async () => {
470
+ if (activeSession === binding) activeSession = void 0;
471
+ unsubscribe();
472
+ clearStatuses(binding);
473
+ mode?.publish();
474
+ const cleanupErrors = [];
475
+ try {
476
+ await defaultRegistration.dispose(SESSION_REPLACED_REASON);
477
+ } catch (error) {
478
+ cleanupErrors.push(error);
479
+ }
480
+ try {
481
+ await launchers.dispose(SESSION_SHUTDOWN_REASON);
482
+ } catch (error) {
483
+ cleanupErrors.push(error);
484
+ }
485
+ try {
486
+ await provider.dispose();
487
+ } catch (error) {
488
+ cleanupErrors.push(error);
489
+ }
490
+ if (cleanupErrors.length > 0) throw new AggregateError(cleanupErrors, "Loop session cleanup failed.");
491
+ };
492
+ });
493
+ }],
494
+ handlers: {
495
+ async start(ctx, args) {
496
+ const binding = currentSession(ctx);
497
+ if (!binding) return;
498
+ if (launchesInProgress.has(binding)) {
499
+ ctx.ui.notify("A loop setup is already in progress.", NOTIFY_INFO_LEVEL);
500
+ return;
501
+ }
502
+ launchesInProgress.add(binding);
503
+ try {
504
+ const launchers = binding.launchers.listLaunchers();
505
+ if (!launchers.length) {
506
+ ctx.ui.notify("No loop launchers are registered for this session.", NOTIFY_INFO_LEVEL);
507
+ return;
508
+ }
509
+ const argument = args.trim();
510
+ let launcherId;
511
+ if (argument) {
512
+ if (argument.split(/\s+/u).length !== 1) {
513
+ ctx.ui.notify("Usage: /loop [launcherId]", "error");
514
+ return;
515
+ }
516
+ if (!launchers.some((launcher) => launcher.id === argument)) {
517
+ ctx.ui.notify(`Unknown loop launcher: ${argument}`, "error");
518
+ return;
519
+ }
520
+ launcherId = argument;
521
+ } else {
522
+ launcherId = await openStartLoopOverlay(ctx, launchers);
523
+ if (activeSession !== binding || !launcherId) return;
524
+ }
525
+ const instance = await binding.launchers.launch(launcherId);
526
+ if (activeSession !== binding) return;
527
+ if (instance) ctx.ui.notify(`${instance.label ?? instance.launcherLabel} started.`, NOTIFY_INFO_LEVEL);
528
+ } catch (error) {
529
+ if (activeSession !== binding) return;
530
+ ctx.ui.notify(`Loop could not start: ${error instanceof Error ? error.message : String(error)}`, "error");
531
+ } finally {
532
+ launchesInProgress.delete(binding);
533
+ }
534
+ },
535
+ async list(ctx) {
536
+ const binding = currentSession(ctx);
537
+ if (!binding) return;
538
+ await openLoopListOverlay(ctx, binding.launchers);
539
+ }
540
+ },
541
+ minorModes: [mode],
542
+ onDispose() {
543
+ active = false;
544
+ const binding = activeSession;
545
+ activeSession = void 0;
546
+ if (binding) clearStatuses(binding);
547
+ mode?.publish();
548
+ disposeLeader?.();
549
+ disposeLeader = void 0;
550
+ }
551
+ };
552
+ }
553
+ //#endregion
554
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/runtime.cli.ts
555
+ var runtime_cli_default = (({ pi }) => {
556
+ const runtime = createLoopPiRuntime(pi);
557
+ return {
558
+ services: [...runtime.services ?? [], (0, _agimon_ai_doompi_minor_mode.piMinorModes)(runtime.minorModes)],
559
+ events: { agent_settled: runtime.onAgentSettled },
560
+ commands: createLoopCommands(runtime.handlers),
561
+ onDispose: () => runtime.onDispose(),
562
+ resources: [{
563
+ source: PACKAGE_SOURCE,
564
+ moduleUrl: require("url").pathToFileURL(__filename).href,
565
+ skills: [{
566
+ name: "doompi-use-loop",
567
+ description: "Use Doom Pi Loop to start, inspect, and stop session-scoped recurring prompts safely."
568
+ }]
569
+ }]
570
+ };
571
+ });
572
+ //#endregion
573
+ //#region src/extensions/workspaces/sessions/(backend)/root.cli.ts
574
+ var root_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoot)((context) => {
575
+ const value = runtime_cli_default(context);
576
+ return {
577
+ value,
578
+ services: value.services,
579
+ onDispose: value.onDispose
580
+ };
581
+ });
582
+ //#endregion
583
+ //#region src/extensions/workspaces/sessions/(backend)/command/loop.cli.ts
584
+ var loop_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliCommand)((context) => context.root.commands[0]);
585
+ //#endregion
586
+ //#region src/extensions/workspaces/sessions/(backend)/command/loops.cli.ts
587
+ var loops_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliCommand)((context) => context.root.commands[1]);
588
+ //#endregion
589
+ //#region src/extensions/workspaces/sessions/(backend)/hook/agent-settled.cli.ts
590
+ var agent_settled_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineCliHook)((context) => context.root.events["agent_settled"]);
591
+ //#endregion
592
+ //#region src/extensions/workspaces/sessions/(backend)/resource/doompi-use-loop.cli.ts
593
+ var doompi_use_loop_cli_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)((context) => context.root.resources[0]);
594
+ //#endregion
12
595
  //#region generated/pi.ts
13
596
  const at = (value, context) => typeof value === "function" ? value(context) : value;
14
- const extension = (0, _agimon_ai_doompi_core_pi_extension.definePiExtension)("@agimon-ai/doompi-loop", async (context) => {
15
- const scopeSession = await require_root_cli.default(context);
597
+ const extension = (0, _agimon_ai_doompi_core_piExtension.definePiExtension)("@agimon-ai/doompi-loop", async (context) => {
598
+ const scopeSession = await root_cli_default(context);
16
599
  const contextSession = {
17
600
  ...context,
18
601
  root: scopeSession.value
19
602
  };
20
603
  return {
21
- ...(0, _agimon_ai_doompi_core_extension_file.composeRootHooks)(scopeSession),
604
+ ...(0, _agimon_ai_doompi_core_extensionFile.composeRootHooks)(scopeSession),
22
605
  get commands() {
23
- return [at(require_loop_cli.default, contextSession), at(require_loops_cli.default, contextSession)];
606
+ return [at(loop_cli_default, contextSession), at(loops_cli_default, contextSession)];
24
607
  },
25
- events: { agent_settled: at(require_agent_settled_cli.default, contextSession) },
608
+ events: { agent_settled: at(agent_settled_cli_default, contextSession) },
26
609
  get resources() {
27
- return [at(require_doompi_use_loop_cli.default, contextSession)];
610
+ return [at(doompi_use_loop_cli_default, contextSession)];
28
611
  },
29
612
  services: [...scopeSession.services ?? []]
30
613
  };