@bastani/atomic 0.6.3 → 0.6.4

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 (49) hide show
  1. package/.agents/skills/ast-grep/SKILL.md +323 -0
  2. package/.agents/skills/ast-grep/references/rule_reference.md +297 -0
  3. package/.agents/skills/ripgrep/SKILL.md +382 -0
  4. package/.mcp.json +5 -6
  5. package/dist/commands/cli/claude-inflight-hook.d.ts +100 -0
  6. package/dist/commands/cli/claude-inflight-hook.d.ts.map +1 -0
  7. package/dist/commands/cli/claude-stop-hook.d.ts +2 -0
  8. package/dist/commands/cli/claude-stop-hook.d.ts.map +1 -1
  9. package/dist/lib/spawn.d.ts +1 -1
  10. package/dist/lib/spawn.d.ts.map +1 -1
  11. package/dist/sdk/providers/claude.d.ts +36 -0
  12. package/dist/sdk/providers/claude.d.ts.map +1 -1
  13. package/dist/sdk/providers/copilot.d.ts +17 -1
  14. package/dist/sdk/providers/copilot.d.ts.map +1 -1
  15. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  16. package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts +49 -34
  17. package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts.map +1 -1
  18. package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts +18 -16
  19. package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts.map +1 -1
  20. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/batching.d.ts +43 -0
  21. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/batching.d.ts.map +1 -0
  22. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts +30 -0
  23. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts.map +1 -1
  24. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts +2 -1
  25. package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts.map +1 -1
  26. package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts +18 -16
  27. package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +1 -1
  28. package/dist/services/config/additional-instructions.d.ts +67 -0
  29. package/dist/services/config/additional-instructions.d.ts.map +1 -0
  30. package/package.json +3 -1
  31. package/src/cli.ts +18 -1
  32. package/src/commands/cli/chat/index.ts +52 -2
  33. package/src/commands/cli/claude-inflight-hook.test.ts +598 -0
  34. package/src/commands/cli/claude-inflight-hook.ts +359 -0
  35. package/src/commands/cli/claude-stop-hook.ts +40 -4
  36. package/src/commands/cli/init/index.ts +9 -0
  37. package/src/lib/spawn.ts +6 -2
  38. package/src/sdk/providers/claude.ts +131 -0
  39. package/src/sdk/providers/copilot.ts +30 -1
  40. package/src/sdk/runtime/executor.ts +43 -2
  41. package/src/sdk/workflows/builtin/deep-research-codebase/claude/index.ts +318 -158
  42. package/src/sdk/workflows/builtin/deep-research-codebase/copilot/index.ts +253 -129
  43. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/batching.ts +65 -0
  44. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/ignore-by-default.d.ts +8 -0
  45. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.ts +203 -12
  46. package/src/sdk/workflows/builtin/deep-research-codebase/helpers/scout.ts +248 -78
  47. package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +258 -146
  48. package/src/services/config/additional-instructions.ts +273 -0
  49. package/src/services/system/auto-sync.ts +10 -1
@@ -1,10 +1,11 @@
1
1
  /**
2
- * Copilot workflow source validation.
2
+ * Copilot workflow source validation + helpers.
3
3
  *
4
4
  * Checks that Copilot workflow source files use the runtime-managed
5
5
  * `s.client` and `s.session` instead of manual SDK client creation.
6
6
  */
7
7
 
8
+ import type { SessionConfig as CopilotSessionConfig } from "@github/copilot-sdk";
8
9
  import { createProviderValidator } from "../types.ts";
9
10
 
10
11
  /**
@@ -27,6 +28,34 @@ export function copilotSubprocessEnv(): Record<string, string | undefined> {
27
28
  return { ...process.env, NODE_NO_WARNINGS: "1" };
28
29
  }
29
30
 
31
+ /**
32
+ * Fold the atomic-managed additional instructions into a caller's
33
+ * `systemMessage` value on `client.createSession`. Behavior:
34
+ *
35
+ * - **No caller value** → `{ mode: "append", content: extra }`. The
36
+ * SDK's default mode is append and preserves the SDK persona.
37
+ * - **Append/customize mode** → concatenate our content to the existing
38
+ * `content` field (newline-separated when both are present).
39
+ * - **Replace mode** → leave alone. The caller has explicitly opted out
40
+ * of SDK-managed sections; silently re-adding the persona-style append
41
+ * would violate that contract.
42
+ *
43
+ * Exported for unit testing.
44
+ */
45
+ export function mergeCopilotSystemMessage(
46
+ existing: CopilotSessionConfig["systemMessage"],
47
+ extra: string,
48
+ ): CopilotSessionConfig["systemMessage"] {
49
+ if (!extra) return existing;
50
+ if (existing === undefined) {
51
+ return { mode: "append", content: extra };
52
+ }
53
+ if (existing.mode === "replace") return existing;
54
+ const prev = existing.content ?? "";
55
+ const merged = prev ? `${prev}\n\n${extra}` : extra;
56
+ return { ...existing, content: merged };
57
+ }
58
+
30
59
  /**
31
60
  * Validate a Copilot workflow source file for common mistakes.
32
61
  */
@@ -40,6 +40,7 @@ import {
40
40
  } from "../../services/config/definitions.ts";
41
41
  import { getProviderOverrides } from "../../services/config/atomic-config.ts";
42
42
  import { getCopilotScmDisableFlags } from "../../services/config/scm-sync.ts";
43
+ import { reconcileOpencodeInstructions } from "../../services/config/additional-instructions.ts";
43
44
  import { ensureDir } from "../../services/system/copy.ts";
44
45
  import type { SessionEvent } from "@github/copilot-sdk";
45
46
  import type { SessionPromptResponse } from "@opencode-ai/sdk/v2";
@@ -481,6 +482,19 @@ export async function executeWorkflow(
481
482
  detach = false,
482
483
  } = options;
483
484
 
485
+ // OpenCode reads its `instructions` array from `.opencode/opencode.json`
486
+ // at server-start time — both for the interactive tmux-pane path and the
487
+ // headless `createOpencode({ port: 0 })` path. Reconcile here, before
488
+ // either spawn, so the resolved AGENTS.md is the source of truth on
489
+ // every workflow run. Best-effort: a malformed config shouldn't block.
490
+ if (agent === "opencode") {
491
+ try {
492
+ await reconcileOpencodeInstructions(projectRoot);
493
+ } catch {
494
+ /* swallow */
495
+ }
496
+ }
497
+
484
498
  const workflowRunId = generateId();
485
499
  const tmuxSessionName = `atomic-wf-${agent}-${definition.name}-${workflowRunId}`;
486
500
  const sessionsBaseDir = join(getSessionsBaseDir(), workflowRunId);
@@ -1174,6 +1188,14 @@ function createMessagesReader(
1174
1188
  interface SharedRunnerState {
1175
1189
  tmuxSessionName: string;
1176
1190
  sessionsBaseDir: string;
1191
+ /**
1192
+ * The project root the workflow is operating against. Threaded through to
1193
+ * provider initialization so headless paths resolve project-scoped config
1194
+ * (e.g. `additional-instructions`) from the workflow's actual root rather
1195
+ * than `process.cwd()`, which can drift when workflows are invoked
1196
+ * programmatically or from a subdirectory.
1197
+ */
1198
+ projectRoot: string;
1177
1199
  agent: AgentType;
1178
1200
  /**
1179
1201
  * Structured inputs for this workflow run. Free-form workflows use
@@ -1270,6 +1292,7 @@ async function initProviderClientAndSession<A extends AgentType>(
1270
1292
  agent: A,
1271
1293
  serverUrl: string,
1272
1294
  paneId: string,
1295
+ projectRoot: string,
1273
1296
  clientOpts: StageClientOptions<A>,
1274
1297
  sessionOpts: StageSessionOptions<A>,
1275
1298
  headless = false,
@@ -1289,7 +1312,12 @@ async function initProviderClientAndSession<A extends AgentType>(
1289
1312
  switch (agent) {
1290
1313
  case "copilot": {
1291
1314
  const { CopilotClient, approveAll } = await import("@github/copilot-sdk");
1292
- const { copilotSubprocessEnv } = await import("../providers/copilot.ts");
1315
+ const { copilotSubprocessEnv, mergeCopilotSystemMessage } = await import(
1316
+ "../providers/copilot.ts"
1317
+ );
1318
+ const { resolveAdditionalInstructionsContent } = await import(
1319
+ "../../services/config/additional-instructions.ts"
1320
+ );
1293
1321
  const copilotClientOpts = clientOpts as StageClientOptions<"copilot">;
1294
1322
  const copilotSessionOpts = sessionOpts as StageSessionOptions<"copilot">;
1295
1323
  // Headless: let the SDK spawn its own CLI process (no cliUrl).
@@ -1320,6 +1348,9 @@ async function initProviderClientAndSession<A extends AgentType>(
1320
1348
  // In headless stages, add `ask_user` to the session's excludedTools so
1321
1349
  // the agent cannot call the interactive question tool — there is no
1322
1350
  // human attached to answer and the SDK would otherwise sit blocked.
1351
+ const additionalInstructions = await resolveAdditionalInstructionsContent(
1352
+ projectRoot,
1353
+ );
1323
1354
  const sessionConfig = {
1324
1355
  onPermissionRequest: approveAll,
1325
1356
  ...copilotSessionOpts,
@@ -1334,6 +1365,14 @@ async function initProviderClientAndSession<A extends AgentType>(
1334
1365
  ),
1335
1366
  }
1336
1367
  : {}),
1368
+ ...(additionalInstructions
1369
+ ? {
1370
+ systemMessage: mergeCopilotSystemMessage(
1371
+ copilotSessionOpts.systemMessage,
1372
+ additionalInstructions,
1373
+ ),
1374
+ }
1375
+ : {}),
1337
1376
  };
1338
1377
  const session = await client.createSession(sessionConfig);
1339
1378
  if (!headless) {
@@ -1379,7 +1418,7 @@ async function initProviderClientAndSession<A extends AgentType>(
1379
1418
  // tracks the latest one and exposes it as `sessionId`.
1380
1419
  const client = new HeadlessClaudeClientWrapper();
1381
1420
  await client.start();
1382
- const session = new HeadlessClaudeSessionWrapper();
1421
+ const session = new HeadlessClaudeSessionWrapper(projectRoot);
1383
1422
  // Cast through `unknown` — `HeadlessClaudeClientWrapper` intentionally
1384
1423
  // omits the interactive-only fields (`paneId`, `sessionDir`, etc.)
1385
1424
  // that `ClaudeClientWrapper` has; both satisfy the same runtime
@@ -1661,6 +1700,7 @@ function createSessionRunner(
1661
1700
  shared.agent,
1662
1701
  serverUrl,
1663
1702
  paneId,
1703
+ shared.projectRoot,
1664
1704
  clientOpts,
1665
1705
  sessionOpts,
1666
1706
  isHeadless,
@@ -2002,6 +2042,7 @@ export async function runOrchestrator(
2002
2042
  const shared: SharedRunnerState = {
2003
2043
  tmuxSessionName,
2004
2044
  sessionsBaseDir,
2045
+ projectRoot: cwd,
2005
2046
  agent,
2006
2047
  inputs,
2007
2048
  providerOverrides,