@bastani/atomic 0.9.5 → 0.9.6-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/builtin/cursor/CHANGELOG.md +6 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +3 -3
- package/dist/builtin/intercom/index-heavy.ts +0 -17
- package/dist/builtin/intercom/index.ts +7 -68
- package/dist/builtin/intercom/lazy-heavy-proxy.ts +0 -6
- package/dist/builtin/intercom/lifecycle.ts +1 -16
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +7 -0
- package/dist/builtin/subagents/README.md +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +1 -1
- package/dist/builtin/subagents/src/extension/prompt-guidance.ts +6 -7
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +8 -0
- package/dist/builtin/workflows/README.md +3 -3
- package/dist/builtin/workflows/builtin/ralph-core.ts +3 -3
- package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -20
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +13 -7
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +8 -8
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/docs/quickstart.md +2 -4
- package/docs/subagents.md +1 -1
- package/docs/workflows.md +12 -12
- package/npm-shrinkwrap.json +23 -23
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Restored workflow-first Atomic guidance for non-trivial work with verifiable objectives and synchronized help/docs around rich inline TypeScript workflow authoring, including dynamic branching, fan-out, verification, candidate-selection, human-gate, child-workflow, and bounded-loop patterns.
|
|
10
|
+
- Documented compositional workflow authoring in model prompts and onboarding/help surfaces, including importing bundled workflows from `@bastani/workflows/builtin`, nesting definitions with `ctx.workflow(...)`, and building deeper reusable workflow graphs within `maxDepth`.
|
|
11
|
+
- Restored tool-driven bundled Intercom startup so foreground subagent launches and bridged child session startup no longer connect either session automatically; the model or user must invoke Intercom when coordination is needed.
|
|
12
|
+
|
|
5
13
|
## [0.9.5] - 2026-07-11
|
|
6
14
|
|
|
7
15
|
### Breaking Changes
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Published a synchronized Atomic 0.9.6-alpha.1 prerelease for the Cursor provider package; no functional Cursor provider changes were made after 0.9.5.
|
|
10
|
+
|
|
5
11
|
## [0.9.5] - 2026-07-11
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/cursor",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Experimental first-party Atomic extension for Cursor OAuth, model discovery, and streaming provider registration.",
|
|
6
6
|
"contributors": [
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@bastani/atomic-natives": "0.9.
|
|
43
|
+
"@bastani/atomic-natives": "0.9.6-alpha.1",
|
|
44
44
|
"@bufbuild/protobuf": "^2.12.1",
|
|
45
45
|
"@earendil-works/pi-ai": "^0.80.6"
|
|
46
46
|
}
|
|
@@ -4,6 +4,12 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Restored fully tool-driven Intercom connections: parent and bridged child sessions no longer import or connect to the broker merely because a subagent starts. The runtime now connects only when the model or user invokes an Intercom tool, command, shortcut, or relay.
|
|
12
|
+
|
|
7
13
|
## [0.9.5] - 2026-07-11
|
|
8
14
|
|
|
9
15
|
### Added
|
|
@@ -24,7 +24,7 @@ Intercom also integrates with delegated subagents: child agents get a child-only
|
|
|
24
24
|
|
|
25
25
|
## In One Minute
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Intercom connections are tool-driven. Parent and delegated child sessions keep the lightweight wrapper unloaded until the model or user invokes an Intercom tool, `/intercom`, or the `ALT+M` overlay. A bridged child receives its deterministic Intercom identity and `contact_supervisor` tool at startup, but invoking that tool establishes its broker connection; merely launching a foreground or background child does not connect either session. Concurrent first-use callers share one import and connection attempt, and lazy broker state is leased to the active session generation and cleaned up on shutdown or replacement.
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
@@ -34,7 +34,7 @@ Atomic bundles `@bastani/intercom` as a first-party extension; no separate insta
|
|
|
34
34
|
pi install npm:pi-intercom
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Then restart Atomic or Pi. The extension registers the bundled `intercom` skill
|
|
37
|
+
Then restart Atomic or Pi. The extension registers the bundled `intercom` skill and lightweight tools at startup, but it does not connect the session until the model or user invokes Intercom.
|
|
38
38
|
|
|
39
39
|
**Recommended:** Add this snippet to your project's `AGENTS.md` to help agents understand when to coordinate across sessions:
|
|
40
40
|
|
|
@@ -53,7 +53,7 @@ Coordinate with other local Atomic/pi sessions on related codebases. Use `/skill
|
|
|
53
53
|
A session becomes intercom-connected when all of these are true:
|
|
54
54
|
- the intercom extension is installed/bundled and loaded in that session
|
|
55
55
|
- `enabled` is not set to `false` in `~/.atomic/agent/intercom/config.json` (Atomic) or the legacy `~/.pi/agent/intercom/config.json` fallback
|
|
56
|
-
- the
|
|
56
|
+
- the model or user has invoked an Intercom tool, `/intercom`, or the `ALT+M` overlay in that session
|
|
57
57
|
- the local broker is running or can be auto-started
|
|
58
58
|
|
|
59
59
|
The session list only shows intercom-connected sessions, not every open Pi process on the machine.
|
|
@@ -37,7 +37,6 @@ export default function piIntercomExtension(pi: ExtensionAPI) {
|
|
|
37
37
|
let reconnectTimer: NodeJS.Timeout | null = null;
|
|
38
38
|
let reconnectPromise: Promise<IntercomClient> | null = null;
|
|
39
39
|
let reconnectPromiseGeneration: number | null = null;
|
|
40
|
-
let startupConnectTimer: NodeJS.Timeout | null = null;
|
|
41
40
|
let reconnectAttempt = 0;
|
|
42
41
|
let shuttingDown = false;
|
|
43
42
|
let disposed = true;
|
|
@@ -99,10 +98,6 @@ export default function piIntercomExtension(pi: ExtensionAPI) {
|
|
|
99
98
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
100
99
|
reconnectTimer = null;
|
|
101
100
|
}
|
|
102
|
-
function clearStartupConnectTimer(): void {
|
|
103
|
-
if (startupConnectTimer) clearTimeout(startupConnectTimer);
|
|
104
|
-
startupConnectTimer = null;
|
|
105
|
-
}
|
|
106
101
|
function clearInboundFlushTimer(): void {
|
|
107
102
|
if (inboundFlushTimer) clearTimeout(inboundFlushTimer);
|
|
108
103
|
inboundFlushTimer = null;
|
|
@@ -425,17 +420,13 @@ export default function piIntercomExtension(pi: ExtensionAPI) {
|
|
|
425
420
|
incrementRuntimeGeneration: () => { runtimeGeneration += 1; foregroundDetachHandoff.reset(); return runtimeGeneration; },
|
|
426
421
|
resetReconnectAttempt: () => { reconnectAttempt = 0; },
|
|
427
422
|
clearReconnectTimer,
|
|
428
|
-
clearStartupConnectTimer,
|
|
429
423
|
setRuntimeContext: (value) => { runtimeContext = value; },
|
|
430
424
|
setCurrentSessionId: (value) => { currentSessionId = value; },
|
|
431
425
|
setCurrentModel: (value) => { currentModel = value; },
|
|
432
426
|
setSessionStartedAt: (value) => { sessionStartedAt = value; },
|
|
433
427
|
setAgentRunning: (value) => { agentRunning = value; },
|
|
434
428
|
activeTools,
|
|
435
|
-
setStartupConnectTimer: (value) => { startupConnectTimer = value; },
|
|
436
429
|
getLiveContext,
|
|
437
|
-
ensureConnected,
|
|
438
|
-
scheduleReconnect,
|
|
439
430
|
rejectReplyWaiter,
|
|
440
431
|
replyTracker,
|
|
441
432
|
pendingIdleMessages,
|
|
@@ -480,12 +471,4 @@ export default function piIntercomExtension(pi: ExtensionAPI) {
|
|
|
480
471
|
ensureConnected,
|
|
481
472
|
syncPresenceIdentity,
|
|
482
473
|
});
|
|
483
|
-
return { enabled: config.enabled,
|
|
484
|
-
async awaitAutomaticBrokerReady(): Promise<void> {
|
|
485
|
-
if (config.enabled) await ensureConnected("startup");
|
|
486
|
-
},
|
|
487
|
-
async awaitForegroundBrokerReady(): Promise<void> {
|
|
488
|
-
if (config.enabled) await ensureConnected("tool");
|
|
489
|
-
},
|
|
490
|
-
};
|
|
491
474
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { APP_NAME, getEnvValue, type ExtensionAPI, type ExtensionContext, type SessionStartEvent, type ToolDefinition
|
|
1
|
+
import { APP_NAME, getEnvValue, type ExtensionAPI, type ExtensionContext, type SessionStartEvent, type ToolDefinition } from "@bastani/atomic";
|
|
2
2
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
4
|
import { renderIntercomToolResult } from "./result-renderers.js";
|
|
5
|
-
import { loadConfig } from "./config.js";
|
|
6
5
|
import { executeHeavyTool, runHeavyCommand, type HeavyHandle } from "./lazy-tool-execution.js";
|
|
7
6
|
import { assertCurrentLifecycleLease, createLifecycleLease, retainSettledLifecycleCleanup, retireLifecycleLease, SerializedLifecycleForwarder, type LifecycleLease } from "./lifecycle-lease.js";
|
|
8
7
|
import { rejectLazyResultRelay } from "./lazy-subagent-ack.js";
|
|
@@ -13,7 +12,6 @@ import {
|
|
|
13
12
|
dispatchHandlers,
|
|
14
13
|
type CapturedHeavy,
|
|
15
14
|
type ForwardedEventMap,
|
|
16
|
-
type HeavyRuntimeReadiness,
|
|
17
15
|
type ToolRenderResultArgs,
|
|
18
16
|
} from "./lazy-heavy-proxy.js";
|
|
19
17
|
|
|
@@ -34,22 +32,9 @@ type ActiveLifecycleState = {
|
|
|
34
32
|
modelSelect: LifecycleSnapshot<"model_select"> | null;
|
|
35
33
|
};
|
|
36
34
|
interface LightweightIntercomOptions {
|
|
37
|
-
importHeavy?: () => Promise<{ default: (pi: ExtensionAPI) => void |
|
|
38
|
-
isEnabled?: () => boolean;
|
|
35
|
+
importHeavy?: () => Promise<{ default: (pi: ExtensionAPI) => void | Promise<void> }>;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
const MANAGEMENT_ONLY_SUBAGENT_ACTIONS = new Set(["list", "get", "create", "update", "delete", "status", "interrupt", "doctor"]);
|
|
42
|
-
|
|
43
|
-
function isInteractiveForegroundSubagentStart(event: ToolExecutionStartEvent, ctx: ExtensionContext): boolean {
|
|
44
|
-
if (!ctx.hasUI || event.toolName !== "subagent") return false;
|
|
45
|
-
if (!event.args || typeof event.args !== "object" || Array.isArray(event.args)) return true;
|
|
46
|
-
const args = event.args as { action?: unknown; async?: unknown };
|
|
47
|
-
const action = typeof args.action === "string" ? args.action.trim() : "";
|
|
48
|
-
if (action && MANAGEMENT_ONLY_SUBAGENT_ACTIONS.has(action)) return false;
|
|
49
|
-
return args.async !== true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
38
|
const SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
|
|
54
39
|
const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
|
|
55
40
|
|
|
@@ -74,8 +59,6 @@ function renderHeavyToolResult(loadedHeavy: CapturedHeavy | null, name: string,
|
|
|
74
59
|
return renderIntercomToolResult(name, args);
|
|
75
60
|
}
|
|
76
61
|
export default function intercom(pi: ExtensionAPI, options: LightweightIntercomOptions = {}) {
|
|
77
|
-
const enabled = options.isEnabled?.() ?? loadConfig().enabled;
|
|
78
|
-
const delegatedSession = hasSubagentIntercomEnv();
|
|
79
62
|
const delegatedSessionName = readSubagentEnv("INTERCOM_SESSION_NAME");
|
|
80
63
|
let heavyAttempt: HeavyAttempt | null = null;
|
|
81
64
|
let loadedHeavy: IntercomHeavyHandle | null = null;
|
|
@@ -187,8 +170,7 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
187
170
|
try {
|
|
188
171
|
const mod = await (options.importHeavy?.() ?? import("./index-heavy.js"));
|
|
189
172
|
assertLease(lease);
|
|
190
|
-
|
|
191
|
-
if (runtimeReadiness) captured.runtimeReadiness = runtimeReadiness;
|
|
173
|
+
await mod.default(createHeavyProxy(pi, captured));
|
|
192
174
|
assertLease(lease);
|
|
193
175
|
if (!sessionSnapshot && ctx) {
|
|
194
176
|
sessionSnapshot = { event: createSyntheticSessionStartEvent(), ctx, generation: ++lifecycleGeneration, lease };
|
|
@@ -214,23 +196,6 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
214
196
|
);
|
|
215
197
|
return promise;
|
|
216
198
|
}
|
|
217
|
-
async function registerAutomatically(ctx: ExtensionContext, phase: string, foreground = false): Promise<boolean> {
|
|
218
|
-
try {
|
|
219
|
-
const handle = await loadHeavy(ctx);
|
|
220
|
-
const readiness = handle.heavy.runtimeReadiness;
|
|
221
|
-
if (!readiness) throw new Error("Intercom heavy runtime did not expose broker readiness");
|
|
222
|
-
if (readiness.enabled) {
|
|
223
|
-
if (foreground) await readiness.awaitForegroundBrokerReady();
|
|
224
|
-
else await readiness.awaitAutomaticBrokerReady();
|
|
225
|
-
}
|
|
226
|
-
handle.assertCurrent();
|
|
227
|
-
return readiness.enabled;
|
|
228
|
-
} catch (error) {
|
|
229
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
230
|
-
console.error(`Intercom ${phase} failed; session will continue and a later call may retry: ${message}`, error);
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
199
|
pi.on("session_start", async (event, ctx) => {
|
|
235
200
|
if (delegatedSessionName && typeof pi.setSessionName === "function") pi.setSessionName(delegatedSessionName);
|
|
236
201
|
if (activeLease.retired) activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++, activeLease.cleanupBarrier);
|
|
@@ -244,12 +209,7 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
244
209
|
}
|
|
245
210
|
const generation = ++lifecycleGeneration;
|
|
246
211
|
sessionSnapshot = { event, ctx, generation, lease };
|
|
247
|
-
if (loadedHeavy)
|
|
248
|
-
await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
if (!enabled || (!ctx.hasUI && !delegatedSession)) return;
|
|
252
|
-
if (delegatedSession) await registerAutomatically(ctx, "bridged child automatic registration");
|
|
212
|
+
if (loadedHeavy) await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
|
|
253
213
|
});
|
|
254
214
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
255
215
|
const lease = activeLease;
|
|
@@ -307,28 +267,7 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
307
267
|
});
|
|
308
268
|
pi.on("tool_execution_start", async (event, ctx) => {
|
|
309
269
|
if (activeLease.retired) return;
|
|
310
|
-
|
|
311
|
-
const toolSnapshot: LifecycleSnapshot<"tool_execution_start"> = { event, ctx };
|
|
312
|
-
activeLifecycle.activeTools.set(event.toolCallId, toolSnapshot);
|
|
313
|
-
if (isInteractiveForegroundSubagentStart(event, ctx) && enabled) {
|
|
314
|
-
const session = sessionSnapshot;
|
|
315
|
-
const warmHeavy = loadedHeavy?.heavy ?? null;
|
|
316
|
-
const warmReplayComplete = warmHeavy !== null
|
|
317
|
-
&& session?.lease === lease
|
|
318
|
-
&& replayedGeneration === session.generation;
|
|
319
|
-
// Successful readiness gates launch; optional Intercom failures degrade
|
|
320
|
-
// without preventing the subagent tool itself from executing.
|
|
321
|
-
await registerAutomatically(ctx, "foreground parent warmup", true);
|
|
322
|
-
if (warmReplayComplete
|
|
323
|
-
&& activeLease === lease
|
|
324
|
-
&& !lease.retired
|
|
325
|
-
&& sessionSnapshot === session
|
|
326
|
-
&& activeLifecycle.activeTools.get(event.toolCallId) === toolSnapshot
|
|
327
|
-
&& loadedHeavy?.heavy === warmHeavy) {
|
|
328
|
-
await lifecycleForward.enqueue(() => dispatchHandlers(warmHeavy, "tool_execution_start", event, ctx));
|
|
329
|
-
}
|
|
330
|
-
return; // Cold initialization replay owns this active tool's delivery.
|
|
331
|
-
}
|
|
270
|
+
activeLifecycle.activeTools.set(event.toolCallId, { event, ctx });
|
|
332
271
|
const heavy = loadedHeavy?.heavy;
|
|
333
272
|
if (heavy) await lifecycleForward.enqueue(() => dispatchHandlers(heavy, "tool_execution_start", event, ctx));
|
|
334
273
|
});
|
|
@@ -367,8 +306,8 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
367
306
|
});
|
|
368
307
|
});
|
|
369
308
|
}
|
|
370
|
-
//
|
|
371
|
-
//
|
|
309
|
+
// Heavy Intercom state stays unloaded until the model or user invokes an
|
|
310
|
+
// Intercom tool, command, shortcut, or relay that needs it.
|
|
372
311
|
pi.registerTool({
|
|
373
312
|
name: "intercom",
|
|
374
313
|
label: "Intercom",
|
|
@@ -27,11 +27,6 @@ type LazyLifecycleEvent = keyof ForwardedEventMap;
|
|
|
27
27
|
type ForwardedHandler<K extends LazyLifecycleEvent> = ExtensionHandler<ForwardedEventMap[K]>;
|
|
28
28
|
type ForwardedHandlerMap = { [K in LazyLifecycleEvent]: ForwardedHandler<K>[] };
|
|
29
29
|
type AnyForwardedHandler = { [K in LazyLifecycleEvent]: ForwardedHandler<K> }[LazyLifecycleEvent];
|
|
30
|
-
export interface HeavyRuntimeReadiness {
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
awaitAutomaticBrokerReady(): Promise<void>;
|
|
33
|
-
awaitForegroundBrokerReady(): Promise<void>;
|
|
34
|
-
}
|
|
35
30
|
|
|
36
31
|
export type CapturedHeavy = {
|
|
37
32
|
tools: Map<string, ToolDefinition>;
|
|
@@ -39,7 +34,6 @@ export type CapturedHeavy = {
|
|
|
39
34
|
handlers: ForwardedHandlerMap;
|
|
40
35
|
shortcuts: Map<string, CapturedShortcut>;
|
|
41
36
|
eventHandlers: Map<string, EventHandler[]>;
|
|
42
|
-
runtimeReadiness?: HeavyRuntimeReadiness;
|
|
43
37
|
};
|
|
44
38
|
|
|
45
39
|
export function createForwardedHandlerMap(): ForwardedHandlerMap {
|
|
@@ -14,17 +14,13 @@ interface LifecycleDeps {
|
|
|
14
14
|
incrementRuntimeGeneration(): number;
|
|
15
15
|
resetReconnectAttempt(): void;
|
|
16
16
|
clearReconnectTimer(): void;
|
|
17
|
-
clearStartupConnectTimer(): void;
|
|
18
17
|
setRuntimeContext(ctx: ExtensionContext | null): void;
|
|
19
18
|
setCurrentSessionId(id: string | null): void;
|
|
20
19
|
setCurrentModel(model: string): void;
|
|
21
20
|
setSessionStartedAt(value: number | null): void;
|
|
22
21
|
setAgentRunning(value: boolean): void;
|
|
23
22
|
activeTools: Map<string, string>;
|
|
24
|
-
setStartupConnectTimer(timer: NodeJS.Timeout | null): void;
|
|
25
23
|
getLiveContext(ctx?: ExtensionContext | null, generation?: number): ExtensionContext | null;
|
|
26
|
-
ensureConnected(reason: "startup"): Promise<IntercomClient>;
|
|
27
|
-
scheduleReconnect(): void;
|
|
28
24
|
rejectReplyWaiter(error: Error): void;
|
|
29
25
|
replyTracker: ReplyTracker;
|
|
30
26
|
pendingIdleMessages: InboundMessageEntry[];
|
|
@@ -44,7 +40,6 @@ export function registerIntercomLifecycle(pi: ExtensionAPI, deps: LifecycleDeps)
|
|
|
44
40
|
deps.setShuttingDown(true);
|
|
45
41
|
deps.setDisposed(true);
|
|
46
42
|
deps.incrementRuntimeGeneration();
|
|
47
|
-
deps.clearStartupConnectTimer();
|
|
48
43
|
deps.clearReconnectTimer();
|
|
49
44
|
deps.rejectReplyWaiter(new Error(reason));
|
|
50
45
|
deps.replyTracker.reset();
|
|
@@ -74,25 +69,15 @@ export function registerIntercomLifecycle(pi: ExtensionAPI, deps: LifecycleDeps)
|
|
|
74
69
|
deps.setShuttingDown(false);
|
|
75
70
|
deps.setDisposed(false);
|
|
76
71
|
deps.setRuntimeStarted(true);
|
|
77
|
-
|
|
72
|
+
deps.incrementRuntimeGeneration();
|
|
78
73
|
deps.resetReconnectAttempt();
|
|
79
74
|
deps.clearReconnectTimer();
|
|
80
|
-
deps.clearStartupConnectTimer();
|
|
81
75
|
deps.setRuntimeContext(ctx);
|
|
82
76
|
deps.setCurrentSessionId(ctx.sessionManager.getSessionId());
|
|
83
77
|
deps.setCurrentModel(ctx.model?.id ?? "unknown");
|
|
84
78
|
deps.setSessionStartedAt(Date.now());
|
|
85
79
|
deps.setAgentRunning(false);
|
|
86
80
|
deps.activeTools.clear();
|
|
87
|
-
deps.setStartupConnectTimer(setTimeout(() => {
|
|
88
|
-
deps.setStartupConnectTimer(null);
|
|
89
|
-
if (!deps.getLiveContext(ctx, startupGeneration)) return;
|
|
90
|
-
void deps.ensureConnected("startup").catch(() => {
|
|
91
|
-
if (!deps.getLiveContext(ctx, startupGeneration)) return;
|
|
92
|
-
deps.setClient(null);
|
|
93
|
-
deps.scheduleReconnect();
|
|
94
|
-
});
|
|
95
|
-
}, 0));
|
|
96
81
|
});
|
|
97
82
|
|
|
98
83
|
pi.on("session_shutdown", async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Published a synchronized Atomic 0.9.6-alpha.1 prerelease for the MCP extension; no functional MCP changes were made after 0.9.5.
|
|
15
|
+
|
|
10
16
|
## [0.9.5] - 2026-07-11
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
|
|
6
6
|
"contributors": [
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Aligned model-facing subagent guidance with workflow-first routing: subagents remain focused specialists inside workflow stages or bounded direct delegation, rather than becoming an ad hoc implementation/review/retry pipeline for workflow-fit work.
|
|
10
|
+
- Changed bundled Intercom coordination back to model-driven connection: launching foreground or background children no longer connects the parent or child session automatically; an Intercom tool or UI action must establish each session's broker connection.
|
|
11
|
+
|
|
5
12
|
## [0.9.5] - 2026-07-11
|
|
6
13
|
|
|
7
14
|
### Added
|
|
@@ -230,7 +230,7 @@ The child can use one dedicated coordination tool:
|
|
|
230
230
|
- `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
|
|
231
231
|
|
|
232
232
|
Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Intercom-confirmed foreground delivery returns a compact receipt with artifact/session paths; without that confirmation, the normal full output is preserved. Grouped messages include child intercom targets and full child summaries. The separate in-process completion event keeps its legacy synchronous semantics: emission is accepted unless a listener explicitly rejects it during the call, and no listener is not treated as an error.
|
|
233
|
-
When the companion is enabled and available,
|
|
233
|
+
When the companion is enabled and available, the bridge gives eligible children deterministic Intercom identities and coordination tools without connecting them automatically. Parent and child connections remain tool-driven: if a child may need live coordination, the parent model should invoke `intercom({ action: "status" })` before launch, and the child connects when it invokes `contact_supervisor` or `intercom`. Foreground/background launch and management-only actions do not force Intercom loading or broker startup.
|
|
234
234
|
|
|
235
235
|
For foreground runs, Intercom uses a targeted probe/reservation before delivery: only the exact live child can claim its message. Atomic then commits detach for that child and waits for its acknowledgement before placing claimed asks, sends, decisions, interviews, and progress updates in the parent's model-visible steering queue, so cancellation between phases cannot surface an orphaned request. Blocking calls remain alive for an exact threaded reply and then resume; fire-and-forget calls create no waiter. The retained child later replaces its detached status and artifacts with the real result. Cancellation/replacement invalidates stale handshakes, duplicate delivery cannot recommit, and background or unmatched messages retain queued-until-idle behavior.
|
|
236
236
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for delegating tasks to subagents with chains, parallel execution, and background runs. Fork of: https://github.com/nicobailon/pi-subagents",
|
|
6
6
|
"contributors": [
|
|
@@ -423,7 +423,7 @@ subagent({
|
|
|
423
423
|
|
|
424
424
|
## Subagent + Intercom Coordination
|
|
425
425
|
|
|
426
|
-
Atomic subagents work without intercom. When Atomic's bundled intercom companion or upstream `pi-intercom` is installed and enabled, the
|
|
426
|
+
Atomic subagents work without intercom. When Atomic's bundled intercom companion or upstream `pi-intercom` is installed and enabled, the bridge can give eligible child agents a private coordination tool back to the parent session without connecting either session automatically. If a child may need live coordination, invoke `intercom({ action: "status" })` in the parent before launching it; the child connects when it first invokes `contact_supervisor` or `intercom`.
|
|
427
427
|
|
|
428
428
|
The builtin specialists in this skill do not declare the `intercom` tool, so they finish their pass and return without coordinating. They cannot pause to ask the parent for a decision mid-run; if you need that, write a custom agent that lists `intercom` (or that the runtime bridge can inject `contact_supervisor` into).
|
|
429
429
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
export const DEFAULT_PROMPT_GUIDANCE: string[] = [
|
|
2
|
-
`**Subagent orchestration**: Use subagents
|
|
3
|
-
-
|
|
4
|
-
- Use a single subagent for a focused specialty, a chain for a bounded sequential handoff, or parallel tasks for independent work.
|
|
5
|
-
- Delegate noisy or context-heavy command investigation when isolation helps, but run concise commands inline when that is simpler.
|
|
6
|
-
- Use async/background execution
|
|
7
|
-
-
|
|
8
|
-
- Debug conceptual questions or exploratory analysis inline when appropriate. Use the debugger subagent for actual failures that need reproduction, root-cause diagnosis, and a validated fix; additional debugger or research delegates are optional when they add a distinct useful angle.`,
|
|
2
|
+
`**Subagent orchestration**: Use subagents for focused specialist work inside workflows or as bounded delegation when a workflow would be unnecessary overhead.
|
|
3
|
+
- Because workflows are the default for non-trivial structured work with verifiable objectives, do not stretch parent-controlled subagent calls into an ad hoc implementation, review, or retry pipeline; use a workflow and let its stages delegate specialists.
|
|
4
|
+
- Use a single subagent for a focused specialty, a chain for a bounded sequential handoff, or parallel tasks for independent work. Keep substantial-overlap tasks together rather than duplicating investigation across agents.
|
|
5
|
+
- Delegate noisy or context-heavy command investigation when isolation helps, but run concise commands inline when that is simpler.
|
|
6
|
+
- Use async/background execution when delegated work is genuinely long-running or independently useful. Foreground execution is appropriate when the parent needs the result before proceeding; do not duplicate a delegated job while waiting.
|
|
7
|
+
- Use the debugger subagent for actual failures that need reproduction, root-cause diagnosis, and a validated fix; additional debugger or research delegates are optional when they add a distinct useful angle.`,
|
|
9
8
|
];
|
|
10
9
|
|
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Published a synchronized Atomic 0.9.6-alpha.1 prerelease for the web-access extension; no functional web-access changes were made after 0.9.5.
|
|
12
|
+
|
|
7
13
|
## [0.9.5] - 2026-07-11
|
|
8
14
|
|
|
9
15
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.6-alpha.1] - 2026-07-12
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Restored workflow-first model routing for non-trivial, structured, and verifiable work while retaining the newer ability to author task-specific TypeScript workflows inline. Prompt guidance now explicitly combines the documented classify/branch, fan-out/synthesis, adversarial verification, generate/filter, tournament, and bounded loop patterns instead of forcing every workflow-fit task into an installed workflow, direct shape, or builtin.
|
|
14
|
+
- Restored Ralph's builtin implementation-stage prompts to require subagent-led investigation, editing, and validation, reversing the selective direct-implementation wording introduced with intent-first routing.
|
|
15
|
+
- Expanded model-facing workflow guidance to treat composition as a first-class design option: custom parents can import reusable project/package workflows or bundled builtin definitions, invoke them through `ctx.workflow(...)`, and nest further child workflows within `maxDepth` while preserving expanded graph visibility, HIL, durability, controls, and declared output contracts.
|
|
16
|
+
|
|
9
17
|
## [0.9.5] - 2026-07-11
|
|
10
18
|
|
|
11
19
|
### Breaking Changes
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
An open-source Atomic workflow extension: install it, author workflows in TypeScript, run them from chat.
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Default to workflows for non-trivial work and requests with inherent structure plus a verifiable objective; reserve direct chat for tiny deterministic low-risk work. Workflow-first is not builtin-only or monolithic: Atomic can author custom TypeScript `workflow({...})` definitions inline, import reusable project/package workflows or builtins from `@bastani/workflows/builtin`, and nest them with `ctx.workflow(...)`. Imported children may nest further workflows within `maxDepth`, so compose proven research, implementation, design, verification, and approval graphs rather than copying them. Custom parents can also use runtime classification, dynamic fan-out and synthesis, adversarial verification, candidate tournaments, HIL gates, and bounded convergence.
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
11
|
<a href="#authoring-api">Authoring API</a>
|
|
@@ -552,12 +552,12 @@ Prompt answer replay is live-memory only. `StageSnapshot.promptAnswerState` repo
|
|
|
552
552
|
|
|
553
553
|
### `workflow` tool (LLM-callable)
|
|
554
554
|
|
|
555
|
-
<!-- Keep the description below in sync with WORKFLOW_TOOL_DESCRIPTION in packages/workflows/src/extension/
|
|
555
|
+
<!-- Keep the description below in sync with WORKFLOW_TOOL_DESCRIPTION in packages/workflows/src/extension/workflow-prompts.ts; integration tests assert this. -->
|
|
556
556
|
|
|
557
557
|
```json
|
|
558
558
|
{
|
|
559
559
|
"name": "workflow",
|
|
560
|
-
"description": "Run named builtin, project, user, or package workflows, or direct one-off task/tasks/chain workflows; when workflow execution fits but another shape would better achieve the task, author a custom TypeScript workflow({...}) inline with normal coding tools, reload it, and run it; discover with list/get/inputs, inspect status/stages/stage details, send prompt answers or steering, pause/resume/interrupt/kill runs, and reload workflow resources. For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.",
|
|
560
|
+
"description": "Run named builtin, project, user, or package workflows, or direct one-off task/tasks/chain workflows; custom definitions may import reusable project/package workflows or builtin definitions from @bastani/workflows/builtin and nest them with ctx.workflow(...), including deeper composition within the configured maxDepth; when workflow execution fits but another shape would better achieve the task, author a custom TypeScript workflow({...}) inline with normal coding tools, reload it, and run it; discover with list/get/inputs, inspect status/stages/stage details, send prompt answers or steering, pause/resume/interrupt/kill runs, and reload workflow resources. For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.",
|
|
561
561
|
"parameters": {
|
|
562
562
|
"workflow": "string (optional) — workflow ID or normalized name",
|
|
563
563
|
"inputs": "object (optional) — key/value map of workflow inputs",
|
|
@@ -434,10 +434,10 @@ export function renderForkedOrchestratorPrompt(args: {
|
|
|
434
434
|
[
|
|
435
435
|
"output_format",
|
|
436
436
|
[
|
|
437
|
-
"After
|
|
437
|
+
"After subagents have done the work, return Markdown with headings:",
|
|
438
438
|
"1. Research file — the path you read",
|
|
439
|
-
"2. Delegations performed — subagents
|
|
440
|
-
"3. Changes made — concrete
|
|
439
|
+
"2. Delegations performed — subagents spawned and what each completed",
|
|
440
|
+
"3. Changes made — concrete changes from subagent work, not intentions",
|
|
441
441
|
"4. Files touched",
|
|
442
442
|
"5. Validation run / recommended",
|
|
443
443
|
"6. Deferred work or blockers",
|