gm-skill 2.0.2187 → 2.0.2189

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.
@@ -676,7 +676,10 @@ function spawnPinnedBoot(extraArgs) {
676
676
  return { ok: true, pinned_version: pinned, duration_ms: durationMs, status: result.status };
677
677
  }
678
678
 
679
- function discoverBundledSkillsAndSources() {
679
+ const SKILL_MD_REMOTE_REPO = 'AnEntrypoint/gm';
680
+ const SKILL_MD_REMOTE_BRANCH = 'main';
681
+
682
+ function discoverBundledSkillsAndSourcesLocal() {
680
683
  const found = new Map();
681
684
  try {
682
685
  for (const f of fs.readdirSync(__dirname)) {
@@ -704,20 +707,66 @@ function discoverBundledSkillsAndSources() {
704
707
  return found;
705
708
  }
706
709
 
707
- function ensureSkillMdFresh() {
710
+ async function discoverRemoteSkillNames(timeoutMs) {
711
+ const url = `https://api.github.com/repos/${SKILL_MD_REMOTE_REPO}/contents/skills?ref=${SKILL_MD_REMOTE_BRANCH}`;
712
+ const buf = await httpGetBuffer(url, timeoutMs || 5000);
713
+ const entries = JSON.parse(buf.toString('utf-8'));
714
+ if (!Array.isArray(entries)) throw new Error('unexpected github contents API response shape');
715
+ return entries.filter(e => e && e.type === 'dir' && e.name).map(e => e.name);
716
+ }
717
+
718
+ async function fetchRemoteSkillMd(skillName, timeoutMs) {
719
+ const url = `https://raw.githubusercontent.com/${SKILL_MD_REMOTE_REPO}/${SKILL_MD_REMOTE_BRANCH}/skills/${skillName}/SKILL.md`;
720
+ const buf = await httpGetBuffer(url, timeoutMs || 8000);
721
+ return buf.toString('utf-8');
722
+ }
723
+
724
+ async function resolveSkillMdSource(skillName, localPath) {
725
+ if (localPath && fs.existsSync(localPath)) {
726
+ return { content: fs.readFileSync(localPath, 'utf-8'), origin: localPath };
727
+ }
728
+ const content = await fetchRemoteSkillMd(skillName, 8000);
729
+ return { content, origin: `https://raw.githubusercontent.com/${SKILL_MD_REMOTE_REPO}/${SKILL_MD_REMOTE_BRANCH}/skills/${skillName}/SKILL.md` };
730
+ }
731
+
732
+ async function ensureSkillMdFresh() {
708
733
  const home = process.env.HOME || process.env.USERPROFILE || require('os').homedir();
709
734
  const crypto = require('crypto');
710
735
  const _norm = s => s.replace(/\r\n/g, '\n');
711
736
  const allRefreshed = [];
712
737
  const sources = {};
713
- const discovered = discoverBundledSkillsAndSources();
714
- for (const [skillName, bundledPath] of discovered) {
738
+ const failures = [];
739
+
740
+ const localFound = discoverBundledSkillsAndSourcesLocal();
741
+ let skillNames = Array.from(localFound.keys());
742
+ let remoteNamesFetched = false;
743
+ try {
744
+ const remoteNames = await discoverRemoteSkillNames(5000);
745
+ remoteNamesFetched = true;
746
+ for (const n of remoteNames) if (!skillNames.includes(n)) skillNames.push(n);
747
+ } catch (e) {
748
+ obsEvent('bootstrap', 'skill-md.refresh.remote-name-discovery-failed', { error: e.message });
749
+ }
750
+
751
+ if (skillNames.length === 0) {
752
+ const msg = `SKILL.md refresh found zero bundled skills: local dev-tree lookup empty AND remote discovery ${remoteNamesFetched ? 'returned zero dirs' : 'failed'} against ${SKILL_MD_REMOTE_REPO}@${SKILL_MD_REMOTE_BRANCH}`;
753
+ log(`ERROR: ${msg}`);
754
+ try { obsEvent('bootstrap', 'skill-md.refresh.zero-skills-discovered', { dir: __dirname, remote_repo: SKILL_MD_REMOTE_REPO, remote_branch: SKILL_MD_REMOTE_BRANCH, remote_names_fetched: remoteNamesFetched }); } catch (_) {}
755
+ return { refreshed: [], sources: {}, failures: [{ skillName: null, error: msg }] };
756
+ }
757
+
758
+ for (const skillName of skillNames) {
715
759
  try {
716
- if (!fs.existsSync(bundledPath)) {
717
- try { obsEvent('bootstrap', 'skill-md.refresh.bundled-not-found', { skillName, searched: [bundledPath] }); } catch (_) {}
760
+ const localPath = localFound.get(skillName) || null;
761
+ let resolved;
762
+ try {
763
+ resolved = await resolveSkillMdSource(skillName, localPath);
764
+ } catch (e) {
765
+ try { obsEvent('bootstrap', 'skill-md.refresh.bundled-not-found', { skillName, searched: [localPath, `https://raw.githubusercontent.com/${SKILL_MD_REMOTE_REPO}/${SKILL_MD_REMOTE_BRANCH}/skills/${skillName}/SKILL.md`], error: e.message }); } catch (_) {}
766
+ failures.push({ skillName, error: e.message });
718
767
  continue;
719
768
  }
720
- const bundled = fs.readFileSync(bundledPath, 'utf-8');
769
+ const bundled = resolved.content;
721
770
  const bundledHash = crypto.createHash('sha256').update(_norm(bundled)).digest('hex');
722
771
  const targets = [
723
772
  path.join(home, '.agents', 'skills', skillName, 'SKILL.md'),
@@ -731,7 +780,7 @@ function ensureSkillMdFresh() {
731
780
  try { if (fs.existsSync(legacy)) fs.rmSync(legacy, { recursive: true, force: true }); } catch (_) {}
732
781
  }
733
782
  }
734
- sources[skillName] = bundledPath;
783
+ sources[skillName] = resolved.origin;
735
784
  for (const target of targets) {
736
785
  try {
737
786
  let needsWrite = true;
@@ -753,13 +802,14 @@ function ensureSkillMdFresh() {
753
802
  }
754
803
  } catch (e) {
755
804
  try { obsEvent('bootstrap', 'skill-md.refresh.failed', { skillName, error: e.message }); } catch (_) {}
805
+ failures.push({ skillName, error: e.message });
756
806
  }
757
807
  }
758
808
  if (allRefreshed.length > 0) {
759
809
  log(`SKILL.md refreshed: ${allRefreshed.length} target(s)`);
760
810
  try { obsEvent('bootstrap', 'skill-md.refreshed', { targets: allRefreshed, sources }); } catch (_) {}
761
811
  }
762
- return { refreshed: allRefreshed, sources };
812
+ return { refreshed: allRefreshed, sources, failures };
763
813
  }
764
814
 
765
815
  function installedVersionAtTools() {
@@ -867,7 +917,7 @@ async function ensureReady(opts) {
867
917
  if (isReady() && !versionDrift) {
868
918
  const wasmPath = getWasmPath();
869
919
  const versionMarkerUpdated = ensureGmPlugkitVersionFresh();
870
- ensureSkillMdFresh();
920
+ await ensureSkillMdFresh();
871
921
  return { ok: true, wasmPath, binaryPath: wasmPath, status: versionMarkerUpdated ? 'version-refreshed' : 'already-ready', version: installed };
872
922
  }
873
923
  if (targetVersion && targetVersion !== pinnedVersion) {
@@ -885,7 +935,7 @@ async function ensureReady(opts) {
885
935
  if (versionDrift && isReady()) {
886
936
  log(`bootstrap for ${targetVersion} failed (${bootErr.message || bootErr}); keeping running watcher on installed ${installed} (no kill, serve cached wasm)`);
887
937
  const cachedPath = getWasmPath();
888
- ensureSkillMdFresh();
938
+ await ensureSkillMdFresh();
889
939
  return { ok: true, wasmPath: cachedPath, binaryPath: cachedPath, status: 'bootstrap-failed-served-cached', version: installed };
890
940
  }
891
941
  throw bootErr;
@@ -895,7 +945,7 @@ async function ensureReady(opts) {
895
945
  try { killSpoolWatcherInCwd(`version_drift:${installed}->${targetVersion}`); } catch (_) {}
896
946
  }
897
947
 
898
- ensureSkillMdFresh();
948
+ await ensureSkillMdFresh();
899
949
  return { ok: true, wasmPath, binaryPath: wasmPath, status: 'bootstrapped', version: targetVersion || installed };
900
950
  }
901
951
 
package/gm-plugkit/cli.js CHANGED
@@ -178,7 +178,7 @@ function tryDelegateToRunner(args) {
178
178
  if (statusServing(already, 12000) && !versionDrifted) {
179
179
  try { ensureGmPlugkitVersionFresh(); } catch (_) {}
180
180
  let skillRefresh = null;
181
- try { skillRefresh = ensureSkillMdFresh(); } catch (_) {}
181
+ try { skillRefresh = await ensureSkillMdFresh(); } catch (_) {}
182
182
  writeCliStatus({ phase: 'ready', already_serving: true, watcher_pid: already.pid });
183
183
  console.log(JSON.stringify({
184
184
  ok: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.2187",
3
+ "version": "2.0.2189",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -15,6 +15,8 @@
15
15
  "gm-process.js",
16
16
  "plugkit.version",
17
17
  "plugkit.sha256",
18
+ "SKILL.md",
19
+ "SKILL-*.md",
18
20
  "instructions/"
19
21
  ],
20
22
  "keywords": [
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.2187",
3
+ "version": "2.0.2189",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.2187",
3
+ "version": "2.0.2189",
4
4
  "description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",