synarcx 0.3.3 → 0.3.5

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
@@ -147,7 +147,7 @@ Each step suggests the next — you decide when to advance. Works in Claude Code
147
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.
148
148
  - `explore`, `debug`, and `refactor` are entry points that hand off to `propose`
149
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
150
+ - Run `synarcx update` in your terminal to refresh all command files after installing a new version
151
151
  - `review` is a three-way fork:
152
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
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`.
@@ -213,7 +213,7 @@ Used in your terminal:
213
213
  | Command | Description |
214
214
  | ------------------- | ------------------------------------------------------------ |
215
215
  | `synarcx init` | Set up SynArcX workflow structure in your repository |
216
- | `synarcx update` | Refresh skill and command files for all configured tools |
216
+ | `synarcx update` | Refresh command files for all configured tools |
217
217
  | `synarcx sync` | Regenerate `constitution.md` |
218
218
  | `synarcx explore` | Open explore session |
219
219
  | `synarcx propose` | Create a structured change proposal |
@@ -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
@@ -384,8 +384,8 @@ export class InitCommand {
384
384
  const skillsDir = path.join(projectPath, tool.skillsDir, 'skills');
385
385
  removedSkillCount += await removeSkillDirs(skillsDir);
386
386
  }
387
- // Generate commands if delivery includes commands
388
- if (shouldGenerateCommands) {
387
+ // Generate commands if delivery includes commands and tool supports them
388
+ if (shouldGenerateCommands && hasCommands) {
389
389
  const adapter = CommandAdapterRegistry.get(tool.value);
390
390
  if (adapter) {
391
391
  const generatedCommands = generateCommands(commandContents, adapter);
@@ -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) {
@@ -98,7 +98,7 @@ export function getSynReviewSkillTemplate() {
98
98
  4. **OUT OF SCOPE** (new capability, different concern, violates non-goal):
99
99
  - Inform user: "This is outside the current change's scope."
100
100
  - Offer: "Archive current change first?" — YES archives with spec sync, NO leaves active
101
- - Route: "Start a new change with \`/syn:propose\`"
101
+ - Route: "Start a new change with \`/syn:propose\`"
102
102
 
103
103
  **If any checks failed** (dirty):
104
104
 
@@ -140,7 +140,7 @@ export function getSynReviewSkillTemplate() {
140
140
 
141
141
  e. **Confirm**:
142
142
  - "Archived <change-name> to synspec/changes/archive/YYYY-MM-DD-<name>/"
143
- - If specs were synced: "Specs synced: <capability>: +N ~M"
143
+ - If specs were synced: "Specs synced: <capability>: +N ~M"
144
144
 
145
145
  ---
146
146
 
@@ -301,7 +301,7 @@ export function getSynReviewCommandTemplate() {
301
301
  c. Move: \`mv synspec/changes/<name> synspec/changes/archive/YYYY-MM-DD-<name>\`
302
302
  d. Sync specs: \`findSpecUpdates(archivePath)\` → \`buildUpdatedSpec()\` → atomic write (\`.tmp\` + rename) → per-capability output
303
303
  e. Update marker with \`syncedAt\` timestamp
304
- f. On failure: archive is already moved, marker stays \`null\`, backstop retries on next sync
304
+ f. On failure: archive is already moved, marker stays \`null\`, backstop retries on next sync
305
305
 
306
306
  ---
307
307
 
@@ -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);
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "synarcx",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Structured engineering workflows for AI coding assistants — persistent project memory, spec-driven development, and architecture drift prevention across every session.",
5
5
  "keywords": [
6
6
  "ai-workflow",
7
7
  "claude-code",
8
8
  "cursor",
9
+ "opencode",
10
+ "codex",
11
+ "gemini",
9
12
  "spec-driven-development",
10
13
  "ai-coding-assistant",
11
14
  "architecture-drift",
@@ -34,7 +37,7 @@
34
37
  }
35
38
  },
36
39
  "bin": {
37
- "synarcx": "bin/synarcx.js"
40
+ "synarcx": "./dist/index.js"
38
41
  },
39
42
  "files": [
40
43
  "dist",