swarmdo 1.58.6 → 1.58.12

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.
@@ -0,0 +1,120 @@
1
+ /**
2
+ * skills-sync.ts — sync curated swarmdo skills into the cross-agent skill dirs.
3
+ *
4
+ * SKILL.md is a universal cross-agent standard (2026): Codex, pi, Copilot, and
5
+ * Cursor all read skills from a `<dir>/SKILL.md` layout with `name`+`description`
6
+ * YAML frontmatter. swarmdo already ships its surface as `sdo-*` skills, so the
7
+ * "integration" for these tools is a near-passthrough copy — no per-tool format
8
+ * conversion, no deprecated Codex `~/.codex/prompts` (removed in favour of skills)
9
+ * and no Copilot slash-command dir (Copilot CLI has none).
10
+ *
11
+ * Targets (GLOBAL scope — every project the user opens):
12
+ * shared → ~/.agents/skills/ the cross-client convention (Codex, pi,
13
+ * Copilot, Cursor all scan it)
14
+ * codex → ~/.codex/skills/ Codex's own global dir (guaranteed pickup)
15
+ * pi → ~/.pi/agent/skills/ pi's own global dir (guaranteed pickup)
16
+ *
17
+ * Every function here is PURE (data in → data out) so the whole surface is
18
+ * unit-testable and re-running the sync never duplicates or clobbers. All fs
19
+ * lives in the command layer (commands/integrations.ts).
20
+ *
21
+ * INVARIANT (do-not-break-Claude): nothing here targets `.claude/**` — the
22
+ * Claude Code skill surface is owned by `swarmdo init`/`efficiency` and is only
23
+ * ever the READ source, never a write target.
24
+ */
25
+ export type SkillTarget = 'shared' | 'codex' | 'pi';
26
+ export declare const SKILL_TARGETS: SkillTarget[];
27
+ /**
28
+ * Curated essentials — the ~20 skills worth exposing to non-Claude agents.
29
+ * An explicit allowlist (not "everything minus internal") so the cross-agent
30
+ * surface stays a deliberate, stable set. Excludes: the swarmdo-internal
31
+ * `sdo-v3-*` build skills, `sdo-dual-mode` (no SKILL.md), and
32
+ * `sdo-caveman-compress` (Claude-slash-command-bound; bundles python bytecode).
33
+ */
34
+ export declare const CURATED_SKILLS: string[];
35
+ /** Manifest dropped at each target root so `--remove`/reconcile only ever
36
+ * touches the exact `sdo-*` dirs swarmdo installed — never a user's own or
37
+ * another tool's skills. */
38
+ export declare const SKILLS_MANIFEST = ".swarmdo-skills.json";
39
+ /**
40
+ * Intersect the curated allowlist with what's actually on disk, preserving
41
+ * curated order. Absent skills are silently skipped so a trimmed package (the
42
+ * standalone build ships a subset) never errors.
43
+ */
44
+ export declare function curateSkills(available: readonly string[]): string[];
45
+ /** The global skills root for a target under `home`. */
46
+ export declare function skillTargetRoot(home: string, target: SkillTarget): string;
47
+ /**
48
+ * Rewrite a skill's SKILL.md for cross-agent portability. The cross-agent spec
49
+ * requires `name` to equal the skill's directory name; swarmdo's source uses a
50
+ * pretty display name (`name: "Swarm Orchestration"`), so we force `name` to the
51
+ * `sdo-*` slug and preserve everything else (crucially `description`, the field
52
+ * agents match on to decide when to activate). Missing frontmatter is repaired.
53
+ */
54
+ export declare function normalizeSkillMd(slug: string, raw: string): string;
55
+ /** Serialize the ownership manifest (deterministic — no timestamps). */
56
+ export declare function buildManifest(slugs: readonly string[], version: string): string;
57
+ /** Read the skill slugs a prior sync recorded at a target root (null = none). */
58
+ export declare function parseManifestSkills(raw: string | null): string[];
59
+ export interface PlannedSkillWrite {
60
+ target: SkillTarget;
61
+ slug: string;
62
+ /** absolute path of the SKILL.md to write */
63
+ path: string;
64
+ content: string;
65
+ }
66
+ export interface PlannedManifest {
67
+ target: SkillTarget;
68
+ path: string;
69
+ content: string;
70
+ }
71
+ export interface StaleSkillDir {
72
+ target: SkillTarget;
73
+ slug: string;
74
+ /** absolute path of the skill directory to delete */
75
+ path: string;
76
+ }
77
+ export interface SkillSyncPlan {
78
+ writes: PlannedSkillWrite[];
79
+ manifests: PlannedManifest[];
80
+ /** dirs from a PRIOR sync that are no longer curated — pruned on --apply */
81
+ stale: StaleSkillDir[];
82
+ }
83
+ /**
84
+ * Plan a sync. Pure: given the curated skills (already read from the source) and
85
+ * the previously-installed slugs per target (from each manifest), produce the
86
+ * exact writes, per-root manifests, and the stale dirs to reconcile away. All
87
+ * curated skills are single-file SKILL.md (bundled-resource skills are excluded
88
+ * from the allowlist), so one write per skill per target.
89
+ */
90
+ export declare function planSkillSync(opts: {
91
+ home: string;
92
+ targets: readonly SkillTarget[];
93
+ skills: ReadonlyArray<{
94
+ slug: string;
95
+ skillMd: string;
96
+ }>;
97
+ version: string;
98
+ previous?: ReadonlyArray<{
99
+ target: SkillTarget;
100
+ slugs: readonly string[];
101
+ }>;
102
+ }): SkillSyncPlan;
103
+ export interface SkillRemovePlan {
104
+ dirs: StaleSkillDir[];
105
+ manifests: PlannedManifest[];
106
+ }
107
+ /**
108
+ * Plan a full uninstall. Pure: given the installed slugs per target (from the
109
+ * manifests), produce every skill dir to delete plus the manifest files to drop.
110
+ * Only ever names slugs the manifest recorded, so a user's own skills in the
111
+ * same root are untouched.
112
+ */
113
+ export declare function planSkillRemove(opts: {
114
+ home: string;
115
+ installed: ReadonlyArray<{
116
+ target: SkillTarget;
117
+ slugs: readonly string[];
118
+ }>;
119
+ }): SkillRemovePlan;
120
+ //# sourceMappingURL=skills-sync.d.ts.map
@@ -0,0 +1,180 @@
1
+ /**
2
+ * skills-sync.ts — sync curated swarmdo skills into the cross-agent skill dirs.
3
+ *
4
+ * SKILL.md is a universal cross-agent standard (2026): Codex, pi, Copilot, and
5
+ * Cursor all read skills from a `<dir>/SKILL.md` layout with `name`+`description`
6
+ * YAML frontmatter. swarmdo already ships its surface as `sdo-*` skills, so the
7
+ * "integration" for these tools is a near-passthrough copy — no per-tool format
8
+ * conversion, no deprecated Codex `~/.codex/prompts` (removed in favour of skills)
9
+ * and no Copilot slash-command dir (Copilot CLI has none).
10
+ *
11
+ * Targets (GLOBAL scope — every project the user opens):
12
+ * shared → ~/.agents/skills/ the cross-client convention (Codex, pi,
13
+ * Copilot, Cursor all scan it)
14
+ * codex → ~/.codex/skills/ Codex's own global dir (guaranteed pickup)
15
+ * pi → ~/.pi/agent/skills/ pi's own global dir (guaranteed pickup)
16
+ *
17
+ * Every function here is PURE (data in → data out) so the whole surface is
18
+ * unit-testable and re-running the sync never duplicates or clobbers. All fs
19
+ * lives in the command layer (commands/integrations.ts).
20
+ *
21
+ * INVARIANT (do-not-break-Claude): nothing here targets `.claude/**` — the
22
+ * Claude Code skill surface is owned by `swarmdo init`/`efficiency` and is only
23
+ * ever the READ source, never a write target.
24
+ */
25
+ import * as path from 'node:path';
26
+ export const SKILL_TARGETS = ['shared', 'codex', 'pi'];
27
+ /**
28
+ * Curated essentials — the ~20 skills worth exposing to non-Claude agents.
29
+ * An explicit allowlist (not "everything minus internal") so the cross-agent
30
+ * surface stays a deliberate, stable set. Excludes: the swarmdo-internal
31
+ * `sdo-v3-*` build skills, `sdo-dual-mode` (no SKILL.md), and
32
+ * `sdo-caveman-compress` (Claude-slash-command-bound; bundles python bytecode).
33
+ */
34
+ export const CURATED_SKILLS = [
35
+ // memory + intelligence (swarmdo's core differentiator)
36
+ 'sdo-agentdb-memory-patterns',
37
+ 'sdo-agentdb-vector-search',
38
+ 'sdo-agentdb-optimization',
39
+ 'sdo-reasoningbank-intelligence',
40
+ // swarm + coordination
41
+ 'sdo-swarm-orchestration',
42
+ 'sdo-swarm-advanced',
43
+ 'sdo-hive-mind-advanced',
44
+ 'sdo-hooks-automation',
45
+ // github
46
+ 'sdo-github-code-review',
47
+ 'sdo-github-workflow-automation',
48
+ 'sdo-github-multi-repo',
49
+ 'sdo-github-release-management',
50
+ 'sdo-github-project-management',
51
+ // methodology + quality
52
+ 'sdo-sparc-methodology',
53
+ 'sdo-verification-quality',
54
+ 'sdo-pair-programming',
55
+ 'sdo-performance-analysis',
56
+ // tooling
57
+ 'sdo-stream-chain',
58
+ 'sdo-browser',
59
+ 'sdo-agentic-jujutsu',
60
+ ];
61
+ /** Manifest dropped at each target root so `--remove`/reconcile only ever
62
+ * touches the exact `sdo-*` dirs swarmdo installed — never a user's own or
63
+ * another tool's skills. */
64
+ export const SKILLS_MANIFEST = '.swarmdo-skills.json';
65
+ /**
66
+ * Intersect the curated allowlist with what's actually on disk, preserving
67
+ * curated order. Absent skills are silently skipped so a trimmed package (the
68
+ * standalone build ships a subset) never errors.
69
+ */
70
+ export function curateSkills(available) {
71
+ const have = new Set(available);
72
+ return CURATED_SKILLS.filter((s) => have.has(s));
73
+ }
74
+ /** The global skills root for a target under `home`. */
75
+ export function skillTargetRoot(home, target) {
76
+ switch (target) {
77
+ case 'shared':
78
+ return path.join(home, '.agents', 'skills');
79
+ case 'codex':
80
+ return path.join(home, '.codex', 'skills');
81
+ case 'pi':
82
+ return path.join(home, '.pi', 'agent', 'skills');
83
+ }
84
+ }
85
+ /**
86
+ * Rewrite a skill's SKILL.md for cross-agent portability. The cross-agent spec
87
+ * requires `name` to equal the skill's directory name; swarmdo's source uses a
88
+ * pretty display name (`name: "Swarm Orchestration"`), so we force `name` to the
89
+ * `sdo-*` slug and preserve everything else (crucially `description`, the field
90
+ * agents match on to decide when to activate). Missing frontmatter is repaired.
91
+ */
92
+ export function normalizeSkillMd(slug, raw) {
93
+ const nameLine = `name: "${slug}"`;
94
+ const fm = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n/.exec(raw);
95
+ if (!fm) {
96
+ // No frontmatter — synthesize a minimal valid header.
97
+ return `---\n${nameLine}\ndescription: "swarmdo skill: ${slug}"\n---\n\n${raw.replace(/^\r?\n+/, '')}`;
98
+ }
99
+ const body = raw.slice(fm[0].length).replace(/^\r?\n+/, '');
100
+ let sawName = false;
101
+ const inner = fm[1].split(/\r?\n/).map((ln) => {
102
+ if (/^\s*name\s*:/.test(ln)) {
103
+ sawName = true;
104
+ return nameLine;
105
+ }
106
+ return ln;
107
+ });
108
+ if (!sawName)
109
+ inner.unshift(nameLine);
110
+ return `---\n${inner.join('\n')}\n---\n\n${body}`;
111
+ }
112
+ /** Serialize the ownership manifest (deterministic — no timestamps). */
113
+ export function buildManifest(slugs, version) {
114
+ return (JSON.stringify({ managedBy: 'swarmdo integrations skills', version, skills: [...slugs] }, null, 2) + '\n');
115
+ }
116
+ /** Read the skill slugs a prior sync recorded at a target root (null = none). */
117
+ export function parseManifestSkills(raw) {
118
+ if (!raw)
119
+ return [];
120
+ try {
121
+ const j = JSON.parse(raw);
122
+ return Array.isArray(j.skills) ? j.skills.filter((x) => typeof x === 'string') : [];
123
+ }
124
+ catch {
125
+ return [];
126
+ }
127
+ }
128
+ /**
129
+ * Plan a sync. Pure: given the curated skills (already read from the source) and
130
+ * the previously-installed slugs per target (from each manifest), produce the
131
+ * exact writes, per-root manifests, and the stale dirs to reconcile away. All
132
+ * curated skills are single-file SKILL.md (bundled-resource skills are excluded
133
+ * from the allowlist), so one write per skill per target.
134
+ */
135
+ export function planSkillSync(opts) {
136
+ const { home, targets, skills, version } = opts;
137
+ const prevByTarget = new Map();
138
+ for (const p of opts.previous ?? [])
139
+ prevByTarget.set(p.target, new Set(p.slugs));
140
+ const slugs = skills.map((s) => s.slug);
141
+ const nextSet = new Set(slugs);
142
+ const writes = [];
143
+ const manifests = [];
144
+ const stale = [];
145
+ for (const target of targets) {
146
+ const root = skillTargetRoot(home, target);
147
+ for (const { slug, skillMd } of skills) {
148
+ writes.push({
149
+ target,
150
+ slug,
151
+ path: path.join(root, slug, 'SKILL.md'),
152
+ content: normalizeSkillMd(slug, skillMd),
153
+ });
154
+ }
155
+ manifests.push({ target, path: path.join(root, SKILLS_MANIFEST), content: buildManifest(slugs, version) });
156
+ for (const old of prevByTarget.get(target) ?? []) {
157
+ if (!nextSet.has(old))
158
+ stale.push({ target, slug: old, path: path.join(root, old) });
159
+ }
160
+ }
161
+ return { writes, manifests, stale };
162
+ }
163
+ /**
164
+ * Plan a full uninstall. Pure: given the installed slugs per target (from the
165
+ * manifests), produce every skill dir to delete plus the manifest files to drop.
166
+ * Only ever names slugs the manifest recorded, so a user's own skills in the
167
+ * same root are untouched.
168
+ */
169
+ export function planSkillRemove(opts) {
170
+ const dirs = [];
171
+ const manifests = [];
172
+ for (const { target, slugs } of opts.installed) {
173
+ const root = skillTargetRoot(opts.home, target);
174
+ for (const slug of slugs)
175
+ dirs.push({ target, slug, path: path.join(root, slug) });
176
+ manifests.push({ target, path: path.join(root, SKILLS_MANIFEST), content: '' });
177
+ }
178
+ return { dirs, manifests };
179
+ }
180
+ //# sourceMappingURL=skills-sync.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * account-plan.ts — decide what the statusline "cost" slot should mean for the
3
+ * currently-authenticated Claude account.
4
+ *
5
+ * Claude Code stores the active account in `~/.claude.json` under `oauthAccount`
6
+ * and OVERWRITES it on account switch — it never records history, and the
7
+ * transcript is account-blind. So the only reliable signal is "who is logged in
8
+ * right now", read live at render time. From that we pick the metric:
9
+ *
10
+ * - subscription (Max/Team/Enterprise/Pro, flat fee) → a dollar figure is a
11
+ * phantom you never pay; show rate-limit % instead.
12
+ * - pay-as-you-go (API/console usage billing) → the dollar figure is real.
13
+ *
14
+ * Pure + injectable (no fs here) so it is unit-tested against literal account
15
+ * objects. The statusline shim reads the file and passes the object in.
16
+ */
17
+ /** The subset of `~/.claude.json.oauthAccount` we look at (never tokens). */
18
+ export interface OAuthAccountLike {
19
+ billingType?: unknown;
20
+ organizationType?: unknown;
21
+ /** shown only when the user opts into --show-account */
22
+ displayName?: unknown;
23
+ organizationName?: unknown;
24
+ }
25
+ export type Plan = 'subscription' | 'payg' | 'unknown';
26
+ /** How the user configured the cost slot. `auto` defers to the detected plan. */
27
+ export type CostMode = 'auto' | 'dollars' | 'limits' | 'off';
28
+ /** What the slot actually renders after resolving `auto` against the plan. */
29
+ export type EffectiveCostMode = 'dollars' | 'limits' | 'off';
30
+ /**
31
+ * Classify the active account. Subscription when the billing type is a
32
+ * subscription OR the org is a Claude consumer/team plan; pay-as-you-go when a
33
+ * known non-subscription billing type is present; unknown when we can't tell
34
+ * (no account, unrecognized shape) — callers treat unknown like payg so a real
35
+ * dollar figure still shows rather than a blank.
36
+ */
37
+ export declare function detectPlan(account: OAuthAccountLike | null | undefined): Plan;
38
+ /**
39
+ * Resolve the configured mode against the detected plan into what to actually
40
+ * render. `auto` → limits for subscription, dollars otherwise. Explicit modes
41
+ * pass through unchanged (the user overrides the heuristic on purpose).
42
+ */
43
+ export declare function resolveEffectiveCostMode(mode: CostMode, plan: Plan): EffectiveCostMode;
44
+ /** A short, screenshare-safe account label. Prefers displayName, then org. */
45
+ export declare function accountLabel(account: OAuthAccountLike | null | undefined, maxLen?: number): string;
46
+ /** Normalize a raw cost-mode string (env/config) to a valid CostMode or null. */
47
+ export declare function parseCostMode(raw: unknown): CostMode | null;
48
+ //# sourceMappingURL=account-plan.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * account-plan.ts — decide what the statusline "cost" slot should mean for the
3
+ * currently-authenticated Claude account.
4
+ *
5
+ * Claude Code stores the active account in `~/.claude.json` under `oauthAccount`
6
+ * and OVERWRITES it on account switch — it never records history, and the
7
+ * transcript is account-blind. So the only reliable signal is "who is logged in
8
+ * right now", read live at render time. From that we pick the metric:
9
+ *
10
+ * - subscription (Max/Team/Enterprise/Pro, flat fee) → a dollar figure is a
11
+ * phantom you never pay; show rate-limit % instead.
12
+ * - pay-as-you-go (API/console usage billing) → the dollar figure is real.
13
+ *
14
+ * Pure + injectable (no fs here) so it is unit-tested against literal account
15
+ * objects. The statusline shim reads the file and passes the object in.
16
+ */
17
+ const SUBSCRIPTION_BILLING = /subscription/i; // e.g. "stripe_subscription"
18
+ const SUBSCRIPTION_ORG = /claude_(max|team|enterprise|pro)/i; // e.g. "claude_max"
19
+ /**
20
+ * Classify the active account. Subscription when the billing type is a
21
+ * subscription OR the org is a Claude consumer/team plan; pay-as-you-go when a
22
+ * known non-subscription billing type is present; unknown when we can't tell
23
+ * (no account, unrecognized shape) — callers treat unknown like payg so a real
24
+ * dollar figure still shows rather than a blank.
25
+ */
26
+ export function detectPlan(account) {
27
+ if (!account || typeof account !== 'object')
28
+ return 'unknown';
29
+ const billing = typeof account.billingType === 'string' ? account.billingType : '';
30
+ const org = typeof account.organizationType === 'string' ? account.organizationType : '';
31
+ if (SUBSCRIPTION_BILLING.test(billing) || SUBSCRIPTION_ORG.test(org))
32
+ return 'subscription';
33
+ if (billing)
34
+ return 'payg'; // a known, non-subscription billing type
35
+ return 'unknown';
36
+ }
37
+ /**
38
+ * Resolve the configured mode against the detected plan into what to actually
39
+ * render. `auto` → limits for subscription, dollars otherwise. Explicit modes
40
+ * pass through unchanged (the user overrides the heuristic on purpose).
41
+ */
42
+ export function resolveEffectiveCostMode(mode, plan) {
43
+ if (mode === 'off')
44
+ return 'off';
45
+ if (mode === 'dollars')
46
+ return 'dollars';
47
+ if (mode === 'limits')
48
+ return 'limits';
49
+ // auto
50
+ return plan === 'subscription' ? 'limits' : 'dollars';
51
+ }
52
+ /** A short, screenshare-safe account label. Prefers displayName, then org. */
53
+ export function accountLabel(account, maxLen = 16) {
54
+ if (!account)
55
+ return '';
56
+ const raw = (typeof account.displayName === 'string' && account.displayName) ||
57
+ (typeof account.organizationName === 'string' && account.organizationName) ||
58
+ '';
59
+ const trimmed = raw.trim();
60
+ if (!trimmed)
61
+ return '';
62
+ return trimmed.length > maxLen ? trimmed.slice(0, maxLen - 1) + '…' : trimmed;
63
+ }
64
+ /** Normalize a raw cost-mode string (env/config) to a valid CostMode or null. */
65
+ export function parseCostMode(raw) {
66
+ if (typeof raw !== 'string')
67
+ return null;
68
+ const v = raw.trim().toLowerCase();
69
+ return v === 'auto' || v === 'dollars' || v === 'limits' || v === 'off' ? v : null;
70
+ }
71
+ //# sourceMappingURL=account-plan.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmdo/cli",
3
- "version": "1.58.6",
3
+ "version": "1.58.12",
4
4
  "type": "module",
5
5
  "description": "Swarmdo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",