magic-spec 1.5.71 → 1.5.159

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.
@@ -16,6 +16,12 @@
16
16
  "magic.spec",
17
17
  "magic.task"
18
18
  ],
19
+ "devWorkflows": [
20
+ "magic.dev.simulate"
21
+ ],
22
+ "devSkills": [
23
+ "magic.dev.simulate"
24
+ ],
19
25
  "magicFiles": [
20
26
  "analyze.md",
21
27
  "init.md",
@@ -31,11 +37,17 @@
31
37
  "scripts/generate-checksums.js",
32
38
  "scripts/generate-context.js",
33
39
  "scripts/init.js",
40
+ "scripts/sync-skills.js",
34
41
  "templates/plan.md",
35
42
  "templates/retrospective.md",
36
43
  "templates/spec.md",
37
44
  "templates/tasks.md"
38
45
  ],
46
+ "devMagicFiles": [
47
+ "simulate.md",
48
+ "tests/engine.js",
49
+ "tests/suite.md"
50
+ ],
39
51
  "download": {
40
52
  "timeoutMs": 10000,
41
53
  "tempPrefix": "magic-spec-tmp-"
@@ -48,6 +60,7 @@
48
60
  "targets": [
49
61
  ".magic",
50
62
  ".agents",
63
+ "skills",
51
64
  "installers"
52
65
  ]
53
66
  },
@@ -55,10 +68,14 @@
55
68
  "versionFiles": [
56
69
  "package.json",
57
70
  "pyproject.toml",
58
- "installers/python/magic_spec/__init__.py"
71
+ "installers/python/magic_spec/__init__.py",
72
+ ".magic/.version",
73
+ ".magic/.checksums"
59
74
  ],
60
75
  "docsTargets": [
61
- "CHANGELOG.md"
76
+ "CHANGELOG.md",
77
+ "README.md",
78
+ "docs/README.md"
62
79
  ]
63
80
  },
64
81
  "tests": {
@@ -70,12 +70,16 @@ function loadInstallerConfig() {
70
70
  const defaultExt = requireNonEmptyString(parsed.defaultExt, 'defaultExt');
71
71
  const workflows = Array.isArray(parsed.workflows) ? parsed.workflows : null;
72
72
  if (!workflows) {
73
- failConfig("field 'workflows' must be an array of strings");
73
+ failConfig("field 'workflows' must be a non-empty array");
74
74
  }
75
+ const devWorkflows = Array.isArray(parsed.devWorkflows) ? parsed.devWorkflows : [];
76
+
75
77
  const magicFiles = Array.isArray(parsed.magicFiles) ? parsed.magicFiles : null;
76
78
  if (!magicFiles) {
77
- failConfig("field 'magicFiles' must be an array of strings");
79
+ failConfig("field 'magicFiles' must be a non-empty array");
78
80
  }
81
+ const devMagicFiles = Array.isArray(parsed.devMagicFiles) ? parsed.devMagicFiles : [];
82
+ const devSkills = Array.isArray(parsed.devSkills) ? parsed.devSkills : [];
79
83
 
80
84
  const designDir = requireNonEmptyString(parsed.designDir, 'designDir');
81
85
  const versionFile = requireNonEmptyString(parsed.versionFile, 'versionFile');
@@ -95,7 +99,10 @@ function loadInstallerConfig() {
95
99
  historyDir,
96
100
  defaultExt,
97
101
  workflows,
102
+ devWorkflows,
98
103
  magicFiles,
104
+ devMagicFiles,
105
+ devSkills,
99
106
  download: { timeoutMs, tempPrefix },
100
107
  userAgent: { node: nodeUserAgent },
101
108
  ejectTargets: parsed.eject.targets
@@ -109,8 +116,11 @@ const ENGINE_DIR = INSTALLER_CONFIG.engineDir;
109
116
  const AGENT_DIR = INSTALLER_CONFIG.agentDir;
110
117
  const WORKFLOWS_DIR = INSTALLER_CONFIG.workflowsDir;
111
118
  const DEFAULT_EXT = INSTALLER_CONFIG.defaultExt;
112
- const WORKFLOWS = INSTALLER_CONFIG.workflows;
113
- const MAGIC_FILES = INSTALLER_CONFIG.magicFiles;
119
+ let WORKFLOWS = [...INSTALLER_CONFIG.workflows];
120
+ let MAGIC_FILES = [...INSTALLER_CONFIG.magicFiles];
121
+ const DEV_WORKFLOWS = INSTALLER_CONFIG.devWorkflows;
122
+ const DEV_MAGIC_FILES = INSTALLER_CONFIG.devMagicFiles;
123
+ const DEV_SKILLS = INSTALLER_CONFIG.devSkills;
114
124
  const DESIGN_DIR = INSTALLER_CONFIG.designDir;
115
125
  const VERSION_FILE = INSTALLER_CONFIG.versionFile;
116
126
  const CHECKSUMS_FILE = INSTALLER_CONFIG.checksumsFile;
@@ -130,6 +140,7 @@ const isListEnvs = args.includes('--list-envs');
130
140
  const isEject = args.includes('--eject');
131
141
  const isFallbackMain = args.includes('--fallback-main');
132
142
  const isLocal = args.includes('--local');
143
+ const isDev = args.includes('--dev');
133
144
  const autoAccept = args.includes('--yes') || args.includes('-y');
134
145
 
135
146
  function parseCsvValues(raw) {
@@ -331,24 +342,16 @@ function installAdapter(sourceRoot, env, adapters, conflictsToSkip = []) {
331
342
  }
332
343
 
333
344
  function runDoctor() {
334
- const isWindows = process.platform === 'win32';
335
- const checkScript = isWindows
336
- ? path.join(cwd, ENGINE_DIR, 'scripts', 'check-prerequisites.ps1')
337
- : path.join(cwd, ENGINE_DIR, 'scripts', 'check-prerequisites.sh');
345
+ const checkScript = path.join(cwd, ENGINE_DIR, 'scripts', 'check-prerequisites.js');
338
346
 
339
347
  if (!fs.existsSync(checkScript)) {
340
- console.error('❌ Error: SDD engine not initialized. Run magic-spec first.');
348
+ console.error('❌ Error: SDD engine not initialized or check-prerequisites.js missing. Run magic-spec first.');
341
349
  process.exit(1);
342
350
  }
343
351
 
344
352
  console.log(`🔍 ${PACKAGE_NAME} Doctor:`);
345
353
  try {
346
- let result;
347
- if (isWindows) {
348
- result = spawnSync('powershell.exe', ['-ExecutionPolicy', 'Bypass', '-File', checkScript, '-json'], { encoding: 'utf-8' });
349
- } else {
350
- result = spawnSync('bash', [checkScript, '--json'], { encoding: 'utf-8' });
351
- }
354
+ const result = spawnSync('node', [checkScript, '--json'], { encoding: 'utf-8' });
352
355
 
353
356
  if (result.error) {
354
357
  console.error('❌ Failed to run doctor prerequisite check:', result.error.message);
@@ -763,6 +766,7 @@ async function main() {
763
766
  console.log(" --env <adapter> Specify environment adapter");
764
767
  console.log(" --<adapter> Shortcut for --env <adapter> (e.g. --cursor)");
765
768
  console.log(" --update Update engine and adapter files");
769
+ console.log(" --dev Install development instruments (simulation, testing)");
766
770
  console.log(" --local Use local project files instead of GitHub");
767
771
  console.log(" --fallback-main Pull payload from main branch");
768
772
  console.log(" --yes, -y Auto-accept prompts");
@@ -775,6 +779,13 @@ async function main() {
775
779
  createBackup();
776
780
  }
777
781
 
782
+ if (isDev) {
783
+ console.log("🛠️ Development instruments enabled.");
784
+ // Append dev workflows and engine files to the active set
785
+ WORKFLOWS = [...WORKFLOWS, ...DEV_WORKFLOWS];
786
+ MAGIC_FILES = [...MAGIC_FILES, ...DEV_MAGIC_FILES];
787
+ }
788
+
778
789
  const versionToFetch = isFallbackMain ? 'main' : version;
779
790
  let sourceRoot = null;
780
791
 
@@ -912,6 +923,39 @@ async function main() {
912
923
  }
913
924
  }
914
925
 
926
+ // If `--dev` is specified during update, ensure dev tools are present
927
+ if (isUpdate && isDev) {
928
+ const srcEng = path.join(sourceRoot, AGENT_DIR);
929
+ const destEng = path.join(cwd, AGENT_DIR);
930
+
931
+ // Sync dev workflows
932
+ const srcWfDir = path.join(srcEng, WORKFLOWS_DIR);
933
+ const destWfDir = path.join(destEng, WORKFLOWS_DIR);
934
+ if (fs.existsSync(srcWfDir)) {
935
+ fs.mkdirSync(destWfDir, { recursive: true });
936
+ for (const wf of DEV_WORKFLOWS) {
937
+ const file = wf + DEFAULT_EXT;
938
+ const sf = path.join(srcWfDir, file);
939
+ if (fs.existsSync(sf)) {
940
+ fs.copyFileSync(sf, path.join(destWfDir, file));
941
+ }
942
+ }
943
+ }
944
+
945
+ // Sync dev skills
946
+ const srcSkillsDir = path.join(srcEng, 'skills');
947
+ const destSkillsDir = path.join(destEng, 'skills');
948
+ if (fs.existsSync(srcSkillsDir)) {
949
+ fs.mkdirSync(destSkillsDir, { recursive: true });
950
+ for (const sk of DEV_SKILLS) {
951
+ const ss = path.join(srcSkillsDir, sk);
952
+ if (fs.existsSync(ss) && fs.statSync(ss).isDirectory()) {
953
+ copyDir(ss, path.join(destSkillsDir, sk));
954
+ }
955
+ }
956
+ }
957
+ }
958
+
915
959
  // 3. Init script
916
960
  if (!isUpdate) {
917
961
  const isWindows = process.platform === 'win32';
@@ -954,6 +998,18 @@ async function main() {
954
998
  console.log(`✅ ${PACKAGE_NAME} updated successfully!`);
955
999
  }
956
1000
 
1001
+ // 3.5. Sync Skill Wrappers
1002
+ const syncScript = path.join(cwd, ENGINE_DIR, 'scripts', 'sync-skills.js');
1003
+ if (fs.existsSync(syncScript)) {
1004
+ console.log('🔄 Projecting Workflows to Skill Wrappers...');
1005
+ const syncResult = spawnSync('node', [syncScript], { cwd });
1006
+ if (syncResult.error || syncResult.status !== 0) {
1007
+ console.warn(`⚠️ Skill synchronization failed: ${syncResult.stderr || syncResult.error?.message}`);
1008
+ } else {
1009
+ console.log('✅ Skills synchronized.');
1010
+ }
1011
+ }
1012
+
957
1013
  // 4. Write version file - [T-2B01]
958
1014
  try {
959
1015
  const versionFileDest = path.join(cwd, ENGINE_DIR, VERSION_FILE);
@@ -963,7 +1019,7 @@ async function main() {
963
1019
  }
964
1020
 
965
1021
  // 5. Auto-update .gitignore
966
- const gitignoreEntries = [ENGINE_DIR];
1022
+ const gitignoreEntries = [ENGINE_DIR, 'skills'];
967
1023
  if (envValues.length > 0) {
968
1024
  for (const env of envValues) {
969
1025
  const adapter = ADAPTERS[env];
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "magic-spec",
3
- "version": "1.5.71",
3
+ "version": "1.5.159",
4
4
  "description": "Magic Specification-Driven Development (SDD) Workflow",
5
5
  "author": "Oleg Alexandrov <alexandrovoleg.ru@gmail.com>",
6
- "license": "MIT",
6
+ "license": "Apache-2.0",
7
7
  "homepage": "https://github.com/teratron/magic-spec",
8
8
  "repository": {
9
9
  "type": "git",