agenticloops 0.1.1 → 0.1.2

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/bin/cli.mjs CHANGED
@@ -7,7 +7,7 @@ import { listRecords, parseSchedule } from "../src/schedule.mjs";
7
7
  import { fetchInstalls } from "../src/telemetry.mjs";
8
8
  import { c, sym, fail, info, CliError } from "../src/util.mjs";
9
9
 
10
- const VERSION = "0.1.1";
10
+ const VERSION = "0.1.2";
11
11
 
12
12
  function parseArgs(argv) {
13
13
  const flags = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenticloops",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Install and run agentic loops — recurring AI agents defined in a single LOOP.md file. One file defines it; any harness can run it.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/config.mjs CHANGED
@@ -15,4 +15,4 @@ export const SKILLS_REGISTRY_URL = "https://skills.sh/index.json";
15
15
  export const SPEC_VERSION = "0.1";
16
16
 
17
17
  // User-Agent so server logs can attribute pings to the CLI (still anonymous).
18
- export const UA = `agenticloops-cli/0.1.1 (+${SITE})`;
18
+ export const UA = `agenticloops-cli/0.1.2 (+${SITE})`;
package/src/harness.mjs CHANGED
@@ -2,8 +2,9 @@
2
2
  // loop's skills, honor its trigger, and run the prompt. Crucially, a loop needs
3
3
  // SCHEDULING — a harness that can only run interactively (an IDE) can run the
4
4
  // agent but cannot honor a recurring trigger; we warn when targeting one.
5
- import { existsSync } from "node:fs";
5
+ import { existsSync, readdirSync, statSync } from "node:fs";
6
6
  import { join } from "node:path";
7
+ import { homedir } from "node:os";
7
8
  import { execSync } from "node:child_process";
8
9
 
9
10
  function has(bin) {
@@ -53,6 +54,32 @@ export function getHarness(id) {
53
54
  return HARNESSES.find((h) => h.id === id);
54
55
  }
55
56
 
57
+ // Where each harness keeps installed skills (a dir of <skill>/SKILL.md). Used
58
+ // to mark a skill "host-satisfied" only when it's VERIFIABLY present, so the
59
+ // skip is honest — never an asserted-but-unchecked built-in.
60
+ const SKILL_DIRS = {
61
+ "claude-code": [join(homedir(), ".claude", "skills")],
62
+ cursor: [join(homedir(), ".cursor", "skills")],
63
+ "5dive": [join(homedir(), ".claude", "skills")],
64
+ };
65
+
66
+ export function hostSkillsFor(harnessId) {
67
+ const dirs = SKILL_DIRS[harnessId] || [];
68
+ const found = new Set();
69
+ for (const dir of dirs) {
70
+ if (!existsSync(dir)) continue;
71
+ try {
72
+ for (const name of readdirSync(dir)) {
73
+ const p = join(dir, name);
74
+ if (statSync(p).isDirectory() && existsSync(join(p, "SKILL.md"))) found.add(name);
75
+ }
76
+ } catch {
77
+ /* unreadable dir — skip */
78
+ }
79
+ }
80
+ return [...found];
81
+ }
82
+
56
83
  // Auto-detect: prefer a schedulable harness when several are present, since a
57
84
  // loop's whole point is the recurring trigger. Returns { harness, all }.
58
85
  export function detectHarness(cwd = process.cwd()) {
package/src/install.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  // pre-flight `requires` (prompt-or-refuse, never auto-install) -> register the
3
3
  // scheduled job -> (on success) anonymous telemetry ping.
4
4
  import { fetchLoopMd, parseLoopMd, validateManifest, triggerOf } from "./loop.mjs";
5
- import { detectHarness, getHarness } from "./harness.mjs";
5
+ import { detectHarness, getHarness, hostSkillsFor } from "./harness.mjs";
6
6
  import { planSkills, installSkill } from "./skills.mjs";
7
7
  import { preflight } from "./preflight.mjs";
8
8
  import { parseSchedule, registerTrigger, saveRecord } from "./schedule.mjs";
@@ -71,7 +71,9 @@ export async function install(ref, opts = {}) {
71
71
  }
72
72
 
73
73
  // 3. Install skills (§3.1) — host-satisfied skipped, paths fetched, bare resolved.
74
- const skillPlan = await planSkills(manifest.skills || [], opts.hostSkills || []);
74
+ // Host-satisfied = verifiably present in the harness's skills dir (not asserted).
75
+ const hostSkills = [...new Set([...(opts.hostSkills || []), ...hostSkillsFor(harness.id)])];
76
+ const skillPlan = await planSkills(manifest.skills || [], hostSkills);
75
77
  if (skillPlan.length) {
76
78
  step("Skills");
77
79
  for (const s of skillPlan) {