@grackle-ai/plugin-core 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 (122) hide show
  1. package/dist/codespace-handlers.d.ts +6 -0
  2. package/dist/codespace-handlers.d.ts.map +1 -0
  3. package/dist/codespace-handlers.js +66 -0
  4. package/dist/codespace-handlers.js.map +1 -0
  5. package/dist/cron-phase.d.ts +46 -0
  6. package/dist/cron-phase.d.ts.map +1 -0
  7. package/dist/cron-phase.js +88 -0
  8. package/dist/cron-phase.js.map +1 -0
  9. package/dist/dispatch-phase.d.ts +46 -0
  10. package/dist/dispatch-phase.d.ts.map +1 -0
  11. package/dist/dispatch-phase.js +99 -0
  12. package/dist/dispatch-phase.js.map +1 -0
  13. package/dist/environment-handlers.d.ts +16 -0
  14. package/dist/environment-handlers.d.ts.map +1 -0
  15. package/dist/environment-handlers.js +255 -0
  16. package/dist/environment-handlers.js.map +1 -0
  17. package/dist/environment-reconciliation.d.ts +35 -0
  18. package/dist/environment-reconciliation.d.ts.map +1 -0
  19. package/dist/environment-reconciliation.js +74 -0
  20. package/dist/environment-reconciliation.js.map +1 -0
  21. package/dist/escalation-handlers.d.ts +8 -0
  22. package/dist/escalation-handlers.d.ts.map +1 -0
  23. package/dist/escalation-handlers.js +60 -0
  24. package/dist/escalation-handlers.js.map +1 -0
  25. package/dist/finding-handlers.d.ts +8 -0
  26. package/dist/finding-handlers.d.ts.map +1 -0
  27. package/dist/finding-handlers.js +38 -0
  28. package/dist/finding-handlers.js.map +1 -0
  29. package/dist/grpc-proto-converters.d.ts +31 -0
  30. package/dist/grpc-proto-converters.d.ts.map +1 -0
  31. package/dist/grpc-proto-converters.js +222 -0
  32. package/dist/grpc-proto-converters.js.map +1 -0
  33. package/dist/grpc-service.d.ts +21 -0
  34. package/dist/grpc-service.d.ts.map +1 -0
  35. package/dist/grpc-service.js +50 -0
  36. package/dist/grpc-service.js.map +1 -0
  37. package/dist/grpc-shared.d.ts +22 -0
  38. package/dist/grpc-shared.d.ts.map +1 -0
  39. package/dist/grpc-shared.js +68 -0
  40. package/dist/grpc-shared.js.map +1 -0
  41. package/dist/index.d.ts +20 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +20 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/knowledge-handlers.d.ts +12 -0
  46. package/dist/knowledge-handlers.d.ts.map +1 -0
  47. package/dist/knowledge-handlers.js +149 -0
  48. package/dist/knowledge-handlers.js.map +1 -0
  49. package/dist/lifecycle-cleanup.d.ts +13 -0
  50. package/dist/lifecycle-cleanup.d.ts.map +1 -0
  51. package/dist/lifecycle-cleanup.js +35 -0
  52. package/dist/lifecycle-cleanup.js.map +1 -0
  53. package/dist/lifecycle.d.ts +28 -0
  54. package/dist/lifecycle.d.ts.map +1 -0
  55. package/dist/lifecycle.js +132 -0
  56. package/dist/lifecycle.js.map +1 -0
  57. package/dist/orphan-phase.d.ts +27 -0
  58. package/dist/orphan-phase.d.ts.map +1 -0
  59. package/dist/orphan-phase.js +69 -0
  60. package/dist/orphan-phase.js.map +1 -0
  61. package/dist/persona-handlers.d.ts +12 -0
  62. package/dist/persona-handlers.d.ts.map +1 -0
  63. package/dist/persona-handlers.js +156 -0
  64. package/dist/persona-handlers.js.map +1 -0
  65. package/dist/root-task-boot.d.ts +67 -0
  66. package/dist/root-task-boot.d.ts.map +1 -0
  67. package/dist/root-task-boot.js +234 -0
  68. package/dist/root-task-boot.js.map +1 -0
  69. package/dist/schedule-expression.d.ts +43 -0
  70. package/dist/schedule-expression.d.ts.map +1 -0
  71. package/dist/schedule-expression.js +105 -0
  72. package/dist/schedule-expression.js.map +1 -0
  73. package/dist/schedule-handlers.d.ts +12 -0
  74. package/dist/schedule-handlers.d.ts.map +1 -0
  75. package/dist/schedule-handlers.js +122 -0
  76. package/dist/schedule-handlers.js.map +1 -0
  77. package/dist/session-handlers.d.ts +40 -0
  78. package/dist/session-handlers.d.ts.map +1 -0
  79. package/dist/session-handlers.js +610 -0
  80. package/dist/session-handlers.js.map +1 -0
  81. package/dist/settings-handlers.d.ts +10 -0
  82. package/dist/settings-handlers.d.ts.map +1 -0
  83. package/dist/settings-handlers.js +80 -0
  84. package/dist/settings-handlers.js.map +1 -0
  85. package/dist/signals/escalation-auto.d.ts +20 -0
  86. package/dist/signals/escalation-auto.d.ts.map +1 -0
  87. package/dist/signals/escalation-auto.js +126 -0
  88. package/dist/signals/escalation-auto.js.map +1 -0
  89. package/dist/signals/orphan-reparent.d.ts +31 -0
  90. package/dist/signals/orphan-reparent.d.ts.map +1 -0
  91. package/dist/signals/orphan-reparent.js +175 -0
  92. package/dist/signals/orphan-reparent.js.map +1 -0
  93. package/dist/signals/sigchld.d.ts +12 -0
  94. package/dist/signals/sigchld.d.ts.map +1 -0
  95. package/dist/signals/sigchld.js +177 -0
  96. package/dist/signals/sigchld.js.map +1 -0
  97. package/dist/task-handlers.d.ts +22 -0
  98. package/dist/task-handlers.d.ts.map +1 -0
  99. package/dist/task-handlers.js +517 -0
  100. package/dist/task-handlers.js.map +1 -0
  101. package/dist/test-utils/integration-setup.d.ts +11 -0
  102. package/dist/test-utils/integration-setup.d.ts.map +1 -0
  103. package/dist/test-utils/integration-setup.js +26 -0
  104. package/dist/test-utils/integration-setup.js.map +1 -0
  105. package/dist/test-utils/mock-database.d.ts +152 -0
  106. package/dist/test-utils/mock-database.d.ts.map +1 -0
  107. package/dist/test-utils/mock-database.js +169 -0
  108. package/dist/test-utils/mock-database.js.map +1 -0
  109. package/dist/token-handlers.d.ts +12 -0
  110. package/dist/token-handlers.d.ts.map +1 -0
  111. package/dist/token-handlers.js +85 -0
  112. package/dist/token-handlers.js.map +1 -0
  113. package/dist/tsdoc-metadata.json +11 -0
  114. package/dist/utils/format-gh-error.d.ts +6 -0
  115. package/dist/utils/format-gh-error.d.ts.map +1 -0
  116. package/dist/utils/format-gh-error.js +30 -0
  117. package/dist/utils/format-gh-error.js.map +1 -0
  118. package/dist/workspace-handlers.d.ts +16 -0
  119. package/dist/workspace-handlers.d.ts.map +1 -0
  120. package/dist/workspace-handlers.js +146 -0
  121. package/dist/workspace-handlers.js.map +1 -0
  122. package/package.json +60 -0
@@ -0,0 +1,10 @@
1
+ import { grackle } from "@grackle-ai/common";
2
+ /** Get the value of a setting by key. */
3
+ export declare function getSetting(req: grackle.GetSettingRequest): Promise<grackle.SettingResponse>;
4
+ /** Set the value of a setting. */
5
+ export declare function setSetting(req: grackle.SetSettingRequest): Promise<grackle.SettingResponse>;
6
+ /** Generate a new pairing code for web UI access. */
7
+ export declare function generatePairingCode(): Promise<grackle.PairingCodeResponse>;
8
+ /** Get the current version status (update available, current/latest versions). */
9
+ export declare function getVersionStatus(): Promise<grackle.VersionStatus>;
10
+ //# sourceMappingURL=settings-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-handlers.d.ts","sourceRoot":"","sources":["../src/settings-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQ7C,yCAAyC;AACzC,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CASjG;AAED,kCAAkC;AAClC,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAqCjG;AAED,qDAAqD;AACrD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAiBhF;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAQvE"}
@@ -0,0 +1,80 @@
1
+ import { ConnectError, Code } from "@connectrpc/connect";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import { grackle } from "@grackle-ai/common";
4
+ import { DEFAULT_WEB_PORT } from "@grackle-ai/common";
5
+ import { settingsStore, personaStore, envRegistry, isAllowedSettingKey } from "@grackle-ai/database";
6
+ import { generatePairingCode as authGeneratePairingCode } from "@grackle-ai/auth";
7
+ import { checkVersionStatus } from "@grackle-ai/core";
8
+ import { detectLanIp } from "@grackle-ai/core";
9
+ import { emit } from "@grackle-ai/core";
10
+ /** Get the value of a setting by key. */
11
+ export async function getSetting(req) {
12
+ if (!isAllowedSettingKey(req.key)) {
13
+ throw new ConnectError(`Setting key not allowed: ${req.key}`, Code.InvalidArgument);
14
+ }
15
+ const value = settingsStore.getSetting(req.key);
16
+ return create(grackle.SettingResponseSchema, {
17
+ key: req.key,
18
+ value: value ?? "",
19
+ });
20
+ }
21
+ /** Set the value of a setting. */
22
+ export async function setSetting(req) {
23
+ if (!isAllowedSettingKey(req.key)) {
24
+ throw new ConnectError(`Setting key not allowed: ${req.key}`, Code.InvalidArgument);
25
+ }
26
+ // Validate persona exists and has required fields when setting default_persona_id
27
+ if (req.key === "default_persona_id" && req.value) {
28
+ const persona = personaStore.getPersona(req.value);
29
+ if (!persona) {
30
+ throw new ConnectError(`Persona not found: ${req.value}`, Code.NotFound);
31
+ }
32
+ if (!persona.runtime || !persona.model) {
33
+ throw new ConnectError(`Persona "${persona.name}" must have runtime and model configured`, Code.FailedPrecondition);
34
+ }
35
+ }
36
+ settingsStore.setSetting(req.key, req.value);
37
+ emit("setting.changed", { key: req.key, value: req.value });
38
+ // Sync the local environment's defaultRuntime when the default persona changes,
39
+ // so bootstrap pre-installs the correct runtime packages (fixes #1031).
40
+ if (req.key === "default_persona_id" && req.value) {
41
+ const newDefault = personaStore.getPersona(req.value);
42
+ if (newDefault?.runtime) {
43
+ const localEnv = envRegistry.getEnvironment("local");
44
+ if (localEnv && localEnv.defaultRuntime !== newDefault.runtime) {
45
+ envRegistry.updateDefaultRuntime("local", newDefault.runtime);
46
+ emit("environment.changed", {});
47
+ }
48
+ }
49
+ }
50
+ return create(grackle.SettingResponseSchema, {
51
+ key: req.key,
52
+ value: req.value,
53
+ });
54
+ }
55
+ /** Generate a new pairing code for web UI access. */
56
+ export async function generatePairingCode() {
57
+ const code = authGeneratePairingCode();
58
+ if (!code) {
59
+ throw new ConnectError("Maximum active pairing codes reached. Wait for existing codes to expire.", Code.ResourceExhausted);
60
+ }
61
+ const webPort = parseInt(process.env.GRACKLE_WEB_PORT || String(DEFAULT_WEB_PORT), 10);
62
+ const bindHost = process.env.GRACKLE_HOST || "127.0.0.1";
63
+ const WILDCARD_ADDRESSES = new Set(["0.0.0.0", "::", "0:0:0:0:0:0:0:0"]);
64
+ const pairingHost = WILDCARD_ADDRESSES.has(bindHost)
65
+ ? (detectLanIp() || "localhost")
66
+ : (bindHost === "127.0.0.1" || bindHost === "::1" ? "localhost" : bindHost);
67
+ const url = `http://${pairingHost}:${webPort}/pair?code=${code}`;
68
+ return create(grackle.PairingCodeResponseSchema, { code, url });
69
+ }
70
+ /** Get the current version status (update available, current/latest versions). */
71
+ export async function getVersionStatus() {
72
+ const status = await checkVersionStatus();
73
+ return create(grackle.VersionStatusSchema, {
74
+ currentVersion: status.currentVersion,
75
+ latestVersion: status.latestVersion,
76
+ updateAvailable: status.updateAvailable,
77
+ isDocker: status.isDocker,
78
+ });
79
+ }
80
+ //# sourceMappingURL=settings-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-handlers.js","sourceRoot":"","sources":["../src/settings-handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Auto-detection subscriber for human escalation.
3
+ *
4
+ * Watches for standalone (parentless, non-system-root) tasks that go IDLE
5
+ * and automatically creates an escalation on the agent's behalf.
6
+ * This is the safety net for simple topologies where there is no orchestrator
7
+ * to explicitly call `escalate_to_human`.
8
+ */
9
+ import type { Disposable, PluginContext } from "@grackle-ai/core";
10
+ /**
11
+ * Create the auto-escalation event-bus subscriber.
12
+ *
13
+ * Watches for standalone (parentless, non-ROOT) tasks whose latest session
14
+ * goes IDLE and automatically creates an escalation.
15
+ *
16
+ * @param ctx - Plugin context providing event-bus access.
17
+ * @returns A Disposable that unsubscribes and clears dedup state.
18
+ */
19
+ export declare function createEscalationAutoSubscriber(ctx: PluginContext): Disposable;
20
+ //# sourceMappingURL=escalation-auto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escalation-auto.d.ts","sourceRoot":"","sources":["../../src/signals/escalation-auto.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKlE;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAgC7E"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Auto-detection subscriber for human escalation.
3
+ *
4
+ * Watches for standalone (parentless, non-system-root) tasks that go IDLE
5
+ * and automatically creates an escalation on the agent's behalf.
6
+ * This is the safety net for simple topologies where there is no orchestrator
7
+ * to explicitly call `escalate_to_human`.
8
+ */
9
+ import { SESSION_STATUS, ROOT_TASK_ID } from "@grackle-ai/common";
10
+ import { taskStore, sessionStore, escalationStore } from "@grackle-ai/database";
11
+ import { readLastTextEntry } from "@grackle-ai/core";
12
+ import { routeEscalation } from "@grackle-ai/core";
13
+ import { logger } from "@grackle-ai/core";
14
+ import { ulid } from "ulid";
15
+ /** How long (ms) to remember a delivered notification before allowing re-delivery. */
16
+ const DEDUP_TTL_MS = 3_600_000; // 1 hour
17
+ /**
18
+ * Create the auto-escalation event-bus subscriber.
19
+ *
20
+ * Watches for standalone (parentless, non-ROOT) tasks whose latest session
21
+ * goes IDLE and automatically creates an escalation.
22
+ *
23
+ * @param ctx - Plugin context providing event-bus access.
24
+ * @returns A Disposable that unsubscribes and clears dedup state.
25
+ */
26
+ export function createEscalationAutoSubscriber(ctx) {
27
+ /** Track delivered notifications to prevent duplicates: key -> delivery timestamp. */
28
+ const delivered = new Map();
29
+ const unsubscribe = ctx.subscribe((event) => {
30
+ if (event.type !== "task.updated") {
31
+ return;
32
+ }
33
+ const taskId = event.payload.taskId;
34
+ if (!taskId) {
35
+ return;
36
+ }
37
+ // Fire-and-forget async handler — errors are logged, never thrown
38
+ (async () => {
39
+ try {
40
+ await handleTaskUpdated(delivered, taskId);
41
+ }
42
+ catch (err) {
43
+ logger.error({ err, taskId }, "Escalation auto-detect handler error");
44
+ }
45
+ })().catch(() => { });
46
+ });
47
+ logger.info("Escalation auto-detect subscriber initialized");
48
+ return {
49
+ dispose() {
50
+ unsubscribe();
51
+ delivered.clear();
52
+ },
53
+ };
54
+ }
55
+ /**
56
+ * Handle a task.updated event: check if the task is a standalone root task
57
+ * whose latest session has gone IDLE, and if so, auto-escalate.
58
+ */
59
+ async function handleTaskUpdated(delivered, taskId) {
60
+ const task = taskStore.getTask(taskId);
61
+ if (!task) {
62
+ return;
63
+ }
64
+ // Only parentless tasks trigger auto-escalation (child tasks use SIGCHLD)
65
+ if (task.parentTaskId) {
66
+ return;
67
+ }
68
+ // Exclude the system root task — it is always idle when nobody is chatting
69
+ if (taskId === ROOT_TASK_ID) {
70
+ return;
71
+ }
72
+ // Check if the latest session is IDLE
73
+ const latestSession = sessionStore.getLatestSessionForTask(taskId);
74
+ if (!latestSession) {
75
+ return;
76
+ }
77
+ if (latestSession.status !== SESSION_STATUS.IDLE) {
78
+ return;
79
+ }
80
+ // Idempotency: don't re-deliver for the same task+session pair
81
+ const dedupeKey = `${taskId}:${latestSession.id}`;
82
+ const now = Date.now();
83
+ const previousDelivery = delivered.get(dedupeKey);
84
+ if (previousDelivery !== undefined && now - previousDelivery < DEDUP_TTL_MS) {
85
+ return;
86
+ }
87
+ // Prune expired entries to prevent unbounded growth
88
+ pruneDelivered(delivered, now);
89
+ // Extract the last text message from the session log
90
+ const logPath = latestSession.logPath || undefined;
91
+ const lastEntry = logPath ? readLastTextEntry(logPath) : undefined;
92
+ const message = lastEntry?.content ?? "";
93
+ // Build task URL
94
+ const taskUrl = `/tasks/${taskId}`;
95
+ // Create and route the escalation
96
+ const escalationId = ulid();
97
+ const workspaceId = task.workspaceId ?? "";
98
+ escalationStore.createEscalation(escalationId, workspaceId, taskId, task.title, message, "auto", "normal", taskUrl);
99
+ // Mark dedupe AFTER successful persistence so failures can retry
100
+ delivered.set(dedupeKey, now);
101
+ // Route immediately — build the row inline to avoid a round-trip read
102
+ await routeEscalation({
103
+ id: escalationId,
104
+ workspaceId,
105
+ taskId,
106
+ title: task.title,
107
+ message,
108
+ source: "auto",
109
+ urgency: "normal",
110
+ status: "pending",
111
+ createdAt: new Date().toISOString(),
112
+ deliveredAt: null,
113
+ acknowledgedAt: null,
114
+ taskUrl,
115
+ });
116
+ logger.info({ taskId, escalationId, title: task.title }, "Auto-escalation created for idle standalone task");
117
+ }
118
+ /** Remove dedup entries older than DEDUP_TTL_MS. */
119
+ function pruneDelivered(delivered, now) {
120
+ for (const [key, timestamp] of delivered) {
121
+ if (now - timestamp >= DEDUP_TTL_MS) {
122
+ delivered.delete(key);
123
+ }
124
+ }
125
+ }
126
+ //# sourceMappingURL=escalation-auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escalation-auto.js","sourceRoot":"","sources":["../../src/signals/escalation-auto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Orphan reparenting — automatically reparent non-terminal children when
3
+ * a parent task reaches terminal state (complete/failed).
4
+ *
5
+ * Follows the SIGCHLD subscriber pattern: subscribes to domain events,
6
+ * detects orphan conditions, and reparents children to the grandparent.
7
+ * The root task (PID 1) is the ultimate adopter.
8
+ */
9
+ import type { Disposable, PluginContext } from "@grackle-ai/core";
10
+ /**
11
+ * Create the orphan reparenting event-bus subscriber.
12
+ *
13
+ * Watches for parent tasks reaching terminal state and reparents their
14
+ * non-terminal children to the grandparent (or root task as ultimate adopter).
15
+ *
16
+ * @param ctx - Plugin context providing event-bus access.
17
+ * @returns A Disposable that unsubscribes and clears dedup state.
18
+ */
19
+ export declare function createOrphanReparentSubscriber(ctx: PluginContext): Disposable;
20
+ /**
21
+ * Transfer ALL pipe subscriptions from a dead parent's sessions to the
22
+ * grandparent's active session. Called once per parent death (not per child).
23
+ *
24
+ * When a parent dies, all its pipe connections should move to the grandparent —
25
+ * like fd inheritance when a Unix process dies and init takes over.
26
+ *
27
+ * Exported so it can be called synchronously from completeTask() /
28
+ * killSessionAndCleanup() before sessions are cleaned up.
29
+ */
30
+ export declare function transferAllPipeSubscriptions(deadParentTaskId: string, grandparentTaskId: string): void;
31
+ //# sourceMappingURL=orphan-reparent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphan-reparent.d.ts","sourceRoot":"","sources":["../../src/signals/orphan-reparent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAWlE;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAmC7E;AA+FD;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAsDN"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Orphan reparenting — automatically reparent non-terminal children when
3
+ * a parent task reaches terminal state (complete/failed).
4
+ *
5
+ * Follows the SIGCHLD subscriber pattern: subscribes to domain events,
6
+ * detects orphan conditions, and reparents children to the grandparent.
7
+ * The root task (PID 1) is the ultimate adopter.
8
+ */
9
+ import { ROOT_TASK_ID, TASK_STATUS } from "@grackle-ai/common";
10
+ import { taskStore, sessionStore } from "@grackle-ai/database";
11
+ import { streamRegistry } from "@grackle-ai/core";
12
+ import { ensureAsyncDeliveryListener } from "@grackle-ai/core";
13
+ import { deliverSignalToTask } from "@grackle-ai/core";
14
+ import { logger } from "@grackle-ai/core";
15
+ /** Terminal task statuses that trigger orphan reparenting. */
16
+ const TERMINAL_TASK_STATUSES = new Set([
17
+ TASK_STATUS.COMPLETE,
18
+ TASK_STATUS.FAILED,
19
+ ]);
20
+ /** How long (ms) to remember a processed parent before allowing re-processing. */
21
+ const DEDUP_TTL_MS = 3_600_000; // 1 hour
22
+ /**
23
+ * Create the orphan reparenting event-bus subscriber.
24
+ *
25
+ * Watches for parent tasks reaching terminal state and reparents their
26
+ * non-terminal children to the grandparent (or root task as ultimate adopter).
27
+ *
28
+ * @param ctx - Plugin context providing event-bus access.
29
+ * @returns A Disposable that unsubscribes and clears dedup state.
30
+ */
31
+ export function createOrphanReparentSubscriber(ctx) {
32
+ /** Track processed parents to prevent duplicate reparenting: parentTaskId → timestamp. */
33
+ const processed = new Map();
34
+ const unsubscribe = ctx.subscribe((event) => {
35
+ if (event.type !== "task.completed" && event.type !== "task.updated") {
36
+ return;
37
+ }
38
+ const parentTaskId = event.payload.taskId;
39
+ if (!parentTaskId) {
40
+ return;
41
+ }
42
+ // Root task never completes — guard defensively
43
+ if (parentTaskId === ROOT_TASK_ID) {
44
+ return;
45
+ }
46
+ // Fire-and-forget async handler — errors are logged, never thrown
47
+ (async () => {
48
+ try {
49
+ await handleParentTerminal(ctx, processed, parentTaskId);
50
+ }
51
+ catch (err) {
52
+ logger.error({ err, parentTaskId }, "Orphan reparenting failed for parent task");
53
+ }
54
+ })().catch(() => { });
55
+ });
56
+ return {
57
+ dispose() {
58
+ unsubscribe();
59
+ processed.clear();
60
+ },
61
+ };
62
+ }
63
+ /**
64
+ * Check if a parent task is terminal and reparent its non-terminal children.
65
+ */
66
+ async function handleParentTerminal(ctx, processed, parentTaskId) {
67
+ const parentTask = taskStore.getTask(parentTaskId);
68
+ if (!parentTask) {
69
+ return;
70
+ }
71
+ // Only trigger for terminal statuses
72
+ if (!TERMINAL_TASK_STATUSES.has(parentTask.status)) {
73
+ return;
74
+ }
75
+ // Deduplication: skip if we already processed this parent recently
76
+ const now = Date.now();
77
+ const lastProcessed = processed.get(parentTaskId);
78
+ if (lastProcessed && now - lastProcessed < DEDUP_TTL_MS) {
79
+ return;
80
+ }
81
+ // Mark as processed before doing work (prevents concurrent re-entry)
82
+ processed.set(parentTaskId, now);
83
+ // Determine the grandparent (or root task as ultimate adopter)
84
+ const grandparentId = parentTask.parentTaskId || ROOT_TASK_ID;
85
+ // Always transfer pipe fds from dead parent to grandparent, even when there
86
+ // are no orphaned tasks. ipc_spawn creates child sessions (not tasks), so
87
+ // pipe subscriptions can exist without corresponding child tasks.
88
+ transferAllPipeSubscriptions(parentTaskId, grandparentId);
89
+ // Get non-terminal children for reparenting
90
+ const orphans = taskStore.getOrphanedTasks(parentTaskId);
91
+ if (orphans.length === 0) {
92
+ // Evict stale dedup entries even when no reparenting needed
93
+ for (const [key, ts] of processed) {
94
+ if (now - ts > DEDUP_TTL_MS) {
95
+ processed.delete(key);
96
+ }
97
+ }
98
+ return;
99
+ }
100
+ logger.info({ parentTaskId, grandparentId, orphanCount: orphans.length, reason: parentTask.status }, "Reparenting orphaned children to grandparent");
101
+ // Reparent each orphan
102
+ for (const orphan of orphans) {
103
+ try {
104
+ taskStore.reparentTask(orphan.id, grandparentId);
105
+ ctx.emit("task.reparented", {
106
+ taskId: orphan.id,
107
+ oldParentTaskId: parentTaskId,
108
+ newParentTaskId: grandparentId,
109
+ workspaceId: orphan.workspaceId || "",
110
+ });
111
+ ctx.emit("task.updated", {
112
+ taskId: orphan.id,
113
+ workspaceId: orphan.workspaceId || "",
114
+ });
115
+ // Deliver [ADOPTED] signal to grandparent
116
+ const message = `[ADOPTED] Task "${orphan.title}" (${orphan.id}) was adopted from ` +
117
+ `terminated parent "${parentTask.title}" (${parentTask.id}). ` +
118
+ `The task is now your direct child. Use ipc_list_fds to see transferred pipe fds.`;
119
+ await deliverSignalToTask(grandparentId, "adopted", message);
120
+ }
121
+ catch (err) {
122
+ logger.error({ err, orphanId: orphan.id, parentTaskId, grandparentId }, "Failed to reparent orphan — continuing with remaining children");
123
+ }
124
+ }
125
+ // Evict stale dedup entries
126
+ for (const [key, ts] of processed) {
127
+ if (now - ts > DEDUP_TTL_MS) {
128
+ processed.delete(key);
129
+ }
130
+ }
131
+ }
132
+ /**
133
+ * Transfer ALL pipe subscriptions from a dead parent's sessions to the
134
+ * grandparent's active session. Called once per parent death (not per child).
135
+ *
136
+ * When a parent dies, all its pipe connections should move to the grandparent —
137
+ * like fd inheritance when a Unix process dies and init takes over.
138
+ *
139
+ * Exported so it can be called synchronously from completeTask() /
140
+ * killSessionAndCleanup() before sessions are cleaned up.
141
+ */
142
+ export function transferAllPipeSubscriptions(deadParentTaskId, grandparentTaskId) {
143
+ const grandparentSessions = sessionStore.getActiveSessionsForTask(grandparentTaskId);
144
+ if (grandparentSessions.length === 0) {
145
+ logger.debug({ deadParentTaskId, grandparentTaskId }, "No active grandparent session — skipping pipe fd transfer");
146
+ return;
147
+ }
148
+ const grandparentSessionId = grandparentSessions[0].id;
149
+ const parentSessions = sessionStore.listSessionsForTask(deadParentTaskId);
150
+ let transferred = 0;
151
+ for (const parentSession of parentSessions) {
152
+ const subs = streamRegistry.getSubscriptionsForSession(parentSession.id);
153
+ for (const sub of subs) {
154
+ const stream = streamRegistry.getStream(sub.streamId);
155
+ if (!stream?.name.startsWith("pipe:")) {
156
+ continue;
157
+ }
158
+ try {
159
+ streamRegistry.subscribe(sub.streamId, grandparentSessionId, sub.permission, sub.deliveryMode, sub.createdBySpawn);
160
+ streamRegistry.unsubscribe(sub.id);
161
+ if (sub.deliveryMode === "async") {
162
+ ensureAsyncDeliveryListener(grandparentSessionId);
163
+ }
164
+ transferred++;
165
+ }
166
+ catch (err) {
167
+ logger.warn({ err, stream: stream.name, deadParentTaskId }, "Failed to transfer pipe fd");
168
+ }
169
+ }
170
+ }
171
+ if (transferred > 0) {
172
+ logger.info({ deadParentTaskId, grandparentTaskId, grandparentSessionId, transferred }, "Transferred %d pipe fd(s) to grandparent session", transferred);
173
+ }
174
+ }
175
+ //# sourceMappingURL=orphan-reparent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphan-reparent.js","sourceRoot":"","sources":["../../src/signals/orphan-reparent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Disposable, PluginContext } from "@grackle-ai/core";
2
+ /**
3
+ * Create the SIGCHLD event-bus subscriber.
4
+ *
5
+ * Watches for child tasks whose latest session reaches a SIGCHLD-triggering
6
+ * status (idle or stopped) and delivers a notification to the parent task.
7
+ *
8
+ * @param ctx - Plugin context providing event-bus access.
9
+ * @returns A Disposable that unsubscribes and clears dedup state.
10
+ */
11
+ export declare function createSigchldSubscriber(ctx: PluginContext): Disposable;
12
+ //# sourceMappingURL=sigchld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigchld.d.ts","sourceRoot":"","sources":["../../src/signals/sigchld.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAgClE;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAgCtE"}