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.
- package/.claude/helpers/statusline.cjs +139 -3
- package/README.md +3 -2
- package/package.json +1 -1
- package/v3/@swarmdo/cli/.claude/commands/sDo/agents/README.md +1 -1
- package/v3/@swarmdo/cli/.claude/commands/sDo/agents/agent-capabilities.md +1 -1
- package/v3/@swarmdo/cli/.claude/commands/sDo/agents/agent-types.md +2 -2
- package/v3/@swarmdo/cli/.claude/commands/sDo/swarm/swarm.md +1 -1
- package/v3/@swarmdo/cli/.claude/helpers/statusline.cjs +770 -498
- package/v3/@swarmdo/cli/.claude/skills/sdo-agentic-jujutsu/SKILL.md +645 -0
- package/v3/@swarmdo/cli/.claude/skills/sdo-hive-mind-advanced/SKILL.md +709 -0
- package/v3/@swarmdo/cli/.claude/skills/sdo-performance-analysis/SKILL.md +560 -0
- package/v3/@swarmdo/cli/dist/src/commands/integrations.js +185 -2
- package/v3/@swarmdo/cli/dist/src/commands/statusline.d.ts +22 -1
- package/v3/@swarmdo/cli/dist/src/commands/statusline.js +84 -3
- package/v3/@swarmdo/cli/dist/src/init/statusline-generator.js +138 -2
- package/v3/@swarmdo/cli/dist/src/integrations/skills-sync.d.ts +120 -0
- package/v3/@swarmdo/cli/dist/src/integrations/skills-sync.js +180 -0
- package/v3/@swarmdo/cli/dist/src/usage/account-plan.d.ts +48 -0
- package/v3/@swarmdo/cli/dist/src/usage/account-plan.js +71 -0
- package/v3/@swarmdo/cli/package.json +1 -1
|
@@ -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.
|
|
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",
|