@grackle-ai/core 0.96.1 → 0.96.3

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 (130) hide show
  1. package/dist/event-processor.js +1 -1
  2. package/dist/event-processor.js.map +1 -1
  3. package/dist/{grpc-shared.d.ts → grpc-shared-utils.d.ts} +6 -10
  4. package/dist/grpc-shared-utils.d.ts.map +1 -0
  5. package/dist/grpc-shared-utils.js +57 -0
  6. package/dist/grpc-shared-utils.js.map +1 -0
  7. package/dist/index.d.ts +33 -27
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +42 -31
  10. package/dist/index.js.map +1 -1
  11. package/dist/lifecycle-streams.d.ts +27 -0
  12. package/dist/lifecycle-streams.d.ts.map +1 -0
  13. package/dist/lifecycle-streams.js +46 -0
  14. package/dist/lifecycle-streams.js.map +1 -0
  15. package/dist/reanimate-agent.js +1 -1
  16. package/dist/reanimate-agent.js.map +1 -1
  17. package/dist/task-session.js +1 -1
  18. package/dist/task-session.js.map +1 -1
  19. package/package.json +8 -8
  20. package/dist/codespace-handlers.d.ts +0 -6
  21. package/dist/codespace-handlers.d.ts.map +0 -1
  22. package/dist/codespace-handlers.js +0 -66
  23. package/dist/codespace-handlers.js.map +0 -1
  24. package/dist/cron-phase.d.ts +0 -46
  25. package/dist/cron-phase.d.ts.map +0 -1
  26. package/dist/cron-phase.js +0 -88
  27. package/dist/cron-phase.js.map +0 -1
  28. package/dist/dispatch-phase.d.ts +0 -46
  29. package/dist/dispatch-phase.d.ts.map +0 -1
  30. package/dist/dispatch-phase.js +0 -99
  31. package/dist/dispatch-phase.js.map +0 -1
  32. package/dist/environment-handlers.d.ts +0 -16
  33. package/dist/environment-handlers.d.ts.map +0 -1
  34. package/dist/environment-handlers.js +0 -255
  35. package/dist/environment-handlers.js.map +0 -1
  36. package/dist/environment-reconciliation.d.ts +0 -35
  37. package/dist/environment-reconciliation.d.ts.map +0 -1
  38. package/dist/environment-reconciliation.js +0 -74
  39. package/dist/environment-reconciliation.js.map +0 -1
  40. package/dist/escalation-handlers.d.ts +0 -8
  41. package/dist/escalation-handlers.d.ts.map +0 -1
  42. package/dist/escalation-handlers.js +0 -60
  43. package/dist/escalation-handlers.js.map +0 -1
  44. package/dist/finding-handlers.d.ts +0 -8
  45. package/dist/finding-handlers.d.ts.map +0 -1
  46. package/dist/finding-handlers.js +0 -38
  47. package/dist/finding-handlers.js.map +0 -1
  48. package/dist/grpc-proto-converters.d.ts +0 -31
  49. package/dist/grpc-proto-converters.d.ts.map +0 -1
  50. package/dist/grpc-proto-converters.js +0 -222
  51. package/dist/grpc-proto-converters.js.map +0 -1
  52. package/dist/grpc-service.d.ts +0 -14
  53. package/dist/grpc-service.d.ts.map +0 -1
  54. package/dist/grpc-service.js +0 -46
  55. package/dist/grpc-service.js.map +0 -1
  56. package/dist/grpc-shared.d.ts.map +0 -1
  57. package/dist/grpc-shared.js +0 -110
  58. package/dist/grpc-shared.js.map +0 -1
  59. package/dist/knowledge-handlers.d.ts +0 -12
  60. package/dist/knowledge-handlers.d.ts.map +0 -1
  61. package/dist/knowledge-handlers.js +0 -149
  62. package/dist/knowledge-handlers.js.map +0 -1
  63. package/dist/lifecycle-cleanup.d.ts +0 -13
  64. package/dist/lifecycle-cleanup.d.ts.map +0 -1
  65. package/dist/lifecycle-cleanup.js +0 -35
  66. package/dist/lifecycle-cleanup.js.map +0 -1
  67. package/dist/lifecycle.d.ts +0 -44
  68. package/dist/lifecycle.d.ts.map +0 -1
  69. package/dist/lifecycle.js +0 -169
  70. package/dist/lifecycle.js.map +0 -1
  71. package/dist/orphan-phase.d.ts +0 -27
  72. package/dist/orphan-phase.d.ts.map +0 -1
  73. package/dist/orphan-phase.js +0 -69
  74. package/dist/orphan-phase.js.map +0 -1
  75. package/dist/persona-handlers.d.ts +0 -12
  76. package/dist/persona-handlers.d.ts.map +0 -1
  77. package/dist/persona-handlers.js +0 -156
  78. package/dist/persona-handlers.js.map +0 -1
  79. package/dist/root-task-boot.d.ts +0 -67
  80. package/dist/root-task-boot.d.ts.map +0 -1
  81. package/dist/root-task-boot.js +0 -234
  82. package/dist/root-task-boot.js.map +0 -1
  83. package/dist/schedule-expression.d.ts +0 -43
  84. package/dist/schedule-expression.d.ts.map +0 -1
  85. package/dist/schedule-expression.js +0 -105
  86. package/dist/schedule-expression.js.map +0 -1
  87. package/dist/schedule-handlers.d.ts +0 -12
  88. package/dist/schedule-handlers.d.ts.map +0 -1
  89. package/dist/schedule-handlers.js +0 -122
  90. package/dist/schedule-handlers.js.map +0 -1
  91. package/dist/session-handlers.d.ts +0 -40
  92. package/dist/session-handlers.d.ts.map +0 -1
  93. package/dist/session-handlers.js +0 -610
  94. package/dist/session-handlers.js.map +0 -1
  95. package/dist/settings-handlers.d.ts +0 -10
  96. package/dist/settings-handlers.d.ts.map +0 -1
  97. package/dist/settings-handlers.js +0 -80
  98. package/dist/settings-handlers.js.map +0 -1
  99. package/dist/signals/escalation-auto.d.ts +0 -20
  100. package/dist/signals/escalation-auto.d.ts.map +0 -1
  101. package/dist/signals/escalation-auto.js +0 -126
  102. package/dist/signals/escalation-auto.js.map +0 -1
  103. package/dist/signals/orphan-reparent.d.ts +0 -31
  104. package/dist/signals/orphan-reparent.d.ts.map +0 -1
  105. package/dist/signals/orphan-reparent.js +0 -175
  106. package/dist/signals/orphan-reparent.js.map +0 -1
  107. package/dist/signals/sigchld.d.ts +0 -12
  108. package/dist/signals/sigchld.d.ts.map +0 -1
  109. package/dist/signals/sigchld.js +0 -177
  110. package/dist/signals/sigchld.js.map +0 -1
  111. package/dist/task-handlers.d.ts +0 -22
  112. package/dist/task-handlers.d.ts.map +0 -1
  113. package/dist/task-handlers.js +0 -518
  114. package/dist/task-handlers.js.map +0 -1
  115. package/dist/test-utils/integration-setup.d.ts +0 -11
  116. package/dist/test-utils/integration-setup.d.ts.map +0 -1
  117. package/dist/test-utils/integration-setup.js +0 -26
  118. package/dist/test-utils/integration-setup.js.map +0 -1
  119. package/dist/token-handlers.d.ts +0 -12
  120. package/dist/token-handlers.d.ts.map +0 -1
  121. package/dist/token-handlers.js +0 -85
  122. package/dist/token-handlers.js.map +0 -1
  123. package/dist/utils/format-gh-error.d.ts +0 -6
  124. package/dist/utils/format-gh-error.d.ts.map +0 -1
  125. package/dist/utils/format-gh-error.js +0 -30
  126. package/dist/utils/format-gh-error.js.map +0 -1
  127. package/dist/workspace-handlers.d.ts +0 -16
  128. package/dist/workspace-handlers.d.ts.map +0 -1
  129. package/dist/workspace-handlers.js +0 -146
  130. package/dist/workspace-handlers.js.map +0 -1
@@ -1,69 +0,0 @@
1
- /**
2
- * Orphan reconciliation phase — periodic safety net for orphaned tasks.
3
- *
4
- * Sweeps all tasks for children whose parent is in a terminal state but
5
- * haven't been reparented by the event-driven handler. This catches edge
6
- * cases like server restarts, race conditions, or missed events.
7
- */
8
- import { ROOT_TASK_ID, TASK_STATUS } from "@grackle-ai/common";
9
- import { logger } from "./logger.js";
10
- /** Terminal task statuses that indicate the parent is done. */
11
- const TERMINAL_TASK_STATUSES = new Set([
12
- TASK_STATUS.COMPLETE,
13
- TASK_STATUS.FAILED,
14
- ]);
15
- /**
16
- * Create the orphan reconciliation phase.
17
- *
18
- * @param deps - Injected dependencies for testability.
19
- * @returns A ReconciliationPhase that can be registered with the ReconciliationManager.
20
- */
21
- export function createOrphanPhase(deps) {
22
- return {
23
- name: "orphan-reparent",
24
- execute: async () => {
25
- const allTasks = deps.listAllTasks();
26
- // Build a lookup map for quick parent resolution
27
- const taskById = new Map(allTasks.map((t) => [t.id, t]));
28
- let reparentCount = 0;
29
- for (const task of allTasks) {
30
- // Skip root tasks and tasks with no parent
31
- if (!task.parentTaskId || task.parentTaskId === ROOT_TASK_ID) {
32
- continue;
33
- }
34
- // Skip terminal tasks (they don't need reparenting)
35
- if (TERMINAL_TASK_STATUSES.has(task.status)) {
36
- continue;
37
- }
38
- // Check if parent is terminal
39
- const parent = taskById.get(task.parentTaskId);
40
- if (!parent || !TERMINAL_TASK_STATUSES.has(parent.status)) {
41
- continue;
42
- }
43
- // This is an orphan! Reparent to grandparent (or root)
44
- const grandparentId = parent.parentTaskId || ROOT_TASK_ID;
45
- try {
46
- deps.reparentTask(task.id, grandparentId);
47
- deps.emit("task.reparented", {
48
- taskId: task.id,
49
- oldParentTaskId: task.parentTaskId,
50
- newParentTaskId: grandparentId,
51
- workspaceId: task.workspaceId || "",
52
- });
53
- deps.emit("task.updated", {
54
- taskId: task.id,
55
- workspaceId: task.workspaceId || "",
56
- });
57
- reparentCount++;
58
- }
59
- catch (err) {
60
- logger.error({ err, taskId: task.id, parentTaskId: task.parentTaskId, grandparentId }, "Orphan phase: failed to reparent task");
61
- }
62
- }
63
- if (reparentCount > 0) {
64
- logger.warn({ reparentCount }, "Orphan phase: reparented %d orphaned task(s) — these should have been caught by the event-driven handler", reparentCount);
65
- }
66
- },
67
- };
68
- }
69
- //# sourceMappingURL=orphan-phase.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"orphan-phase.js","sourceRoot":"","sources":["../src/orphan-phase.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAKrC,+DAA+D;AAC/D,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IAC1D,WAAW,CAAC,QAAQ;IACpB,WAAW,CAAC,MAAM;CACnB,CAAC,CAAC;AAYH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAErC,iDAAiD;YACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAkB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE1E,IAAI,aAAa,GAAG,CAAC,CAAC;YAEtB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,2CAA2C;gBAC3C,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,YAAY,EAAE,CAAC;oBAC7D,SAAS;gBACX,CAAC;gBAED,oDAAoD;gBACpD,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC5C,SAAS;gBACX,CAAC;gBAED,8BAA8B;gBAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC/C,IAAI,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1D,SAAS;gBACX,CAAC;gBAED,uDAAuD;gBACvD,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,IAAI,YAAY,CAAC;gBAE1D,IAAI,CAAC;oBACH,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;oBAC1C,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;wBAC3B,MAAM,EAAE,IAAI,CAAC,EAAE;wBACf,eAAe,EAAE,IAAI,CAAC,YAAY;wBAClC,eAAe,EAAE,aAAa;wBAC9B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;qBACpC,CAAC,CAAC;oBACH,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;wBACxB,MAAM,EAAE,IAAI,CAAC,EAAE;wBACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;qBACpC,CAAC,CAAC;oBACH,aAAa,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CACV,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,EACxE,uCAAuC,CACxC,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CACT,EAAE,aAAa,EAAE,EACjB,0GAA0G,EAC1G,aAAa,CACd,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,12 +0,0 @@
1
- import { grackle } from "@grackle-ai/common";
2
- /** List all personas. */
3
- export declare function listPersonas(): Promise<grackle.PersonaList>;
4
- /** Create a new persona. */
5
- export declare function createPersona(req: grackle.CreatePersonaRequest): Promise<grackle.Persona>;
6
- /** Get a persona by ID. */
7
- export declare function getPersona(req: grackle.PersonaId): Promise<grackle.Persona>;
8
- /** Update an existing persona. */
9
- export declare function updatePersona(req: grackle.UpdatePersonaRequest): Promise<grackle.Persona>;
10
- /** Delete a persona by ID. */
11
- export declare function deletePersona(req: grackle.PersonaId): Promise<grackle.Empty>;
12
- //# sourceMappingURL=persona-handlers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persona-handlers.d.ts","sourceRoot":"","sources":["../src/persona-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQ7C,yBAAyB;AACzB,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAKjE;AAED,4BAA4B;AAC5B,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAsE/F;AAED,2BAA2B;AAC3B,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAMjF;AAED,kCAAkC;AAClC,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAkG/F;AAED,8BAA8B;AAC9B,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAIlF"}
@@ -1,156 +0,0 @@
1
- import { ConnectError, Code } from "@connectrpc/connect";
2
- import { create } from "@bufbuild/protobuf";
3
- import { grackle } from "@grackle-ai/common";
4
- import { ALL_MCP_TOOL_NAMES } from "@grackle-ai/common";
5
- import { personaStore, settingsStore, envRegistry } from "@grackle-ai/database";
6
- import { v4 as uuid } from "uuid";
7
- import { slugify } from "@grackle-ai/database";
8
- import { emit } from "./event-bus.js";
9
- import { personaRowToProto } from "./grpc-proto-converters.js";
10
- /** List all personas. */
11
- export async function listPersonas() {
12
- const rows = personaStore.listPersonas();
13
- return create(grackle.PersonaListSchema, {
14
- personas: rows.map(personaRowToProto),
15
- });
16
- }
17
- /** Create a new persona. */
18
- export async function createPersona(req) {
19
- if (!req.name) {
20
- throw new ConnectError("Persona name is required", Code.InvalidArgument);
21
- }
22
- const personaType = req.type || "agent";
23
- if (personaType !== "agent" && personaType !== "script") {
24
- throw new ConnectError(`Invalid persona type: "${personaType}". Must be "agent" or "script".`, Code.InvalidArgument);
25
- }
26
- if (personaType === "script") {
27
- if (!req.script) {
28
- throw new ConnectError("Script content is required for script personas", Code.InvalidArgument);
29
- }
30
- }
31
- else {
32
- if (!req.systemPrompt) {
33
- throw new ConnectError("Persona system_prompt is required", Code.InvalidArgument);
34
- }
35
- }
36
- // Enforce unique ID and unique name
37
- let id = slugify(req.name) || uuid().slice(0, 8);
38
- if (personaStore.getPersona(id)) {
39
- id = `${id}-${uuid().slice(0, 4)}`;
40
- }
41
- if (personaStore.getPersonaByName(req.name)) {
42
- throw new ConnectError(`Persona with name "${req.name}" already exists`, Code.AlreadyExists);
43
- }
44
- const toolConfigJson = JSON.stringify({
45
- allowedTools: [...(req.toolConfig?.allowedTools || [])],
46
- disallowedTools: [...(req.toolConfig?.disallowedTools || [])],
47
- });
48
- const mcpServersJson = JSON.stringify(req.mcpServers.map((s) => ({
49
- name: s.name,
50
- command: s.command,
51
- args: [...s.args],
52
- tools: [...s.tools],
53
- })));
54
- // Validate allowed MCP tools against the known tool registry
55
- const allowedMcpTools = Array.isArray(req.allowedMcpTools) ? [...req.allowedMcpTools] : [];
56
- if (allowedMcpTools.length > 0) {
57
- const invalid = allowedMcpTools.filter((t) => !ALL_MCP_TOOL_NAMES.has(t));
58
- if (invalid.length > 0) {
59
- throw new ConnectError(`Invalid MCP tool name(s): ${invalid.join(", ")}`, Code.InvalidArgument);
60
- }
61
- }
62
- const allowedMcpToolsJson = JSON.stringify(allowedMcpTools);
63
- personaStore.createPersona(id, req.name, req.description, req.systemPrompt, toolConfigJson, req.runtime, req.model, req.maxTurns, mcpServersJson, personaType, req.script, allowedMcpToolsJson);
64
- emit("persona.created", { personaId: id });
65
- const row = personaStore.getPersona(id);
66
- return personaRowToProto(row);
67
- }
68
- /** Get a persona by ID. */
69
- export async function getPersona(req) {
70
- const row = personaStore.getPersona(req.id);
71
- if (!row) {
72
- throw new ConnectError(`Persona not found: ${req.id}`, Code.NotFound);
73
- }
74
- return personaRowToProto(row);
75
- }
76
- /** Update an existing persona. */
77
- export async function updatePersona(req) {
78
- const existing = personaStore.getPersona(req.id);
79
- if (!existing) {
80
- throw new ConnectError(`Persona not found: ${req.id}`, Code.NotFound);
81
- }
82
- // Only update toolConfig/mcpServers if the request provides non-empty values;
83
- // otherwise keep the existing stored value.
84
- const hasNewToolConfig = !!req.toolConfig &&
85
- (req.toolConfig.allowedTools.length > 0 ||
86
- req.toolConfig.disallowedTools.length > 0);
87
- const toolConfigJson = hasNewToolConfig
88
- ? JSON.stringify({
89
- allowedTools: [...(req.toolConfig?.allowedTools || [])],
90
- disallowedTools: [...(req.toolConfig?.disallowedTools || [])],
91
- })
92
- : existing.toolConfig;
93
- const hasNewMcpServers = Array.isArray(req.mcpServers) && req.mcpServers.length > 0;
94
- const mcpServersJson = hasNewMcpServers
95
- ? JSON.stringify(req.mcpServers.map((s) => ({
96
- name: s.name,
97
- command: s.command,
98
- args: [...s.args],
99
- tools: [...s.tools],
100
- })))
101
- : existing.mcpServers;
102
- // Treat empty string / 0 as "not set" and keep existing value
103
- const name = req.name || existing.name;
104
- if (name !== existing.name && personaStore.getPersonaByName(name)) {
105
- throw new ConnectError(`Persona with name "${name}" already exists`, Code.AlreadyExists);
106
- }
107
- const description = req.description || existing.description;
108
- const systemPrompt = req.systemPrompt || existing.systemPrompt;
109
- const runtime = req.runtime || existing.runtime;
110
- const model = req.model || existing.model;
111
- const maxTurns = req.maxTurns === 0 ? existing.maxTurns : req.maxTurns;
112
- // Empty string means "keep existing", non-empty means "set to this value"
113
- const updatedType = req.type || existing.type;
114
- const updatedScript = req.script || existing.script;
115
- // AllowedMcpTools is a wrapper message with proto3 presence tracking:
116
- // - absent (undefined) → preserve existing value
117
- // - present with empty tools → clear to default (revert to full set)
118
- // - present with tools → validate and replace
119
- let allowedMcpToolsJson;
120
- if (req.allowedMcpTools) {
121
- const tools = [...req.allowedMcpTools.tools];
122
- if (tools.length > 0) {
123
- const invalid = tools.filter((t) => !ALL_MCP_TOOL_NAMES.has(t));
124
- if (invalid.length > 0) {
125
- throw new ConnectError(`Invalid MCP tool name(s): ${invalid.join(", ")}`, Code.InvalidArgument);
126
- }
127
- }
128
- allowedMcpToolsJson = JSON.stringify(tools);
129
- }
130
- else {
131
- allowedMcpToolsJson = existing.allowedMcpTools;
132
- }
133
- personaStore.updatePersona(req.id, name, description, systemPrompt, toolConfigJson, runtime, model, maxTurns, mcpServersJson, updatedType, updatedScript, allowedMcpToolsJson);
134
- // Sync the local environment's defaultRuntime when the app-level default
135
- // persona's runtime changes, so bootstrap pre-installs the correct packages.
136
- if (runtime !== existing.runtime) {
137
- const appDefault = settingsStore.getSetting("default_persona_id") || "";
138
- if (appDefault === req.id) {
139
- const localEnv = envRegistry.getEnvironment("local");
140
- if (localEnv) {
141
- envRegistry.updateDefaultRuntime("local", runtime);
142
- emit("environment.changed", {});
143
- }
144
- }
145
- }
146
- emit("persona.updated", { personaId: req.id });
147
- const row = personaStore.getPersona(req.id);
148
- return personaRowToProto(row);
149
- }
150
- /** Delete a persona by ID. */
151
- export async function deletePersona(req) {
152
- personaStore.deletePersona(req.id);
153
- emit("persona.deleted", { personaId: req.id });
154
- return create(grackle.EmptySchema, {});
155
- }
156
- //# sourceMappingURL=persona-handlers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persona-handlers.js","sourceRoot":"","sources":["../src/persona-handlers.ts"],"names":[],"mappings":"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"}
@@ -1,67 +0,0 @@
1
- /**
2
- * Root task boot with reanimate-first strategy and exponential backoff.
3
- *
4
- * Extracted from the inline closure in `server/src/index.ts` so it can be
5
- * unit tested. Follows the dependency-injection pattern established by
6
- * `cron-phase.ts`.
7
- *
8
- * On each invocation (triggered by `environment.changed` events):
9
- * 1. Checks if the root task is already running — if so, tracks stability.
10
- * 2. If not running, attempts to reanimate the most recent session (preserving
11
- * conversation history) before falling back to a fresh spawn.
12
- * 3. Applies exponential backoff after consecutive failures to prevent
13
- * crash-loop resource waste.
14
- *
15
- * @module
16
- */
17
- import type { TaskRow, SessionRow, EnvironmentRow } from "@grackle-ai/database";
18
- import type { TaskStatusResult } from "./compute-task-status.js";
19
- import type { Disposable, PluginContext } from "./subscriber-types.js";
20
- /** Dependencies injected into the root task boot module for testability. */
21
- export interface RootTaskBootDeps {
22
- /** Look up a task by ID. */
23
- getTask: (id: string) => TaskRow | undefined;
24
- /** List all sessions for a task. */
25
- listSessionsForTask: (taskId: string) => Pick<SessionRow, "id" | "status" | "startedAt">[];
26
- /** Get the most recent session for a task (by startedAt DESC). */
27
- getLatestSessionForTask: (taskId: string) => SessionRow | undefined;
28
- /** Compute effective task status from stored status + session history. */
29
- computeTaskStatus: (storedStatus: string, sessions: Pick<SessionRow, "id" | "status" | "startedAt">[]) => TaskStatusResult;
30
- /** Find the first connected environment, preferring local. */
31
- findFirstConnectedEnvironment: () => EnvironmentRow | undefined;
32
- /** Start a new agent session for a task. Returns error string on failure, undefined on success. */
33
- startTaskSession: (task: TaskRow, options?: {
34
- environmentId?: string;
35
- notes?: string;
36
- }) => Promise<string | undefined>;
37
- /** Reanimate a terminal session by resuming it on PowerLine. Throws on failure. */
38
- reanimateAgent: (sessionId: string) => SessionRow;
39
- /** Whether onboarding is complete. Boot is deferred until the user has chosen a runtime (#1031). */
40
- isOnboarded?: () => boolean;
41
- }
42
- /**
43
- * Create the root task boot handler.
44
- *
45
- * Returns a callable async function that can be wired to `environment.changed`
46
- * event subscriptions. Each call checks whether the root task needs starting
47
- * and applies reanimate-first + exponential backoff logic.
48
- *
49
- * Each call creates independent backoff state (not shared across calls).
50
- *
51
- * @param deps - Injected dependencies for testability.
52
- * @returns An async function to call on each `environment.changed` event.
53
- */
54
- export declare function createRootTaskBoot(deps: RootTaskBootDeps): () => Promise<void>;
55
- /**
56
- * Create the root task boot subscriber.
57
- *
58
- * Creates independent backoff state (not shared with other factory calls)
59
- * and subscribes to `environment.changed` and `setting.changed` events.
60
- * Returns a Disposable that unsubscribes the handler.
61
- *
62
- * @param ctx - Plugin context providing event-bus access.
63
- * @param deps - Injected dependencies for testability.
64
- * @returns A Disposable that unsubscribes the handler.
65
- */
66
- export declare function createRootTaskBootSubscriber(ctx: PluginContext, deps: RootTaskBootDeps): Disposable;
67
- //# sourceMappingURL=root-task-boot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"root-task-boot.d.ts","sourceRoot":"","sources":["../src/root-task-boot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAqBvE,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAAC;IAC7C,oCAAoC;IACpC,mBAAmB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,QAAQ,GAAG,WAAW,CAAC,EAAE,CAAC;IAC3F,kEAAkE;IAClE,uBAAuB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;IACpE,0EAA0E;IAC1E,iBAAiB,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,QAAQ,GAAG,WAAW,CAAC,EAAE,KAAK,gBAAgB,CAAC;IAC3H,8DAA8D;IAC9D,6BAA6B,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IAChE,mGAAmG;IACnG,gBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvH,mFAAmF;IACnF,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,UAAU,CAAC;IAClD,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AA4BD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAE9E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,UAAU,CAuBnG"}
@@ -1,234 +0,0 @@
1
- /**
2
- * Root task boot with reanimate-first strategy and exponential backoff.
3
- *
4
- * Extracted from the inline closure in `server/src/index.ts` so it can be
5
- * unit tested. Follows the dependency-injection pattern established by
6
- * `cron-phase.ts`.
7
- *
8
- * On each invocation (triggered by `environment.changed` events):
9
- * 1. Checks if the root task is already running — if so, tracks stability.
10
- * 2. If not running, attempts to reanimate the most recent session (preserving
11
- * conversation history) before falling back to a fresh spawn.
12
- * 3. Applies exponential backoff after consecutive failures to prevent
13
- * crash-loop resource waste.
14
- *
15
- * @module
16
- */
17
- import { ROOT_TASK_ID, ROOT_TASK_INITIAL_PROMPT, TASK_STATUS } from "@grackle-ai/common";
18
- import { logger } from "./logger.js";
19
- // ─── Constants ──────────────────────────────────────────────
20
- /** Initial delay before the first retry after a failed boot (milliseconds). */
21
- const BOOT_INITIAL_DELAY_MS = 1_000;
22
- /** Multiplier for exponential backoff between boot retries. */
23
- const BOOT_BACKOFF_MULTIPLIER = 2;
24
- /** Maximum delay between boot retries (milliseconds). */
25
- const BOOT_MAX_DELAY_MS = 60_000;
26
- /** Maximum consecutive boot failures before giving up until server restart. */
27
- const BOOT_MAX_FAILURES = 10;
28
- /** Minimum time a session must survive (ms) to be considered stable and reset backoff. */
29
- const BOOT_STABLE_THRESHOLD_MS = 30_000;
30
- // ─── State ──────────────────────────────────────────────────
31
- /** Create a fresh backoff state. */
32
- function createInitialState() {
33
- return {
34
- failures: 0,
35
- lastFailureAt: 0,
36
- inProgress: false,
37
- lastSessionStartedAt: 0,
38
- };
39
- }
40
- // ─── Public API ─────────────────────────────────────────────
41
- /**
42
- * Create the root task boot handler.
43
- *
44
- * Returns a callable async function that can be wired to `environment.changed`
45
- * event subscriptions. Each call checks whether the root task needs starting
46
- * and applies reanimate-first + exponential backoff logic.
47
- *
48
- * Each call creates independent backoff state (not shared across calls).
49
- *
50
- * @param deps - Injected dependencies for testability.
51
- * @returns An async function to call on each `environment.changed` event.
52
- */
53
- export function createRootTaskBoot(deps) {
54
- return createRootTaskBootHandler(deps, createInitialState());
55
- }
56
- /**
57
- * Create the root task boot subscriber.
58
- *
59
- * Creates independent backoff state (not shared with other factory calls)
60
- * and subscribes to `environment.changed` and `setting.changed` events.
61
- * Returns a Disposable that unsubscribes the handler.
62
- *
63
- * @param ctx - Plugin context providing event-bus access.
64
- * @param deps - Injected dependencies for testability.
65
- * @returns A Disposable that unsubscribes the handler.
66
- */
67
- export function createRootTaskBootSubscriber(ctx, deps) {
68
- const bootState = createInitialState();
69
- const tryBoot = createRootTaskBootHandler(deps, bootState);
70
- const unsubscribe = ctx.subscribe((event) => {
71
- if (event.type === "environment.changed") {
72
- tryBoot().catch(() => { });
73
- }
74
- // Also try when onboarding completes — the environment is already
75
- // connected but boot was deferred until the user chose a runtime.
76
- if (event.type === "setting.changed") {
77
- const payload = event.payload;
78
- if (payload.key === "onboarding_completed" && payload.value === "true") {
79
- tryBoot().catch(() => { });
80
- }
81
- }
82
- });
83
- return {
84
- dispose() {
85
- unsubscribe();
86
- },
87
- };
88
- }
89
- // ─── Internal ───────────────────────────────────────────────
90
- /**
91
- * Create an async boot handler that uses the given backoff state.
92
- * Shared implementation for both {@link createRootTaskBoot} and
93
- * {@link createRootTaskBootSubscriber}.
94
- */
95
- function createRootTaskBootHandler(deps, s) {
96
- return async () => {
97
- // Guard: prevent concurrent boot attempts
98
- if (s.inProgress) {
99
- return;
100
- }
101
- s.inProgress = true;
102
- try {
103
- await attemptBoot(deps, s);
104
- }
105
- catch (err) {
106
- recordFailure(s);
107
- logger.warn({ err }, "Root task boot failed with unexpected exception");
108
- }
109
- finally {
110
- s.inProgress = false; // eslint-disable-line require-atomic-updates -- single-threaded, flag guards re-entry
111
- }
112
- };
113
- }
114
- /** Core boot logic — separated from the guard/error wrapper for clarity. */
115
- async function attemptBoot(deps, s) {
116
- // 0. Don't auto-start before onboarding — the user hasn't chosen their
117
- // runtime yet, so the root task would launch with the default "claude-code".
118
- if (deps.isOnboarded && !deps.isOnboarded()) {
119
- return;
120
- }
121
- // 1. Look up root task
122
- const rootTask = deps.getTask(ROOT_TASK_ID);
123
- if (!rootTask) {
124
- return;
125
- }
126
- // 2. Check if already working
127
- const sessions = deps.listSessionsForTask(ROOT_TASK_ID);
128
- const { status } = deps.computeTaskStatus(rootTask.status, sessions);
129
- if (status === TASK_STATUS.WORKING) {
130
- checkStabilityReset(s);
131
- return;
132
- }
133
- // 2b. Crash-loop detection: if we recently started a session but the task
134
- // is no longer working before the stability threshold, count it as a failure.
135
- // This catches the case where startTaskSession succeeded but the session
136
- // crashed shortly after (the main crash-loop scenario from issue #959).
137
- if (s.lastSessionStartedAt > 0) {
138
- const sinceLastStart = Date.now() - s.lastSessionStartedAt;
139
- if (sinceLastStart < BOOT_STABLE_THRESHOLD_MS) {
140
- // Session crashed before reaching stability — record as failure
141
- if (s.lastFailureAt < s.lastSessionStartedAt) {
142
- // Only record once per start (guard against multiple environment.changed events)
143
- recordFailure(s);
144
- logger.info({ survivedMs: sinceLastStart, failures: s.failures }, "Root task session crashed before stability threshold — recording failure");
145
- }
146
- }
147
- else {
148
- // Session survived past stability threshold but is now stopped — reset backoff
149
- resetBackoff(s, sinceLastStart);
150
- }
151
- s.lastSessionStartedAt = 0;
152
- }
153
- // 3. Find connected environment
154
- const connectedEnv = deps.findFirstConnectedEnvironment();
155
- if (!connectedEnv) {
156
- return;
157
- }
158
- // 4. Check backoff
159
- if (s.failures >= BOOT_MAX_FAILURES) {
160
- // Log only once when the threshold is first reached to avoid spam
161
- if (s.failures === BOOT_MAX_FAILURES) {
162
- logger.error({ failures: s.failures }, "Root task boot exhausted all retries (%d failures) — giving up until server restart", s.failures);
163
- }
164
- return;
165
- }
166
- if (s.failures > 0) {
167
- const delay = Math.min(BOOT_INITIAL_DELAY_MS * Math.pow(BOOT_BACKOFF_MULTIPLIER, s.failures - 1), BOOT_MAX_DELAY_MS);
168
- const elapsed = Date.now() - s.lastFailureAt;
169
- if (elapsed < delay) {
170
- return; // backoff not elapsed yet
171
- }
172
- }
173
- // 5. Reanimate-first: try to resume the latest session
174
- let booted = false;
175
- const latestSession = deps.getLatestSessionForTask(ROOT_TASK_ID);
176
- if (latestSession?.runtimeSessionId) {
177
- try {
178
- deps.reanimateAgent(latestSession.id);
179
- booted = true;
180
- logger.info({ sessionId: latestSession.id, environmentId: latestSession.environmentId }, "Root task reanimated existing session");
181
- }
182
- catch (reanimateErr) {
183
- logger.info({ sessionId: latestSession.id, err: reanimateErr }, "Root task reanimate failed — falling back to fresh spawn");
184
- }
185
- }
186
- // 6. Fresh spawn (fallback)
187
- if (!booted) {
188
- const err = await deps.startTaskSession(rootTask, {
189
- environmentId: connectedEnv.id,
190
- notes: ROOT_TASK_INITIAL_PROMPT,
191
- });
192
- if (err) {
193
- recordFailure(s);
194
- logger.warn({ err }, "Root task auto-start failed");
195
- return;
196
- }
197
- logger.info({ environmentId: connectedEnv.id }, "Root task auto-started (fresh spawn)");
198
- }
199
- // 7. Track session start time for stability detection
200
- s.lastSessionStartedAt = Date.now(); // eslint-disable-line require-atomic-updates -- single-threaded
201
- }
202
- /** Record a boot failure: increment counter and timestamp. */
203
- function recordFailure(s) {
204
- s.failures++;
205
- s.lastFailureAt = Date.now();
206
- }
207
- /**
208
- * If the root task has been WORKING long enough (past the stability threshold),
209
- * reset the backoff counter. Called when we detect the task is already running.
210
- */
211
- function checkStabilityReset(s) {
212
- if (s.failures === 0) {
213
- return;
214
- }
215
- if (s.lastSessionStartedAt > 0) {
216
- const elapsed = Date.now() - s.lastSessionStartedAt;
217
- if (elapsed >= BOOT_STABLE_THRESHOLD_MS) {
218
- resetBackoff(s, elapsed);
219
- }
220
- }
221
- else {
222
- // Task is WORKING but we didn't start it (e.g., session recovery
223
- // reanimated it externally). Begin tracking stability from now so
224
- // backoff can eventually reset — otherwise MAX_FAILURES is permanent.
225
- s.lastSessionStartedAt = Date.now();
226
- }
227
- }
228
- /** Zero out the backoff state after a session has proven stable. */
229
- function resetBackoff(s, survivedMs) {
230
- logger.info({ survivedMs, previousFailures: s.failures }, "Root task session stable — resetting backoff");
231
- s.failures = 0;
232
- s.lastFailureAt = 0;
233
- }
234
- //# sourceMappingURL=root-task-boot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"root-task-boot.js","sourceRoot":"","sources":["../src/root-task-boot.ts"],"names":[],"mappings":"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"}
@@ -1,43 +0,0 @@
1
- /**
2
- * Schedule expression parsing and next-run-time computation.
3
- *
4
- * Supports two formats:
5
- * - **Interval shorthand**: `"<number><unit>"` where unit is s/m/h/d (min 10s)
6
- * - **Cron expressions**: Standard 5-field cron syntax via `cron-parser`
7
- */
8
- /**
9
- * Parse an interval shorthand expression to milliseconds.
10
- *
11
- * @param expr - e.g. "30s", "5m", "1h", "1d"
12
- * @returns Duration in milliseconds
13
- * @throws If the expression is invalid or below the minimum (10s)
14
- */
15
- export declare function parseDuration(expr: string): number;
16
- /**
17
- * Detect whether an expression is interval shorthand (vs. cron).
18
- *
19
- * @param expr - Schedule expression string
20
- * @returns true if the expression matches interval shorthand format
21
- */
22
- export declare function isIntervalExpression(expr: string): boolean;
23
- /**
24
- * Compute the next run time for a schedule expression.
25
- *
26
- * For intervals: if `lastRunAt + interval` is in the future, use that (prevents
27
- * drift). Otherwise use `now + interval` (prevents burst-firing after downtime).
28
- *
29
- * For cron: next occurrence after now.
30
- *
31
- * @param expr - Schedule expression (interval or cron)
32
- * @param lastRunAt - ISO timestamp of the last fire (undefined for first fire)
33
- * @returns ISO timestamp of the next fire
34
- */
35
- export declare function computeNextRunAt(expr: string, lastRunAt?: string): string;
36
- /**
37
- * Validate a schedule expression. Throws if invalid.
38
- *
39
- * @param expr - Schedule expression to validate
40
- * @throws If the expression is neither valid interval shorthand nor valid cron
41
- */
42
- export declare function validateExpression(expr: string): void;
43
- //# sourceMappingURL=schedule-expression.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schedule-expression.d.ts","sourceRoot":"","sources":["../src/schedule-expression.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBlD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBrD"}