kspec 1.0.15 → 1.0.16

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +97 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kspec",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Spec-driven development workflow for Kiro CLI",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const os = require('os');
3
4
  const { execSync, spawn } = require('child_process');
4
5
  const readline = require('readline');
5
6
 
@@ -7,6 +8,7 @@ const KSPEC_DIR = '.kspec';
7
8
  const STEERING_DIR = '.kiro/steering';
8
9
  const AGENTS_DIR = '.kiro/agents';
9
10
  const CONFIG_FILE = path.join(KSPEC_DIR, 'config.json');
11
+ const UPDATE_CHECK_FILE = path.join(os.homedir(), '.kspec-update-check');
10
12
 
11
13
  // Default config
12
14
  const defaultConfig = {
@@ -33,6 +35,62 @@ function saveConfig(cfg) {
33
35
  }
34
36
 
35
37
  const config = loadConfig();
38
+ const pkg = require('../package.json');
39
+
40
+ // Update check (non-blocking, cached for 24h)
41
+ function shouldCheckUpdate() {
42
+ try {
43
+ if (fs.existsSync(UPDATE_CHECK_FILE)) {
44
+ const lastCheck = parseInt(fs.readFileSync(UPDATE_CHECK_FILE, 'utf8'), 10);
45
+ const hoursSinceCheck = (Date.now() - lastCheck) / (1000 * 60 * 60);
46
+ return hoursSinceCheck >= 24;
47
+ }
48
+ } catch {}
49
+ return true;
50
+ }
51
+
52
+ function saveUpdateCheck() {
53
+ try {
54
+ fs.writeFileSync(UPDATE_CHECK_FILE, Date.now().toString());
55
+ } catch {}
56
+ }
57
+
58
+ function compareVersions(v1, v2) {
59
+ const parts1 = v1.split('.').map(Number);
60
+ const parts2 = v2.split('.').map(Number);
61
+ for (let i = 0; i < 3; i++) {
62
+ if ((parts1[i] || 0) < (parts2[i] || 0)) return -1;
63
+ if ((parts1[i] || 0) > (parts2[i] || 0)) return 1;
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ async function checkForUpdates() {
69
+ if (!shouldCheckUpdate()) return;
70
+
71
+ try {
72
+ const https = require('https');
73
+ const data = await new Promise((resolve, reject) => {
74
+ const req = https.get('https://registry.npmjs.org/kspec/latest', { timeout: 3000 }, res => {
75
+ let body = '';
76
+ res.on('data', chunk => body += chunk);
77
+ res.on('end', () => resolve(body));
78
+ });
79
+ req.on('error', reject);
80
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
81
+ });
82
+
83
+ const latest = JSON.parse(data).version;
84
+ saveUpdateCheck();
85
+
86
+ if (compareVersions(pkg.version, latest) < 0) {
87
+ console.log(`\n Update available: ${pkg.version} → ${latest}`);
88
+ console.log(` Run: npm install -g kspec\n`);
89
+ }
90
+ } catch {
91
+ // Silently fail - don't block user workflow
92
+ }
93
+ }
36
94
 
37
95
  // Helpers
38
96
  function log(msg) { console.log(`[kspec] ${msg}`); }
@@ -818,6 +876,37 @@ Switch: /agent swap or use keyboard shortcuts
818
876
  `);
819
877
  },
820
878
 
879
+ async update() {
880
+ console.log(`\nkspec v${pkg.version}\n`);
881
+ console.log('Checking for updates...');
882
+
883
+ try {
884
+ const https = require('https');
885
+ const data = await new Promise((resolve, reject) => {
886
+ const req = https.get('https://registry.npmjs.org/kspec/latest', { timeout: 5000 }, res => {
887
+ let body = '';
888
+ res.on('data', chunk => body += chunk);
889
+ res.on('end', () => resolve(body));
890
+ });
891
+ req.on('error', reject);
892
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
893
+ });
894
+
895
+ const latest = JSON.parse(data).version;
896
+ saveUpdateCheck();
897
+
898
+ if (compareVersions(pkg.version, latest) < 0) {
899
+ console.log(`\nUpdate available: ${pkg.version} → ${latest}`);
900
+ console.log('\nTo update, run:');
901
+ console.log(' npm install -g kspec\n');
902
+ } else {
903
+ console.log(`\nYou're on the latest version!\n`);
904
+ }
905
+ } catch (err) {
906
+ console.error('\nCould not check for updates. Check your internet connection.\n');
907
+ }
908
+ },
909
+
821
910
  help() {
822
911
  console.log(`
823
912
  kspec - Spec-driven development for Kiro CLI
@@ -847,6 +936,7 @@ Other:
847
936
  kspec list List all specs
848
937
  kspec status Current status
849
938
  kspec agents List agents
939
+ kspec update Check for updates
850
940
  kspec help Show this help
851
941
 
852
942
  Examples:
@@ -858,14 +948,17 @@ Examples:
858
948
  };
859
949
 
860
950
  async function run(args) {
951
+ // Check for updates (non-blocking, cached for 24h)
952
+ checkForUpdates();
953
+
861
954
  // Handle standard CLI flags first
862
955
  if (args.includes('--help') || args.includes('-h')) {
863
956
  return commands.help();
864
957
  }
865
-
958
+
866
959
  if (args.includes('--version') || args.includes('-v')) {
867
- const pkg = require('../package.json');
868
- console.log(pkg.version);
960
+ // Show version and check for updates
961
+ await commands.update();
869
962
  return;
870
963
  }
871
964
 
@@ -879,4 +972,4 @@ async function run(args) {
879
972
  }
880
973
  }
881
974
 
882
- module.exports = { run, commands, loadConfig, detectCli, requireCli, agentTemplates, getTaskStats, refreshContext, getCurrentTask };
975
+ module.exports = { run, commands, loadConfig, detectCli, requireCli, agentTemplates, getTaskStats, refreshContext, getCurrentTask, checkForUpdates, compareVersions };