synarcx 0.3.2 → 0.3.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.
package/README.md CHANGED
@@ -92,7 +92,7 @@ Then in your AI coding tool:
92
92
  3. `/syn:propose "my-feature"` — create proposal, specs, design, and tasks in one step
93
93
  4. `/syn:clarify` — sharpen artifacts with targeted questions + auto consistency check
94
94
  5. `/syn:apply` — implement the tasks
95
- 6. `/syn:review` — verify implementation, run sanity checks, and archive when clean
95
+ 6. `/syn:review` — verify implementation, run sanity checks, then choose: archive (auto spec sync), add more work (scope-gated), or start a new change
96
96
 
97
97
  For specific cases, use these instead of `/syn:explore`:
98
98
 
@@ -126,22 +126,32 @@ Session 1 ──► constitution.md ──► Session 2 ──► constitu
126
126
  **The workflow:**
127
127
 
128
128
  ```
129
- sync ─────────────────────────────────────► constitution
130
-
131
- explore ──┐
132
- debug ──┤
133
- ├──► propose ──► clarify ──► apply ──► review
134
- └── (auto-analyze) ──┘
135
- refactor ──┘
136
-
137
- quick ───────────────────────────────────────────► apply
129
+ quick ─────────────────────────────────────┐
130
+
131
+ explore ──┐
132
+ debug ──┤
133
+ ├───► propose ──► clarify ──► apply ──► review
134
+ ▲ ▲ │
135
+ refactor ──┘ │ │ │
136
+ │ │ │
137
+ │ │ ┌───────────────┼───────────────┐
138
+ │ │ ▼ ▼ ▼
139
+ │ add more work new change archive
140
+ │ │ │
141
+ └─────────────────────────────────┘ ▼
142
+ sync ──────────────────────────────────────────────────────────► constitution
138
143
  ```
139
144
 
140
145
  Each step suggests the next — you decide when to advance. Works in Claude Code, Cursor, Cline, and any AI coding tool that supports slash commands.
141
146
 
142
- - `sync` generates the `constitution.md` — run once, re-run when the project shifts. Also runs a daily version check: if a newer synarcx is available, prompts to auto-update inline.
147
+ - `sync` generates the `constitution.md` — run once, re-run when the project shifts. Also runs a daily version check (prompts to auto-update) and checks for pending spec syncs from recently archived changes.
143
148
  - `explore`, `debug`, and `refactor` are entry points that hand off to `propose`
144
149
  - `quick` skips the pipeline for small, low-risk changes
150
+ - Run `synarcx update` in your terminal to refresh all skill and command files after installing a new version
151
+ - `review` is a three-way fork:
152
+ - **Archive now**: auto-syncs delta specs to main spec via `buildUpdatedSpec()`, writes `.pending-sync.json` marker, moves to archive. If spec sync fails, the change is already safely in archive; retry on next sync run.
153
+ - **Add more work**: scope gate reads proposal capabilities + design goals/non-goals. In-scope → update artifacts, MUST `/syn:clarify` then `/syn:apply` then `/syn:review` again (loop). Out-of-scope → offer archive then route to `/syn:propose`.
154
+ - **Start a new change**: routes to `/syn:propose`.
145
155
 
146
156
  Each change gets its own folder under `synspec/changes/` with:
147
157
 
@@ -183,35 +193,35 @@ A typical `constitution.md` includes:
183
193
 
184
194
  Used inside your AI coding tool (Claude Code, Cursor, Cline, etc.):
185
195
 
186
- | Command | Description |
187
- | ----------------- | ------------------------------------------------------------------------ |
188
- | `/syn:sync` | Scan project, run guardrail Q&A, generate/update `constitution.md`. Auto-checks for synarcx updates once daily. |
189
- | `/syn:explore` | Think through ideas, investigate problems, clarify requirements |
190
- | `/syn:debug` | Diagnose a known error (3-phase analysis), then prompts `/syn:propose` |
191
- | `/syn:refactor` | Map current vs target structure, then prompts `/syn:propose` |
192
- | `/syn:quick` | Fast-path for small low-risk changes — inline preview, confirm, apply |
193
- | `/syn:propose` | Create a new change with proposal, specs, design, and tasks |
194
- | `/syn:clarify` | Targeted Q&A (adaptive limit) + auto consistency checks in one command |
195
- | `/syn:analyze` | Standalone cross-artifact consistency check (auto-run by clarify) |
196
- | `/syn:apply` | Implement tasks from a change's task list |
197
- | `/syn:review` | Verify implementation, run sanity checks, and archive when clean |
196
+ | Command | Description |
197
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
198
+ | `/syn:sync` | Scan project, run guardrail Q&A, generate/update `constitution.md`. Checks pending spec syncs from archived changes first. Auto-checks for synarcx updates once daily. |
199
+ | `/syn:explore` | Think through ideas, investigate problems, clarify requirements |
200
+ | `/syn:debug` | Diagnose a known error (3-phase analysis), then prompts `/syn:propose` |
201
+ | `/syn:refactor` | Map current vs target structure, then prompts `/syn:propose` |
202
+ | `/syn:quick` | Fast-path for small low-risk changes — inline preview, confirm, apply |
203
+ | `/syn:propose` | Create a new change with proposal, specs, design, and tasks |
204
+ | `/syn:clarify` | Targeted Q&A (adaptive limit) + auto consistency checks in one command |
205
+ | `/syn:analyze` | Standalone cross-artifact consistency check (auto-run by clarify) |
206
+ | `/syn:apply` | Implement tasks from a change's task list |
207
+ | `/syn:review` | Verify implementation, run sanity checks, and three-way fork: archive (auto spec sync), add more work (scope gate), or start new change |
198
208
 
199
209
  ### CLI Commands
200
210
 
201
211
  Used in your terminal:
202
212
 
203
- | Command | Description |
204
- | ------------------- | ------------------------------------------------------- |
205
- | `synarcx init` | Set up SynArcX workflow structure in your repository |
206
- | `synarcx update` | Refresh skill and command files for all configured tools |
207
- | `synarcx sync` | Regenerate `constitution.md` |
208
- | `synarcx explore` | Open explore session |
209
- | `synarcx propose` | Create a structured change proposal |
210
- | `synarcx clarify` | Targeted Q&A (adaptive limit) + auto consistency checks |
211
- | `synarcx analyze` | Cross-artifact consistency check (standalone) |
212
- | `synarcx apply` | Execute implementation tasks |
213
+ | Command | Description |
214
+ | ------------------- | ------------------------------------------------------------ |
215
+ | `synarcx init` | Set up SynArcX workflow structure in your repository |
216
+ | `synarcx update` | Refresh skill and command files for all configured tools |
217
+ | `synarcx sync` | Regenerate `constitution.md` |
218
+ | `synarcx explore` | Open explore session |
219
+ | `synarcx propose` | Create a structured change proposal |
220
+ | `synarcx clarify` | Targeted Q&A (adaptive limit) + auto consistency checks |
221
+ | `synarcx analyze` | Cross-artifact consistency check (standalone) |
222
+ | `synarcx apply` | Execute implementation tasks |
213
223
  | `synarcx review` | Verify implementation, run sanity checks, archive when clean |
214
- | `synarcx quick` | Fast-path execution for small changes |
224
+ | `synarcx quick` | Fast-path execution for small changes |
215
225
 
216
226
  ---
217
227
 
@@ -266,7 +276,7 @@ SynArcX is evolving toward an architecture-aware workflow system for long-runnin
266
276
 
267
277
  ## Status
268
278
 
269
- **v0.3.x** — `syn:review` added as the terminal quality gate (verify implementation, run sanity checks, three-way fork: archive, add work, or start fresh); seamless upgrade from v0.2.x (auto-migrates to `core` profile so new commands appear without any manual steps); clarify+analyze merged, adaptive Q&A limit, quick command, debug/refactor guardrail alignment
279
+ **v0.3.x** — `syn:review` three-way fork (archive with auto spec sync, scope-gated add-more-work, or start new change); `syn:sync` extended with pending spec sync backstop for recently archived changes; archive writes `.pending-sync.json` marker consumed by sync; atomic spec writes prevent half-written corruption; retroactive fix for broken main spec format; seamless upgrade from v0.2.x (auto-migrates to `core` profile)
270
280
 
271
281
  Active development roadmap:
272
282
 
@@ -4,32 +4,32 @@ export const SYNSPEC_MARKERS = {
4
4
  end: '<!-- SYNSPEC:END -->'
5
5
  };
6
6
  export const AI_TOOLS = [
7
- { name: 'Amazon Q Developer', value: 'amazon-q', available: true, successLabel: 'Amazon Q Developer', skillsDir: '.amazonq' },
8
- { name: 'Antigravity', value: 'antigravity', available: true, successLabel: 'Antigravity', skillsDir: '.agent' },
9
- { name: 'Auggie (Augment CLI)', value: 'auggie', available: true, successLabel: 'Auggie', skillsDir: '.augment' },
10
- { name: 'Bob Shell', value: 'bob', available: true, successLabel: 'Bob Shell', skillsDir: '.bob' },
7
+ { name: 'Amazon Q Developer', value: 'amazon-q', available: true, successLabel: 'Amazon Q Developer', skillsDir: '.amazonq', hasCommands: true },
8
+ { name: 'Antigravity', value: 'antigravity', available: true, successLabel: 'Antigravity', skillsDir: '.agent', hasCommands: true },
9
+ { name: 'Auggie (Augment CLI)', value: 'auggie', available: true, successLabel: 'Auggie', skillsDir: '.augment', hasCommands: true },
10
+ { name: 'Bob Shell', value: 'bob', available: true, successLabel: 'Bob Shell', skillsDir: '.bob', hasCommands: true },
11
11
  { name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code', skillsDir: '.claude', hasCommands: true },
12
- { name: 'Cline', value: 'cline', available: true, successLabel: 'Cline', skillsDir: '.cline' },
13
- { name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.codex' },
14
- { name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code', skillsDir: '.codebuddy' },
15
- { name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)', skillsDir: '.continue' },
16
- { name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict', skillsDir: '.cospec' },
17
- { name: 'Crush', value: 'crush', available: true, successLabel: 'Crush', skillsDir: '.crush' },
18
- { name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor', skillsDir: '.cursor' },
19
- { name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid', skillsDir: '.factory' },
20
- { name: 'Gemini CLI', value: 'gemini', available: true, successLabel: 'Gemini CLI', skillsDir: '.gemini' },
21
- { name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot', skillsDir: '.github', detectionPaths: ['.github/copilot-instructions.md', '.github/instructions', '.github/workflows/copilot-setup-steps.yml', '.github/prompts', '.github/agents', '.github/skills', '.github/.mcp.json'] },
22
- { name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow' },
23
- { name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie' },
24
- { name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode' },
25
- { name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro' },
12
+ { name: 'Cline', value: 'cline', available: true, successLabel: 'Cline', skillsDir: '.cline', hasCommands: true },
13
+ { name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.codex', hasCommands: true },
14
+ { name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code', skillsDir: '.codebuddy', hasCommands: true },
15
+ { name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)', skillsDir: '.continue', hasCommands: true },
16
+ { name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict', skillsDir: '.cospec', hasCommands: true },
17
+ { name: 'Crush', value: 'crush', available: true, successLabel: 'Crush', skillsDir: '.crush', hasCommands: true },
18
+ { name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor', skillsDir: '.cursor', hasCommands: true },
19
+ { name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid', skillsDir: '.factory', hasCommands: true },
20
+ { name: 'Gemini CLI', value: 'gemini', available: true, successLabel: 'Gemini CLI', skillsDir: '.gemini', hasCommands: true },
21
+ { name: 'GitHub Copilot', value: 'github-copilot', available: true, successLabel: 'GitHub Copilot', skillsDir: '.github', detectionPaths: ['.github/copilot-instructions.md', '.github/instructions', '.github/workflows/copilot-setup-steps.yml', '.github/prompts', '.github/agents', '.github/skills', '.github/.mcp.json'], hasCommands: true },
22
+ { name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow', hasCommands: true },
23
+ { name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie', hasCommands: true },
24
+ { name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode', hasCommands: true },
25
+ { name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro', hasCommands: true },
26
26
  { name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode', skillsDir: '.opencode', hasCommands: true },
27
- { name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi' },
28
- { name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder' },
29
- { name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma' },
30
- { name: 'Qwen Code', value: 'qwen', available: true, successLabel: 'Qwen Code', skillsDir: '.qwen' },
31
- { name: 'RooCode', value: 'roocode', available: true, successLabel: 'RooCode', skillsDir: '.roo' },
32
- { name: 'Windsurf', value: 'windsurf', available: true, successLabel: 'Windsurf', skillsDir: '.windsurf' },
27
+ { name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi', hasCommands: true },
28
+ { name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder', hasCommands: true },
29
+ { name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma', hasCommands: true },
30
+ { name: 'Qwen Code', value: 'qwen', available: true, successLabel: 'Qwen Code', skillsDir: '.qwen', hasCommands: true },
31
+ { name: 'RooCode', value: 'roocode', available: true, successLabel: 'RooCode', skillsDir: '.roo', hasCommands: true },
32
+ { name: 'Windsurf', value: 'windsurf', available: true, successLabel: 'Windsurf', skillsDir: '.windsurf', hasCommands: true },
33
33
  { name: 'AGENTS.md (works with Amp, VS Code, …)', value: 'agents', available: false, successLabel: 'your AGENTS.md-compatible assistant' }
34
34
  ];
35
35
  //# sourceMappingURL=config.js.map
package/dist/core/init.js CHANGED
@@ -19,7 +19,7 @@ import { generateCommands, CommandAdapterRegistry, } from './command-generation/
19
19
  import { detectLegacyArtifacts, cleanupLegacyArtifacts, formatCleanupSummary, formatDetectionSummary, } from './legacy-cleanup.js';
20
20
  import { getToolsWithSkillsDir, getToolStates, getSkillTemplates, getCommandContents, generateSkillContent, } from './shared/index.js';
21
21
  import { getGlobalConfig } from './global-config.js';
22
- import { getProfileWorkflows } from './profiles.js';
22
+ import { getProfileWorkflows, syncNewCoreWorkflowsToCustomProfile } from './profiles.js';
23
23
  import { DEFAULT_SCHEMA } from './shared/workflow-registry.js';
24
24
  import { removeSkillDirs, removeCommandFiles } from './shared/artifact-cleanup.js';
25
25
  import { getAvailableTools } from './available-tools.js';
@@ -60,6 +60,9 @@ export class InitCommand {
60
60
  // Migration check: migrate existing projects to profile system (task 7.3)
61
61
  if (extendMode) {
62
62
  migrateIfNeeded(projectPath, detectedTools);
63
+ // Ensure custom-profile users receive any new commands added since their last init
64
+ // (e.g. syn:review added in 0.3.x). Runs after migration so the profile is settled.
65
+ syncNewCoreWorkflowsToCustomProfile(getGlobalConfig());
63
66
  }
64
67
  // Show animated welcome screen (interactive mode only)
65
68
  const canPrompt = this.canPromptInteractively();
@@ -381,8 +384,8 @@ export class InitCommand {
381
384
  const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
382
385
  removedSkillCount += await removeSkillDirs(skillsDir);
383
386
  }
384
- // Generate commands if delivery includes commands
385
- if (shouldGenerateCommands) {
387
+ // Generate commands if delivery includes commands and tool supports them
388
+ if (shouldGenerateCommands && hasCommands) {
386
389
  const adapter = CommandAdapterRegistry.get(tool.value);
387
390
  if (adapter) {
388
391
  const generatedCommands = generateCommands(commandContents, adapter);
@@ -4,12 +4,20 @@
4
4
  * Defines workflow profiles that control which workflows are installed.
5
5
  * Profiles determine WHICH workflows; delivery (in global config) determines HOW.
6
6
  */
7
- import type { Profile } from './global-config.js';
7
+ import type { Profile, GlobalConfig } from './global-config.js';
8
8
  /**
9
9
  * Resolves which workflows should be active for a given profile configuration.
10
10
  *
11
11
  * - 'core' profile always returns CORE_WORKFLOWS
12
12
  * - 'custom' profile returns the provided customWorkflows, or empty array if not provided
13
13
  */
14
- export declare function getProfileWorkflows(profile: Profile, customWorkflows?: string[]): readonly string[];
14
+ export declare function getProfileWorkflows(profile: Profile, customWorkflows?: readonly string[]): readonly string[];
15
+ /**
16
+ * Ensures a 'custom' profile always contains all current ALL_WORKFLOWS entries.
17
+ * Called by both `synarcx init` and `synarcx update` so new commands (e.g. syn:review)
18
+ * are never silently dropped for users on a stale custom profile, regardless of which
19
+ * command they run after upgrading.
20
+ * No-op for 'core' profile (it derives its list from ALL_WORKFLOWS directly).
21
+ */
22
+ export declare function syncNewCoreWorkflowsToCustomProfile(config: GlobalConfig): void;
15
23
  //# sourceMappingURL=profiles.d.ts.map
@@ -4,7 +4,8 @@
4
4
  * Defines workflow profiles that control which workflows are installed.
5
5
  * Profiles determine WHICH workflows; delivery (in global config) determines HOW.
6
6
  */
7
- import { CORE_WORKFLOWS } from './shared/workflow-registry.js';
7
+ import { saveGlobalConfig } from './global-config.js';
8
+ import { ALL_WORKFLOWS, CORE_WORKFLOWS } from './shared/workflow-registry.js';
8
9
  /**
9
10
  * Resolves which workflows should be active for a given profile configuration.
10
11
  *
@@ -17,4 +18,22 @@ export function getProfileWorkflows(profile, customWorkflows) {
17
18
  }
18
19
  return CORE_WORKFLOWS;
19
20
  }
21
+ /**
22
+ * Ensures a 'custom' profile always contains all current ALL_WORKFLOWS entries.
23
+ * Called by both `synarcx init` and `synarcx update` so new commands (e.g. syn:review)
24
+ * are never silently dropped for users on a stale custom profile, regardless of which
25
+ * command they run after upgrading.
26
+ * No-op for 'core' profile (it derives its list from ALL_WORKFLOWS directly).
27
+ */
28
+ export function syncNewCoreWorkflowsToCustomProfile(config) {
29
+ if (config.profile !== 'custom')
30
+ return;
31
+ const current = config.workflows ?? [];
32
+ const currentSet = new Set(current);
33
+ const missing = ALL_WORKFLOWS.filter(w => !currentSet.has(w));
34
+ if (missing.length === 0)
35
+ return;
36
+ config.workflows = [...current, ...missing];
37
+ saveGlobalConfig(config);
38
+ }
20
39
  //# sourceMappingURL=profiles.js.map
@@ -19,6 +19,18 @@ export async function removeSkillDirs(skillsDir) {
19
19
  // Ignore errors
20
20
  }
21
21
  }
22
+ // Remove empty parent skills directory
23
+ try {
24
+ if (fs.existsSync(skillsDir)) {
25
+ const remaining = await fs.promises.readdir(skillsDir);
26
+ if (remaining.length === 0) {
27
+ await fs.promises.rmdir(skillsDir);
28
+ }
29
+ }
30
+ }
31
+ catch {
32
+ // Ignore errors
33
+ }
22
34
  return removed;
23
35
  }
24
36
  export async function removeUnselectedSkillDirs(skillsDir, desiredWorkflows) {
@@ -270,7 +270,10 @@ export async function writeUpdatedSpec(update, rebuilt, counts) {
270
270
  // Create target directory if needed
271
271
  const targetDir = path.dirname(update.target);
272
272
  await fs.mkdir(targetDir, { recursive: true });
273
- await fs.writeFile(update.target, rebuilt);
273
+ // Atomic write: write to .tmp then rename (prevents half-written files on crash)
274
+ const tmpPath = update.target + '.tmp';
275
+ await fs.writeFile(tmpPath, rebuilt);
276
+ await fs.rename(tmpPath, update.target);
274
277
  const specName = path.basename(path.dirname(update.target));
275
278
  console.log(`Applying changes to synspec/specs/${specName}/spec.md:`);
276
279
  if (counts.added)
@@ -347,10 +350,12 @@ export async function applySpecs(projectRoot, changeName, options = {}) {
347
350
  for (const p of prepared) {
348
351
  const capability = path.basename(path.dirname(p.update.target));
349
352
  if (!options.dryRun) {
350
- // Write the updated spec
353
+ // Write the updated spec (atomic: .tmp + rename)
351
354
  const targetDir = path.dirname(p.update.target);
352
355
  await fs.mkdir(targetDir, { recursive: true });
353
- await fs.writeFile(p.update.target, p.rebuilt);
356
+ const tmpPath = p.update.target + '.tmp';
357
+ await fs.writeFile(tmpPath, p.rebuilt);
358
+ await fs.rename(tmpPath, p.update.target);
354
359
  if (!options.silent) {
355
360
  console.log(`Applying changes to synspec/specs/${capability}/spec.md:`);
356
361
  if (p.counts.added)
@@ -77,15 +77,28 @@ export function getSynReviewSkillTemplate() {
77
77
 
78
78
  **If ALL checks pass** (clean):
79
79
 
80
- Present three options:
81
-
82
- | Option | Label | What happens | Next |
83
- |---|---|---|---|
84
- | A | Archive now | AI moves change to archive/ | Done |
85
- | B | Add more work | AI appends new tasks, suggests refinement loop | /syn:clarify/syn:analyze /syn:apply |
86
- | C | Start a new change | AI suggests creating a fresh change | /syn:propose |
87
-
88
- **For option B (add more work)**: Ask the user what else is needed. If the new work fits within the existing change's scope (same capabilities, same specs, related code), append unchecked tasks to \`tasks.md\` and say: "Run /syn:clarify to refine the new requirements, then /syn:analyze, then /syn:apply." If the new work involves different capabilities, different specs, or unrelated code, tell the user: "This is outside this change's scope. Start a new change with /syn:propose instead."
80
+ Present three options:
81
+
82
+ | Option | Label | What happens | Next |
83
+ |---|---|---|---|
84
+ | A | Archive now | AI moves change to archive/ with auto spec sync | Done (specs merged to main) |
85
+ | B | Add more work | AI reads proposal+design for scope boundary, checks scope gate | Scope check update or route |
86
+ | C | Start a new change | AI suggests creating a fresh change | /syn:propose |
87
+
88
+ **For option B (add more work)**: Use the scope gate protocol:
89
+
90
+ 1. Read \`proposal.md\` capabilities section and \`design.md\` goals/non-goals to establish scope boundary
91
+ 2. Ask the user what additional work is needed
92
+ 3. **IN SCOPE** (same capabilities, same concern, no non-goal violation):
93
+ - Update \`proposal.md\` if scope description needs widening
94
+ - Update spec with ADDED requirements
95
+ - Update \`design.md\` if new technical decisions
96
+ - Append unchecked tasks to \`tasks.md\`
97
+ - MUST run \`/syn:clarify\` then \`/syn:apply\` — no skipping refinement, no escape hatch for trivial changes
98
+ 4. **OUT OF SCOPE** (new capability, different concern, violates non-goal):
99
+ - Inform user: "This is outside the current change's scope."
100
+ - Offer: "Archive current change first?" — YES archives with spec sync, NO leaves active
101
+ - Route: "Start a new change with \`/syn:propose\`"
89
102
 
90
103
  **If any checks failed** (dirty):
91
104
 
@@ -103,13 +116,31 @@ export function getSynReviewSkillTemplate() {
103
116
 
104
117
  **Note**: /syn:quick bypasses review entirely. Quick is the low-risk fast path.
105
118
 
106
- 8. **Archive inline** (when user picks option A)
119
+ 8. **Archive inline** (when user picks option A, or in Option B out-of-scope with "yes" to archive)
120
+
121
+ a. **Check for delta specs**: Look for any \`synspec/changes/<name>/specs/<capability>/spec.md\` files. If any exist, proceed with spec sync. If none exist (infrastructure, doc-only change), skip the marker and just do the directory move.
122
+
123
+ b. **Write marker** (only if delta specs exist):
124
+ - Create \`synspec/.pending-sync.json\` if it doesn't exist
125
+ - Add entry: \`{ change: "YYYY-MM-DD-<change-name>", archivedAt: "<ISO timestamp>", syncedAt: null }\`
126
+ - Use the full archive directory name (with date prefix) in the \`change\` field
127
+
128
+ c. **Move to archive**:
129
+ - Create \`synspec/changes/archive/\` if missing
130
+ - Target: \`YYYY-MM-DD-<change-name>\`
131
+ - If target already exists: fail with error, suggest renaming
132
+ - Move: \`mv synspec/changes/<name> synspec/changes/archive/YYYY-MM-DD-<name>\`
107
133
 
108
- - Create \`synspec/changes/archive/\` if it doesn't exist
109
- - Target name: \`YYYY-MM-DD-<change-name>\`
110
- - If target already exists: fail with error, suggest renaming existing archive or using a different approach
111
- - Move: \`mv synspec/changes/<name> synspec/changes/archive/YYYY-MM-DD-<name>\`
112
- - Confirm: "Archived <change-name> to synspec/changes/archive/YYYY-MM-DD-<name>/"
134
+ d. **Sync specs** (only if delta specs existed):
135
+ - Call \`findSpecUpdates(archivePath, synspec/specs/)\` to discover delta specs
136
+ - For each delta: call \`buildUpdatedSpec()\`, write atomically (\`.tmp\` + rename)
137
+ - Show per-capability progress: "Syncing specs for <capability>: +N added, ~M modified"
138
+ - Update marker entry with \`syncedAt\` timestamp
139
+ - On failure: change is already safely archived, show error, marker stays \`null\` for backstop retry
140
+
141
+ e. **Confirm**:
142
+ - "Archived <change-name> to synspec/changes/archive/YYYY-MM-DD-<name>/"
143
+ - If specs were synced: "Specs synced: <capability>: +N ~M"
113
144
 
114
145
  ---
115
146
 
@@ -156,7 +187,7 @@ This change still has 3 tasks remaining.
156
187
  → Use /syn:apply to finish the remaining tasks, then run /syn:review again.
157
188
  \`\`\`
158
189
 
159
- ## Output (Archived)
190
+ ## Output (Archived with Spec Sync)
160
191
 
161
192
  \`\`\`
162
193
  ## Archive Complete
@@ -164,16 +195,32 @@ This change still has 3 tasks remaining.
164
195
  **Change:** <change-name>
165
196
  **Archived to:** synspec/changes/archive/YYYY-MM-DD-<name>/
166
197
 
198
+ Specs synced:
199
+ review-command: +2 added, ~1 modified
200
+
167
201
  All tasks complete. All checks passed. Change archived.
168
202
  \`\`\`
169
203
 
204
+ ## Output (Archived — No Delta Specs)
205
+
206
+ \`\`\`
207
+ ## Archive Complete
208
+
209
+ **Change:** <change-name>
210
+ **Archived to:** synspec/changes/archive/YYYY-MM-DD-<name>/
211
+
212
+ No delta specs to sync. Change archived.
213
+ \`\`\`
214
+
170
215
  ## Guardrails
171
216
  - Do NOT run checks if tasks are incomplete — gate at step 3
172
217
  - Checks are read-only — do not modify project files during checks
173
- - Archive move is the only write operation (step 8)
218
+ - Archive happens BEFORE spec sync if sync fails, change is safely archived
174
219
  - Always list ALL findings at once, don't ask "fix one at a time"
175
220
  - For failed checks, show only summary counts unless user asks for details
176
- - If user picks "add more work," evaluate scope before appending tasks
221
+ - If user picks "add more work," use scope gate protocol: read proposal capabilities + design goals/non-goals before acting
222
+ - MUST run clarify after any in-scope expansion — no escape hatch for trivial changes
223
+ - Out-of-scope work: offer to archive first, then route to \`/syn:propose\`
177
224
  - Quick bypasses review — do not suggest review to users who used /syn:quick`,
178
225
  license: 'MIT',
179
226
  compatibility: 'Requires synarcx CLI.',
@@ -236,24 +283,25 @@ export function getSynReviewCommandTemplate() {
236
283
 
237
284
  Then narrative paragraph.
238
285
 
239
- 7. **Present the fork**
286
+ 7. **Present the fork**
240
287
 
241
288
  **If all checks pass:**
242
- - Archive now → AI moves to archive/
243
- - Add more work → AI appends tasks (scope-checked), suggests \`/syn:clarify\` \`/syn:analyze\` \`/syn:apply\`
289
+ - Archive now → write marker, move to archive, sync specs, update marker
290
+ - Add more work → scope gate: read proposal capabilities + design goals/non-goals. If in scope: update artifacts, MUST run \`/syn:clarify\` then \`/syn:apply\`. If out of scope: offer to archive first (with spec sync), route to \`/syn:propose\`.
244
291
  - Start a new change → \`/syn:propose\`
245
292
 
246
293
  **If issues found:**
247
294
  - Show each finding with route: \`/syn:apply\`, \`/syn:clarify\`, \`/syn:analyze\`
248
295
  - List all findings at once
249
296
 
250
- 8. **Archive inline** (when user picks archive)
297
+ 8. **Archive inline** (when user picks archive)
251
298
 
252
- - Create \`synspec/changes/archive/\` if missing
253
- - Target: \`YYYY-MM-DD-<change-name>\`
254
- - Fail if target exists
255
- - Move: \`mv synspec/changes/<name> synspec/changes/archive/YYYY-MM-DD-<name>\`
256
- - Confirm
299
+ a. Check for delta specs. If none, skip marker and just move.
300
+ b. Write \`synspec/.pending-sync.json\` with \`syncedAt: null\` using full \`YYYY-MM-DD-<name>\` as change field
301
+ c. Move: \`mv synspec/changes/<name> synspec/changes/archive/YYYY-MM-DD-<name>\`
302
+ d. Sync specs: \`findSpecUpdates(archivePath)\` \`buildUpdatedSpec()\` → atomic write (\`.tmp\` + rename) → per-capability output
303
+ e. Update marker with \`syncedAt\` timestamp
304
+ f. On failure: archive is already moved, marker stays \`null\`, backstop retries on next sync
257
305
 
258
306
  ---
259
307
 
@@ -267,7 +315,7 @@ Lint: 0 errors ✓
267
315
  Typecheck: clean ✓
268
316
 
269
317
  All checks pass. What would you like to do?
270
- [A] Archive now [B] Add more work [C] Start a new change
318
+ [A] Archive now (with spec sync) [B] Add more work (scope-gated) [C] Start a new change
271
319
  \`\`\`
272
320
 
273
321
  ## Output (Dirty)
@@ -286,7 +334,10 @@ Findings:
286
334
  ## Guardrails
287
335
  - Gate on task completion — no checks until all tasks are done
288
336
  - Summary only for failed checks (not full logs)
289
- - Scope-check before appending tasks
337
+ - Scope gate for Option B: read proposal capabilities + design goals/non-goals before acting
338
+ - In-scope expansion MUST run clarify then apply — no escape hatch
339
+ - Out-of-scope work: offer archive first, then route to /syn:propose
340
+ - Archive happens before spec sync — if sync fails, change is safely archived
290
341
  - Quick bypasses review — do not suggest review after /syn:quick`
291
342
  });
292
343
  }
@@ -3,11 +3,47 @@ export function getSynSyncSkillTemplate() {
3
3
  return {
4
4
  name: 'syn-sync',
5
5
  description: 'Generate or update synspec/constitution.md with README validation, supporting file scan, guardrail Q&A, and structured constitution generation.',
6
- instructions: `## Step 0: SynArcX Version Check (MUST run first)
6
+ instructions: `## Step 0: Pending Spec Sync Check (runs before version check)
7
7
 
8
- Do NOT read any project files yet. Run this version check first.
8
+ Check for pending spec syncs from recently archived changes. This runs before the version check because it's a local filesystem operation and should not be blocked by network issues.
9
9
 
10
- ### 0.1 Read the daily cache
10
+ ### 0.1 Read \`synspec/.pending-sync.json\`
11
+
12
+ If the file doesn't exist, skip this step entirely (no pending syncs).
13
+
14
+ Expected format:
15
+ \`\`\`json
16
+ { "pending": [{ "change": "YYYY-MM-DD-<name>", "archivedAt": "<ISO>", "syncedAt": null }] }
17
+ \`\`\`
18
+
19
+ ### 0.2 Process pending entries (FIFO order)
20
+
21
+ For each entry where \`syncedAt\` is \`null\`:
22
+ - Construct path: \`synspec/changes/archive/<change>/\`
23
+ - Call \`findSpecUpdates(archivePath, synspec/specs/)\` to discover delta specs in the archived change
24
+ - For each delta spec, call \`buildUpdatedSpec()\` to merge into main specs
25
+ - Write rebuilt specs atomically (\`.tmp\` + rename to \`spec.md\`)
26
+ - Show per-change output: "Synced specs from <change>: <capability>: +N ~M"
27
+ - After each change processed, update its \`syncedAt\` field
28
+ - If \`buildUpdatedSpec()\` throws: show error, leave \`syncedAt\` as \`null\` (retry next time)
29
+
30
+ ### 0.3 Clean up marker
31
+
32
+ After all pending entries are processed:
33
+ - If all entries have \`syncedAt\` set: delete \`synspec/.pending-sync.json\` entirely (clean slate)
34
+ - If some entries failed (\`syncedAt\` still \`null\`): keep the marker, show which changes still need attention, and why
35
+
36
+ ### 0.4 Proceed to version check
37
+
38
+ Once pending syncs are handled, proceed to Step 1.
39
+
40
+ ---
41
+
42
+ ## Step 1: SynArcX Version Check
43
+
44
+ Do NOT read any project files yet. Run this version check after pending spec syncs are handled.
45
+
46
+ ### 1.1 Read the daily cache
11
47
 
12
48
  Read \`synspec/.version-cache.json\`. If \`lastCheck\` matches today's UTC date (YYYY-MM-DD), skip the version check entirely — proceed to "Main Sync Flow" below.
13
49
 
@@ -18,15 +54,15 @@ Expected cache format:
18
54
 
19
55
  If missing or malformed, treat as cache miss and continue.
20
56
 
21
- ### 0.2 Fetch latest from npm
57
+ ### 1.2 Fetch latest from npm
22
58
 
23
- Run \`npm view synarcx version\`. On failure (no npm, no network, non-zero exit): silently skip to 0.5, write cache with \`latestVersion: null\`.
59
+ Run \`npm view synarcx version\`. On failure (no npm, no network, non-zero exit): silently skip to 1.5, write cache with \`latestVersion: null\`.
24
60
 
25
- ### 0.3 Get installed version
61
+ ### 1.3 Get installed version
26
62
 
27
- Run \`synarcx --version\`. On failure: silently skip to 0.5.
63
+ Run \`synarcx --version\`. On failure: silently skip to 1.5.
28
64
 
29
- ### 0.4 Compare and prompt
65
+ ### 1.4 Compare and prompt
30
66
 
31
67
  Parse both as semver: split on \`.\`, parse each as integer, compare major→minor→patch. If npm version > installed:
32
68
 
@@ -37,7 +73,7 @@ Parse both as semver: split on \`.\`, parse each as integer, compare major→min
37
73
 
38
74
  If versions match, proceed silently.
39
75
 
40
- ### 0.5 Write cache
76
+ ### 1.5 Write cache
41
77
 
42
78
  Write \`synspec/.version-cache.json\` with today's UTC date and latest version (or \`null\` on failure). Use \`new Date().toISOString().split('T')[0]\`.
43
79
 
@@ -150,23 +186,31 @@ export function getSynSyncCommandTemplate() {
150
186
  name: 'syn:sync',
151
187
  description: 'Generate/update project constitution with README validation, guardrail Q&A, and constraint capture',
152
188
  tags: ['workflow', 'sync', 'project'],
153
- content: `## Step 0: SynArcX Version Check (MUST run first)
189
+ content: `## Step 0: Pending Spec Sync Check (runs before version check)
190
+
191
+ Check \`synspec/.pending-sync.json\`. If file missing, skip (no pending syncs). Expected format: \`{ "pending": [{ "change": "YYYY-MM-DD-<name>", "archivedAt": "<ISO>", "syncedAt": null }] }\`.
192
+
193
+ For each entry with \`syncedAt: null\`: construct path \`synspec/changes/archive/<change>/\`, call \`findSpecUpdates()\` + \`buildUpdatedSpec()\`, write atomically (\`.tmp\` + rename), update \`syncedAt\`. On error: leave \`syncedAt: null\` for retry.
194
+
195
+ After all processed: if all entries have \`syncedAt\`, delete marker file. If some still \`null\`, keep marker with error info. Then proceed.
196
+
197
+ ---
154
198
 
155
- Do NOT read any project files yet. Run this version check first.
199
+ ## Step 1: SynArcX Version Check
156
200
 
157
- ### 0.1 Read the daily cache
201
+ ### 1.1 Read the daily cache
158
202
 
159
203
  Read \`synspec/.version-cache.json\`. If \`lastCheck\` matches today's UTC date (YYYY-MM-DD), skip to "Main Sync Flow" below. Expected format: \`{ "lastCheck": "2026-05-13", "latestVersion": "0.4.0" }\`.
160
204
 
161
- ### 0.2 Fetch latest from npm
205
+ ### 1.2 Fetch latest from npm
162
206
 
163
- Run \`npm view synarcx version\`. On failure, silently skip to 0.5, write cache with \`latestVersion: null\`.
207
+ Run \`npm view synarcx version\`. On failure, silently skip to 1.5, write cache with \`latestVersion: null\`.
164
208
 
165
- ### 0.3 Get installed version
209
+ ### 1.3 Get installed version
166
210
 
167
- Run \`synarcx --version\`. On failure, silently skip to 0.5.
211
+ Run \`synarcx --version\`. On failure, silently skip to 1.5.
168
212
 
169
- ### 0.4 Compare and prompt
213
+ ### 1.4 Compare and prompt
170
214
 
171
215
  Parse both as semver: split on \`.\`, parse each as integer, compare major→minor→patch. If npm version > installed:
172
216
 
@@ -177,7 +221,7 @@ Parse both as semver: split on \`.\`, parse each as integer, compare major→min
177
221
 
178
222
  If versions match, proceed silently.
179
223
 
180
- ### 0.5 Write cache
224
+ ### 1.5 Write cache
181
225
 
182
226
  Write \`synspec/.version-cache.json\` with today's UTC date and latest version (or \`null\` on failure). Use \`new Date().toISOString().split('T')[0]\`.
183
227
 
@@ -39,12 +39,11 @@ export declare class UpdateCommand {
39
39
  */
40
40
  private displayExtraWorkflowsNote;
41
41
  /**
42
- * Ensures a 'custom' profile always contains all current ALL_WORKFLOWS entries.
43
42
  * Runs on every `synarcx update` so any newly introduced workflow (e.g. syn:review)
44
43
  * is automatically added to the saved custom workflow list rather than silently dropped.
45
- * No-op for 'core' profile (it derives workflows from ALL_WORKFLOWS directly).
44
+ * Also prints a dim notice listing what was added.
46
45
  */
47
- private syncNewCoreWorkflowsToCustomProfile;
46
+ private runSyncNewCoreWorkflowsToCustomProfile;
48
47
  /**
49
48
  * Suggest opting back into core when a custom profile still matches the old
50
49
  * pre-sync core set. Keep custom profiles user-owned; do not mutate them.
@@ -15,8 +15,8 @@ import { generateCommands, CommandAdapterRegistry, } from './command-generation/
15
15
  import { getToolVersionStatus, getSkillTemplates, getCommandContents, generateSkillContent, getToolsWithSkillsDir, } from './shared/index.js';
16
16
  import { detectLegacyArtifacts, cleanupLegacyArtifacts, formatCleanupSummary, formatDetectionSummary, getToolsFromLegacyArtifacts, } from './legacy-cleanup.js';
17
17
  import { isInteractive } from '../utils/interactive.js';
18
- import { getGlobalConfig, saveGlobalConfig } from './global-config.js';
19
- import { getProfileWorkflows } from './profiles.js';
18
+ import { getGlobalConfig } from './global-config.js';
19
+ import { getProfileWorkflows, syncNewCoreWorkflowsToCustomProfile } from './profiles.js';
20
20
  import { ALL_WORKFLOWS } from './shared/workflow-registry.js';
21
21
  import { removeSkillDirs, removeUnselectedSkillDirs, removeCommandFiles, removeUnselectedCommandFiles, } from './shared/artifact-cleanup.js';
22
22
  import { getAvailableTools } from './available-tools.js';
@@ -60,7 +60,7 @@ export class UpdateCommand {
60
60
  // 3b. For custom profiles, auto-merge any new ALL_WORKFLOWS entries that aren't
61
61
  // listed yet (e.g. 'syn:review' added in a new release). This prevents future
62
62
  // versions from silently dropping new commands for existing custom-profile users.
63
- this.syncNewCoreWorkflowsToCustomProfile(globalConfig);
63
+ this.runSyncNewCoreWorkflowsToCustomProfile(globalConfig);
64
64
  // Re-read after potential mutation so desiredWorkflows is always current.
65
65
  const effectiveConfig = getGlobalConfig();
66
66
  const profileWorkflows = getProfileWorkflows(profile, effectiveConfig.workflows);
@@ -144,12 +144,12 @@ export class UpdateCommand {
144
144
  }
145
145
  removedDeselectedSkillCount += await removeUnselectedSkillDirs(skillsDir, desiredWorkflows);
146
146
  }
147
- // Delete skill directories if delivery is commands-only
148
- if (!shouldGenerateSkills) {
147
+ // Delete skill directories if delivery is commands-only or tool uses commands
148
+ if (!shouldGenerateSkills || tool.hasCommands) {
149
149
  removedSkillCount += await removeSkillDirs(skillsDir);
150
150
  }
151
- // Generate commands if delivery includes commands
152
- if (shouldGenerateCommands) {
151
+ // Generate commands if delivery includes commands and tool supports them
152
+ if (shouldGenerateCommands && tool.hasCommands) {
153
153
  const adapter = CommandAdapterRegistry.get(tool.value);
154
154
  if (adapter) {
155
155
  const generatedCommands = generateCommands(commandContents, adapter);
@@ -273,24 +273,21 @@ export class UpdateCommand {
273
273
  }
274
274
  }
275
275
  /**
276
- * Ensures a 'custom' profile always contains all current ALL_WORKFLOWS entries.
277
276
  * Runs on every `synarcx update` so any newly introduced workflow (e.g. syn:review)
278
277
  * is automatically added to the saved custom workflow list rather than silently dropped.
279
- * No-op for 'core' profile (it derives workflows from ALL_WORKFLOWS directly).
278
+ * Also prints a dim notice listing what was added.
280
279
  */
281
- syncNewCoreWorkflowsToCustomProfile(config) {
282
- if (config.profile !== 'custom')
283
- return;
284
- const current = config.workflows ?? [];
285
- const currentSet = new Set(current);
286
- const missing = ALL_WORKFLOWS.filter(w => !currentSet.has(w));
287
- if (missing.length === 0)
288
- return;
289
- config.workflows = [...current, ...missing];
290
- saveGlobalConfig(config);
291
- const listed = missing.map(w => `/syn:${w}`).join(', ');
292
- console.log(chalk.dim(`Auto-added new workflow(s) to your profile: ${listed}`));
293
- console.log();
280
+ runSyncNewCoreWorkflowsToCustomProfile(config) {
281
+ const before = config.workflows ? [...config.workflows] : null;
282
+ syncNewCoreWorkflowsToCustomProfile(config);
283
+ const after = config.workflows ?? [];
284
+ const beforeSet = new Set(before ?? []);
285
+ const added = after.filter(w => !beforeSet.has(w));
286
+ if (added.length > 0) {
287
+ const listed = added.map(w => `/syn:${w}`).join(', ');
288
+ console.log(chalk.dim(`Auto-added new workflow(s) to your profile: ${listed}`));
289
+ console.log();
290
+ }
294
291
  }
295
292
  /**
296
293
  * Suggest opting back into core when a custom profile still matches the old
package/package.json CHANGED
@@ -1,83 +1,87 @@
1
- {
2
- "name": "synarcx",
3
- "version": "0.3.2",
4
- "description": "Structured engineering workflows for AI coding assistants — persistent project memory, spec-driven development, and architecture drift prevention across every session.",
5
- "keywords": [
6
- "ai-workflow",
7
- "claude-code",
8
- "cursor",
9
- "spec-driven-development",
10
- "ai-coding-assistant",
11
- "architecture-drift",
12
- "persistent-context",
13
- "engineering-workflow",
14
- "ai-coding-workflow",
15
- "specification",
16
- "claude-code-workflow",
17
- "ai-context-management"
18
- ],
19
- "homepage": "https://github.com/funara/synarcx",
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/funara/synarcx.git"
23
- },
24
- "license": "MIT",
25
- "author": "Adhi Rahmadian",
26
- "type": "module",
27
- "publishConfig": {
28
- "access": "public"
29
- },
30
- "exports": {
31
- ".": {
32
- "types": "./dist/index.d.ts",
33
- "default": "./dist/index.js"
34
- }
35
- },
36
- "bin": {
37
- "synarcx": "bin/synarcx.js"
38
- },
39
- "files": [
40
- "dist",
41
- "bin",
42
- "schemas",
43
- "scripts/postinstall.js",
44
- "!dist/**/*.test.js",
45
- "!dist/**/__tests__",
46
- "!dist/**/*.map"
47
- ],
48
- "scripts": {
49
- "lint": "eslint src/",
50
- "build": "node build.js",
51
- "dev": "tsc --watch",
52
- "dev:cli": "pnpm build && node bin/synarcx.js",
53
- "test": "vitest run",
54
- "test:watch": "vitest",
55
- "test:ui": "vitest --ui",
56
- "test:coverage": "vitest --coverage",
57
- "test:postinstall": "node scripts/postinstall.js",
58
- "prepare": "pnpm run build",
59
- "postinstall": "node scripts/postinstall.js"
60
- },
61
- "engines": {
62
- "node": ">=20.19.0"
63
- },
64
- "devDependencies": {
65
- "@types/node": "^24.2.0",
66
- "@vitest/ui": "^3.2.4",
67
- "eslint": "^9.39.2",
68
- "typescript": "^5.9.3",
69
- "typescript-eslint": "^8.50.1",
70
- "vitest": "^3.2.4"
71
- },
72
- "dependencies": {
73
- "@inquirer/core": "^10.2.2",
74
- "@inquirer/prompts": "^7.8.0",
75
- "chalk": "^5.5.0",
76
- "commander": "^14.0.0",
77
- "cross-spawn": "7.0.6",
78
- "fast-glob": "^3.3.3",
79
- "ora": "^8.2.0",
80
- "yaml": "^2.8.2",
81
- "zod": "^4.0.17"
82
- }
83
- }
1
+ {
2
+ "name": "synarcx",
3
+ "version": "0.3.4",
4
+ "description": "Structured engineering workflows for AI coding assistants — persistent project memory, spec-driven development, and architecture drift prevention across every session.",
5
+ "keywords": [
6
+ "ai-workflow",
7
+ "claude-code",
8
+ "cursor",
9
+ "opencode",
10
+ "codex",
11
+ "gemini",
12
+ "spec-driven-development",
13
+ "ai-coding-assistant",
14
+ "architecture-drift",
15
+ "persistent-context",
16
+ "engineering-workflow",
17
+ "ai-coding-workflow",
18
+ "specification",
19
+ "claude-code-workflow",
20
+ "ai-context-management"
21
+ ],
22
+ "homepage": "https://github.com/funara/synarcx",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/funara/synarcx.git"
26
+ },
27
+ "license": "MIT",
28
+ "author": "Adhi Rahmadian",
29
+ "type": "module",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "default": "./dist/index.js"
37
+ }
38
+ },
39
+ "bin": {
40
+ "synarcx": "./dist/index.js"
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "bin",
45
+ "schemas",
46
+ "scripts/postinstall.js",
47
+ "!dist/**/*.test.js",
48
+ "!dist/**/__tests__",
49
+ "!dist/**/*.map"
50
+ ],
51
+ "scripts": {
52
+ "lint": "eslint src/",
53
+ "build": "node build.js",
54
+ "dev": "tsc --watch",
55
+ "dev:cli": "pnpm build && node bin/synarcx.js",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "test:ui": "vitest --ui",
59
+ "test:coverage": "vitest --coverage",
60
+ "test:postinstall": "node scripts/postinstall.js",
61
+ "prepare": "pnpm run build",
62
+ "postinstall": "node scripts/postinstall.js"
63
+ },
64
+ "engines": {
65
+ "node": ">=20.19.0"
66
+ },
67
+ "devDependencies": {
68
+ "@types/node": "^24.2.0",
69
+ "@vitest/ui": "^3.2.4",
70
+ "eslint": "^9.39.2",
71
+ "typescript": "^5.9.3",
72
+ "typescript-eslint": "^8.50.1",
73
+ "vitest": "^3.2.4"
74
+ },
75
+ "dependencies": {
76
+ "@inquirer/core": "^10.2.2",
77
+ "@inquirer/prompts": "^7.8.0",
78
+ "chalk": "^5.5.0",
79
+ "commander": "^14.0.0",
80
+ "cross-spawn": "7.0.6",
81
+ "fast-glob": "^3.3.3",
82
+ "ora": "^8.2.0",
83
+ "synarcx": "link:",
84
+ "yaml": "^2.8.2",
85
+ "zod": "^4.0.17"
86
+ }
87
+ }