@structured-vibe-coding/core 0.6.1 → 0.7.0

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.
@@ -5,16 +5,21 @@ import {
5
5
  DEFAULT_INIT_INTEGRATION,
6
6
  PROTOCOL_MD,
7
7
  SDD_AGENT_ROLES,
8
+ agentHostPaths,
9
+ agentKickoffMessage,
8
10
  getIntegration,
9
11
  installAgentIntegration,
10
12
  installAgentIntegrations,
11
13
  integrationKeyFor,
14
+ loadInstalledAgent,
12
15
  optionForTarget,
13
16
  parseAgentTargets,
14
17
  parseIntegration,
15
18
  refreshActiveAgentContext,
16
- renderThinAgent
17
- } from "./chunk-QTHYRKMK.js";
19
+ removeOtherAgentHosts,
20
+ renderThinAgent,
21
+ writeAgentHandoff
22
+ } from "./chunk-4ZDPIYEB.js";
18
23
  export {
19
24
  AGENT_INTEGRATIONS,
20
25
  AGENT_TARGET_OPTIONS,
@@ -22,13 +27,18 @@ export {
22
27
  DEFAULT_INIT_INTEGRATION,
23
28
  PROTOCOL_MD,
24
29
  SDD_AGENT_ROLES,
30
+ agentHostPaths,
31
+ agentKickoffMessage,
25
32
  getIntegration,
26
33
  installAgentIntegration,
27
34
  installAgentIntegrations,
28
35
  integrationKeyFor,
36
+ loadInstalledAgent,
29
37
  optionForTarget,
30
38
  parseAgentTargets,
31
39
  parseIntegration,
32
40
  refreshActiveAgentContext,
33
- renderThinAgent
41
+ removeOtherAgentHosts,
42
+ renderThinAgent,
43
+ writeAgentHandoff
34
44
  };
@@ -686,6 +686,54 @@ function integrationKeyFor(target) {
686
686
  function optionForTarget(target) {
687
687
  return getIntegration(target);
688
688
  }
689
+ function agentHostPaths(target) {
690
+ switch (target) {
691
+ case "copilot":
692
+ return [".github/agents"];
693
+ case "claude-code":
694
+ return [".claude/agents"];
695
+ case "grok":
696
+ return [".grok/rules"];
697
+ default:
698
+ return [];
699
+ }
700
+ }
701
+ var LEGACY_AGENT_PATHS = [".idea/sdd-agent-notes.md"];
702
+ async function removeOtherAgentHosts(projectRoot, keep) {
703
+ const removed = [];
704
+ for (const integ of AGENT_INTEGRATIONS) {
705
+ if (integ.id === keep) continue;
706
+ for (const rel of agentHostPaths(integ.id)) {
707
+ const full = join4(projectRoot, rel);
708
+ if (await pathExists(full)) {
709
+ await removePath(full);
710
+ removed.push(rel);
711
+ }
712
+ }
713
+ }
714
+ for (const rel of LEGACY_AGENT_PATHS) {
715
+ const full = join4(projectRoot, rel);
716
+ if (await pathExists(full)) {
717
+ await removePath(full);
718
+ removed.push(rel);
719
+ }
720
+ }
721
+ for (const parent of [".claude", ".idea", ".grok"]) {
722
+ if (keep === "grok" && parent === ".grok") continue;
723
+ const full = join4(projectRoot, parent);
724
+ if (!await pathExists(full)) continue;
725
+ try {
726
+ const { readdir } = await import("fs/promises");
727
+ const kids = await readdir(full);
728
+ if (kids.length === 0) {
729
+ await removePath(full);
730
+ removed.push(parent);
731
+ }
732
+ } catch {
733
+ }
734
+ }
735
+ return removed;
736
+ }
689
737
  function parseIntegration(raw) {
690
738
  const p = raw.trim().toLowerCase();
691
739
  if (!p) {
@@ -764,6 +812,7 @@ async function installAgentIntegration(opts) {
764
812
  const skipped = [];
765
813
  const root = opts.projectRoot;
766
814
  const force = opts.force ?? false;
815
+ await removeOtherAgentHosts(root, opts.target);
767
816
  const write = async (rel, content) => {
768
817
  const full = join4(root, rel);
769
818
  if (await pathExists(full) && !force) {
@@ -847,6 +896,47 @@ Remind the human: \`sdd verify\` then \`sdd next\` / \`sdd complete\` as appropr
847
896
  Do not claim the change is complete without local verification when the workflow requires it.
848
897
  `;
849
898
  }
899
+ async function loadInstalledAgent(projectRoot) {
900
+ const path = join4(sddRoot(projectRoot), "agents.json");
901
+ if (!await pathExists(path)) return null;
902
+ try {
903
+ const raw = JSON.parse(await readText(path));
904
+ const key = raw.ai ?? raw.integration ?? raw.installed?.[0];
905
+ if (!key || typeof key !== "string") return null;
906
+ const target = parseIntegration(key);
907
+ return { ai: integrationKeyFor(target), target, integration: getIntegration(target) };
908
+ } catch {
909
+ return null;
910
+ }
911
+ }
912
+ async function writeAgentHandoff(projectRoot, config, changeId) {
913
+ const ctx = await buildContext(projectRoot, config, changeId);
914
+ const body = await buildAgentPrompt(ctx, config, projectRoot);
915
+ const outPath = join4(sddRoot(projectRoot), "handoff.md");
916
+ const header = `# SDD handoff (auto)
917
+
918
+ > Generated for the AI coding agent configured at init.
919
+ > Change: **${ctx.meta.title}** \xB7 \`${ctx.id}\` \xB7 stage **${ctx.meta.stage}**
920
+
921
+ Also read: \`.sdd/active-context.md\`, \`.sdd/protocol.md\`, \`memory/constitution.md\` if present.
922
+
923
+ ---
924
+
925
+ `;
926
+ await writeText(outPath, header + body + "\n");
927
+ return outPath;
928
+ }
929
+ function agentKickoffMessage(opts) {
930
+ return [
931
+ `SDD: new change started.`,
932
+ `Title: ${opts.title}`,
933
+ `Change: ${opts.changeId}`,
934
+ `Stage: ${opts.stage}`,
935
+ `Read in order: .sdd/active-context.md, .sdd/handoff.md, .sdd/protocol.md, memory/constitution.md (if present).`,
936
+ `Fill/update current stage artifacts only under changes/${opts.changeId}/. Do not expand scope.`,
937
+ `When the stage is done, tell the human to run: sdd next`
938
+ ].join(" ");
939
+ }
850
940
  async function refreshActiveAgentContext(projectRoot) {
851
941
  const markerDir = sddRoot(projectRoot);
852
942
  if (!await pathExists(join4(markerDir, "config.yaml"))) {
@@ -1034,12 +1124,17 @@ export {
1034
1124
  getIntegration,
1035
1125
  integrationKeyFor,
1036
1126
  optionForTarget,
1127
+ agentHostPaths,
1128
+ removeOtherAgentHosts,
1037
1129
  parseIntegration,
1038
1130
  parseAgentTargets,
1039
1131
  SDD_AGENT_ROLES,
1040
1132
  installAgentIntegration,
1041
1133
  installAgentIntegrations,
1042
1134
  renderThinAgent,
1135
+ loadInstalledAgent,
1136
+ writeAgentHandoff,
1137
+ agentKickoffMessage,
1043
1138
  refreshActiveAgentContext,
1044
1139
  PROTOCOL_MD
1045
1140
  };
package/dist/index.d.ts CHANGED
@@ -1197,6 +1197,16 @@ declare const AGENT_TARGET_OPTIONS: AgentTargetOption[];
1197
1197
  declare function getIntegration(target: AgentTarget): AgentIntegration;
1198
1198
  declare function integrationKeyFor(target: AgentTarget): string;
1199
1199
  declare function optionForTarget(target: AgentTarget): AgentTargetOption;
1200
+ /**
1201
+ * Paths this integration owns (safe to delete when switching agents).
1202
+ * Never includes shared SDD dirs (memory, changes, .sdd) or whole .github (workflows stay).
1203
+ */
1204
+ declare function agentHostPaths(target: AgentTarget): string[];
1205
+ /**
1206
+ * Remove agent files for hosts other than `keep` (and legacy IntelliJ notes).
1207
+ * Does not touch .sdd/, memory/, changes/, or non-agent .github content.
1208
+ */
1209
+ declare function removeOtherAgentHosts(projectRoot: string, keep: AgentTarget): Promise<string[]>;
1200
1210
  /** Parse one Speckit-style integration key. */
1201
1211
  declare function parseIntegration(raw: string): AgentTarget;
1202
1212
  /**
@@ -1248,6 +1258,25 @@ declare function installAgentIntegration(opts: InstallAgentOptions): Promise<Ins
1248
1258
  declare function installAgentIntegrations(opts: InstallAgentsOptions): Promise<InstallAgentsResult>;
1249
1259
  /** Thin agent body shared across hosts (same text). */
1250
1260
  declare function renderThinAgent(role: SddAgentRole): string;
1261
+ interface InstalledAgentSnapshot {
1262
+ /** Public key: copilot | claude | grok */
1263
+ ai: string;
1264
+ target: AgentTarget;
1265
+ integration: AgentIntegration;
1266
+ }
1267
+ /** Read which AI agent was configured at `sdd init` / last agents install. */
1268
+ declare function loadInstalledAgent(projectRoot: string): Promise<InstalledAgentSnapshot | null>;
1269
+ /**
1270
+ * Write `.sdd/handoff.md` for the active (or given) change — full agent brief.
1271
+ * Used by `sdd agent` and auto-launch after `sdd new`.
1272
+ */
1273
+ declare function writeAgentHandoff(projectRoot: string, config: Config, changeId: string): Promise<string>;
1274
+ /** Short kickoff line to pass into agent CLIs (full brief is in handoff.md). */
1275
+ declare function agentKickoffMessage(opts: {
1276
+ title: string;
1277
+ stage: string;
1278
+ changeId: string;
1279
+ }): string;
1251
1280
  /** Write .sdd/active-context.md for the current change. */
1252
1281
  declare function refreshActiveAgentContext(projectRoot: string): Promise<string | null>;
1253
1282
  /** Single playbook — only long agent-facing content we author once. */
@@ -1319,4 +1348,4 @@ declare function listFiles(path: string): Promise<string[]>;
1319
1348
  declare function copyDir(src: string, dest: string): Promise<void>;
1320
1349
  declare function removePath(path: string): Promise<void>;
1321
1350
 
1322
- export { AGENT_INTEGRATIONS, AGENT_TARGET_OPTIONS, ALL_AGENT_TARGETS, type AdvanceResult, type AgentIntegration, type AgentTarget, type AgentTargetOption, type ArtifactDef, ArtifactDefSchema, type ChangeContext, type ChangeMeta, ChangeMetaSchema, type Complexity, type Config, ConfigSchema, type CreateChangeInput, DEFAULT_INIT_INTEGRATION, type Gate, GateSchema, type InitOptions, type InitResult, type InstallAgentOptions, type InstallAgentResult, type InstallAgentsOptions, type InstallAgentsResult, PROTOCOL_MD, SDD_AGENT_ROLES, SDD_DIR, type SddAgentRole, type SddAgentRoleId, type Stage, StageSchema, VerifyCommandSchema, type VerifyResult, type Workflow, WorkflowSchema, activePointerPath, activeStages, advanceStage, approveGate, archiveDir, buildAgentPrompt, buildContext, canLeaveStage, changeDirName, changeMetaPath, changePath, changesDir, clearActiveIf, completeChange, configPath, copyDir, createChange, defaultConfig, defaultMemoryDir, defaultTemplatesDir, defaultWorkflowsDir, defaultsRoot, domainsDir, ensureDir, firstActiveStageId, formatStatus, getActiveChangeId, getIntegration, getStage, inferComplexity, initProject, installAgentIntegration, installAgentIntegrations, integrationKeyFor, isInitialized, isStageSkipped, listChanges, listDirs, listFiles, listWorkflowNames, loadChangeMeta, loadConfig, loadWorkflow, memoryDir, nextStageId, nowIso, optionForTarget, parseAgentTargets, parseIntegration, pathExists, readText, readYaml, recommendWorkflow, refreshActiveAgentContext, removePath, renderThinAgent, resolveChangeId, resolveStages, runLocalVerify, saveChangeMeta, saveConfig, sddRoot, setActiveChange, shouldAutoSkip, skipStage, slugify, switchWorkflow, templatesDir, todayIsoDate, uniqueChangeDirName, workflowsDir, writeText, writeYaml };
1351
+ export { AGENT_INTEGRATIONS, AGENT_TARGET_OPTIONS, ALL_AGENT_TARGETS, type AdvanceResult, type AgentIntegration, type AgentTarget, type AgentTargetOption, type ArtifactDef, ArtifactDefSchema, type ChangeContext, type ChangeMeta, ChangeMetaSchema, type Complexity, type Config, ConfigSchema, type CreateChangeInput, DEFAULT_INIT_INTEGRATION, type Gate, GateSchema, type InitOptions, type InitResult, type InstallAgentOptions, type InstallAgentResult, type InstallAgentsOptions, type InstallAgentsResult, type InstalledAgentSnapshot, PROTOCOL_MD, SDD_AGENT_ROLES, SDD_DIR, type SddAgentRole, type SddAgentRoleId, type Stage, StageSchema, VerifyCommandSchema, type VerifyResult, type Workflow, WorkflowSchema, activePointerPath, activeStages, advanceStage, agentHostPaths, agentKickoffMessage, approveGate, archiveDir, buildAgentPrompt, buildContext, canLeaveStage, changeDirName, changeMetaPath, changePath, changesDir, clearActiveIf, completeChange, configPath, copyDir, createChange, defaultConfig, defaultMemoryDir, defaultTemplatesDir, defaultWorkflowsDir, defaultsRoot, domainsDir, ensureDir, firstActiveStageId, formatStatus, getActiveChangeId, getIntegration, getStage, inferComplexity, initProject, installAgentIntegration, installAgentIntegrations, integrationKeyFor, isInitialized, isStageSkipped, listChanges, listDirs, listFiles, listWorkflowNames, loadChangeMeta, loadConfig, loadInstalledAgent, loadWorkflow, memoryDir, nextStageId, nowIso, optionForTarget, parseAgentTargets, parseIntegration, pathExists, readText, readYaml, recommendWorkflow, refreshActiveAgentContext, removeOtherAgentHosts, removePath, renderThinAgent, resolveChangeId, resolveStages, runLocalVerify, saveChangeMeta, saveConfig, sddRoot, setActiveChange, shouldAutoSkip, skipStage, slugify, switchWorkflow, templatesDir, todayIsoDate, uniqueChangeDirName, workflowsDir, writeAgentHandoff, writeText, writeYaml };
package/dist/index.js CHANGED
@@ -15,6 +15,8 @@ import {
15
15
  WorkflowSchema,
16
16
  activePointerPath,
17
17
  activeStages,
18
+ agentHostPaths,
19
+ agentKickoffMessage,
18
20
  archiveDir,
19
21
  buildAgentPrompt,
20
22
  buildContext,
@@ -45,6 +47,7 @@ import {
45
47
  listWorkflowNames,
46
48
  loadChangeMeta,
47
49
  loadConfig,
50
+ loadInstalledAgent,
48
51
  loadWorkflow,
49
52
  memoryDir,
50
53
  nextStageId,
@@ -57,6 +60,7 @@ import {
57
60
  readYaml,
58
61
  recommendWorkflow,
59
62
  refreshActiveAgentContext,
63
+ removeOtherAgentHosts,
60
64
  removePath,
61
65
  renderThinAgent,
62
66
  resolveChangeId,
@@ -71,9 +75,10 @@ import {
71
75
  todayIsoDate,
72
76
  uniqueChangeDirName,
73
77
  workflowsDir,
78
+ writeAgentHandoff,
74
79
  writeText,
75
80
  writeYaml
76
- } from "./chunk-QTHYRKMK.js";
81
+ } from "./chunk-4ZDPIYEB.js";
77
82
 
78
83
  // src/change.ts
79
84
  import { join as join2 } from "pathe";
@@ -185,7 +190,7 @@ async function createChange(input) {
185
190
  await materializeStageArtifacts(projectRoot, config, id, workflow, meta, firstStage);
186
191
  await setActiveChange(projectRoot, config, id);
187
192
  try {
188
- const { refreshActiveAgentContext: refreshActiveAgentContext2 } = await import("./agents-O5ABMQJQ.js");
193
+ const { refreshActiveAgentContext: refreshActiveAgentContext2 } = await import("./agents-TN7TOYF7.js");
189
194
  await refreshActiveAgentContext2(projectRoot);
190
195
  } catch {
191
196
  }
@@ -281,7 +286,7 @@ async function advanceStage(projectRoot, config, changeId, opts) {
281
286
  stage
282
287
  );
283
288
  try {
284
- const { refreshActiveAgentContext: refreshActiveAgentContext2 } = await import("./agents-O5ABMQJQ.js");
289
+ const { refreshActiveAgentContext: refreshActiveAgentContext2 } = await import("./agents-TN7TOYF7.js");
285
290
  await refreshActiveAgentContext2(projectRoot);
286
291
  } catch {
287
292
  }
@@ -708,6 +713,8 @@ export {
708
713
  activePointerPath,
709
714
  activeStages,
710
715
  advanceStage,
716
+ agentHostPaths,
717
+ agentKickoffMessage,
711
718
  approveGate,
712
719
  archiveDir,
713
720
  buildAgentPrompt,
@@ -747,6 +754,7 @@ export {
747
754
  listWorkflowNames,
748
755
  loadChangeMeta,
749
756
  loadConfig,
757
+ loadInstalledAgent,
750
758
  loadWorkflow,
751
759
  memoryDir,
752
760
  nextStageId,
@@ -759,6 +767,7 @@ export {
759
767
  readYaml,
760
768
  recommendWorkflow,
761
769
  refreshActiveAgentContext,
770
+ removeOtherAgentHosts,
762
771
  removePath,
763
772
  renderThinAgent,
764
773
  resolveChangeId,
@@ -776,6 +785,7 @@ export {
776
785
  todayIsoDate,
777
786
  uniqueChangeDirName,
778
787
  workflowsDir,
788
+ writeAgentHandoff,
779
789
  writeText,
780
790
  writeYaml
781
791
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@structured-vibe-coding/core",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Core engine for structured vibe coding (local-first Spec-Driven Development)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",