swarmdo 1.27.0 → 1.29.0
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/auto-memory-hook.mjs +5 -1
- package/.claude-plugin/README.md +3 -3
- package/.claude-plugin/docs/INSTALLATION.md +1 -1
- package/.claude-plugin/docs/PLUGIN_SUMMARY.md +1 -1
- package/.claude-plugin/docs/QUICKSTART.md +3 -3
- package/.claude-plugin/hooks/hooks.json +19 -1
- package/.claude-plugin/marketplace.json +17 -17
- package/.claude-plugin/plugin.json +7 -39
- package/.claude-plugin/scripts/install.sh +3 -3
- package/.claude-plugin/scripts/swarmdo-hook.sh +1 -1
- package/.claude-plugin/scripts/verify.sh +2 -2
- package/README.md +10 -8
- package/package.json +1 -1
- package/v3/@swarmdo/cli/.claude/helpers/auto-memory-hook.mjs +5 -1
- package/v3/@swarmdo/cli/bin/cli.js +38 -0
- package/v3/@swarmdo/cli/dist/src/apply/apply.d.ts +6 -0
- package/v3/@swarmdo/cli/dist/src/apply/apply.js +41 -8
- package/v3/@swarmdo/cli/dist/src/commands/apply.js +17 -4
- package/v3/@swarmdo/cli/dist/src/commands/compact-snapshot.d.ts +17 -0
- package/v3/@swarmdo/cli/dist/src/commands/compact-snapshot.js +133 -0
- package/v3/@swarmdo/cli/dist/src/commands/index.js +4 -3
- package/v3/@swarmdo/cli/dist/src/commands/pack.d.ts +8 -0
- package/v3/@swarmdo/cli/dist/src/commands/pack.js +28 -2
- package/v3/@swarmdo/cli/dist/src/compact/compact.js +17 -7
- package/v3/@swarmdo/cli/dist/src/compact-snapshot/compact-snapshot.d.ts +58 -0
- package/v3/@swarmdo/cli/dist/src/compact-snapshot/compact-snapshot.js +104 -0
- package/v3/@swarmdo/cli/dist/src/config-lint/lint.js +16 -2
- package/v3/@swarmdo/cli/dist/src/init/helpers-generator.js +33 -3
- package/v3/@swarmdo/cli/dist/src/redact/redact.js +1 -1
- package/v3/@swarmdo/cli/dist/src/sbom/sbom.js +5 -2
- package/v3/@swarmdo/cli/dist/src/swarmvector/model-prices.js +12 -2
- package/v3/@swarmdo/cli/dist/src/testreport/testreport.js +11 -2
- package/v3/@swarmdo/cli/dist/src/transcript/export.d.ts +5 -0
- package/v3/@swarmdo/cli/dist/src/transcript/export.js +8 -1
- package/v3/@swarmdo/cli/dist/src/usage/claude-pricing.d.ts +6 -2
- package/v3/@swarmdo/cli/dist/src/usage/claude-pricing.js +33 -4
- package/v3/@swarmdo/cli/dist/src/usage/transcript-usage.js +1 -1
- package/v3/@swarmdo/cli/package.json +2 -2
|
@@ -11,14 +11,23 @@
|
|
|
11
11
|
* No XML dependency — well-formed JUnit escapes <>& in attribute values, so a
|
|
12
12
|
* focused tokenizer over <testcase>/<failure> is safe.
|
|
13
13
|
*/
|
|
14
|
-
/**
|
|
14
|
+
/** A numeric character reference → its char, or the original ref if the code
|
|
15
|
+
* point is out of the valid Unicode range (so a malformed entity never throws
|
|
16
|
+
* and leaks literally instead of aborting the parse). Pure. */
|
|
17
|
+
function fromCodePointSafe(n, original) {
|
|
18
|
+
return Number.isInteger(n) && n >= 0 && n <= 0x10ffff ? String.fromCodePoint(n) : original;
|
|
19
|
+
}
|
|
20
|
+
/** Decode the five predefined XML entities plus decimal AND hex numeric
|
|
21
|
+
* character references (`A`, ``). XML 1.0 allows both numeric forms;
|
|
22
|
+
* JUnit stack traces with ANSI colouring escape control chars as hex. Pure. */
|
|
15
23
|
function decodeXml(s) {
|
|
16
24
|
return s
|
|
17
25
|
.replace(/</g, '<')
|
|
18
26
|
.replace(/>/g, '>')
|
|
19
27
|
.replace(/"/g, '"')
|
|
20
28
|
.replace(/'/g, "'")
|
|
21
|
-
.replace(/&#(
|
|
29
|
+
.replace(/&#x([0-9a-fA-F]+);/g, (m, h) => fromCodePointSafe(parseInt(h, 16), m))
|
|
30
|
+
.replace(/&#(\d+);/g, (m, d) => fromCodePointSafe(parseInt(d, 10), m))
|
|
22
31
|
.replace(/&/g, '&'); // last, so &lt; → < not <
|
|
23
32
|
}
|
|
24
33
|
/**
|
|
@@ -45,6 +45,11 @@ export interface RenderOptions {
|
|
|
45
45
|
export declare function cleanUserText(s: string): string;
|
|
46
46
|
/** Flatten tool_result content (string | array of {text}) to text. */
|
|
47
47
|
export declare function contentToText(content: unknown): string;
|
|
48
|
+
/** Count the conversational turns in a rendered body by matching only the
|
|
49
|
+
* exact role-heading lines. Anchored to end-of-line so `### Foo` markdown
|
|
50
|
+
* headings written *inside* a user/assistant message don't inflate the count.
|
|
51
|
+
* Pure. */
|
|
52
|
+
export declare function countRenderedTurns(markdown: string): number;
|
|
48
53
|
/** Render an ordered list of parsed transcript lines into Markdown. */
|
|
49
54
|
export declare function renderTranscriptMarkdown(lines: RawTranscriptLine[], opts?: RenderOptions): string;
|
|
50
55
|
export interface SessionSummary {
|
|
@@ -92,6 +92,13 @@ function renderLine(role, content, opts) {
|
|
|
92
92
|
sections.push(results.join('\n'));
|
|
93
93
|
return sections.join('\n\n');
|
|
94
94
|
}
|
|
95
|
+
/** Count the conversational turns in a rendered body by matching only the
|
|
96
|
+
* exact role-heading lines. Anchored to end-of-line so `### Foo` markdown
|
|
97
|
+
* headings written *inside* a user/assistant message don't inflate the count.
|
|
98
|
+
* Pure. */
|
|
99
|
+
export function countRenderedTurns(markdown) {
|
|
100
|
+
return (markdown.match(/^### (?:🤖 Assistant|👤 User)$/gm) || []).length;
|
|
101
|
+
}
|
|
95
102
|
/** Render an ordered list of parsed transcript lines into Markdown. */
|
|
96
103
|
export function renderTranscriptMarkdown(lines, opts = {}) {
|
|
97
104
|
const resolved = {
|
|
@@ -202,7 +209,7 @@ export function exportSession(idOrLatest, opts = {}) {
|
|
|
202
209
|
const sessionId = sessionIdFromFile(file);
|
|
203
210
|
const project = path.basename(path.dirname(file));
|
|
204
211
|
const body = renderTranscriptMarkdown(lines, opts);
|
|
205
|
-
const turns = (body
|
|
212
|
+
const turns = countRenderedTurns(body);
|
|
206
213
|
const header = `# Claude Code session \`${sessionId}\`\n\n- Project: \`${project}\`\n- Turns: ${turns}\n\n---\n\n`;
|
|
207
214
|
return { markdown: header + body, sessionId, project, turns, file };
|
|
208
215
|
}
|
|
@@ -29,8 +29,12 @@ export interface TranscriptModelPrice {
|
|
|
29
29
|
* 'claude-sonnet-4-6@20260115' → 'claude-sonnet-4-6' (Vertex)
|
|
30
30
|
*/
|
|
31
31
|
export declare function normalizeTranscriptModelId(raw: string): string;
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Longest-prefix price lookup; undefined = unpriced (report it, don't guess).
|
|
34
|
+
* Pass the transcript entry's timestamp as `atMs` to get date-ranged promo
|
|
35
|
+
* rates (e.g. Sonnet 5 intro pricing); omitted → sticker price.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveTranscriptPrice(rawModelId: string, atMs?: number): TranscriptModelPrice | undefined;
|
|
34
38
|
/** Token counts for one billed API response. */
|
|
35
39
|
export interface TokenBundle {
|
|
36
40
|
inputTokens: number;
|
|
@@ -16,11 +16,20 @@
|
|
|
16
16
|
* Price families, matched by LONGEST normalized-id prefix so dated ids like
|
|
17
17
|
* `claude-sonnet-4-6-20260115` resolve without per-snapshot entries.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* Opus pricing split (#41): Opus 4.0/4.1 were $15/$75, but Opus 4.5 dropped
|
|
20
|
+
* the tier to $5/$25 and 4.6/4.7/4.8 kept it. The bare 'claude-opus-4' entry
|
|
21
|
+
* stays at legacy rates for 4.0/4.1; the longer per-version prefixes win for
|
|
22
|
+
* 4.5+ via longest-prefix matching.
|
|
21
23
|
*/
|
|
22
24
|
const PRICE_FAMILIES = {
|
|
25
|
+
'claude-fable-5': { in: 10, out: 50, cacheWrite: 12.5, cacheWrite1h: 20, cacheRead: 1 },
|
|
26
|
+
'claude-mythos-5': { in: 10, out: 50, cacheWrite: 12.5, cacheWrite1h: 20, cacheRead: 1 },
|
|
23
27
|
'claude-opus-4': { in: 15, out: 75, cacheWrite: 18.75, cacheWrite1h: 30, cacheRead: 1.5 },
|
|
28
|
+
'claude-opus-4-5': { in: 5, out: 25, cacheWrite: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
|
|
29
|
+
'claude-opus-4-6': { in: 5, out: 25, cacheWrite: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
|
|
30
|
+
'claude-opus-4-7': { in: 5, out: 25, cacheWrite: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
|
|
31
|
+
'claude-opus-4-8': { in: 5, out: 25, cacheWrite: 6.25, cacheWrite1h: 10, cacheRead: 0.5 },
|
|
32
|
+
'claude-sonnet-5': { in: 3, out: 15, cacheWrite: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
|
|
24
33
|
'claude-sonnet-4': { in: 3, out: 15, cacheWrite: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
|
|
25
34
|
'claude-haiku-4': { in: 1, out: 5, cacheWrite: 1.25, cacheWrite1h: 2, cacheRead: 0.1 },
|
|
26
35
|
'claude-3-7-sonnet': { in: 3, out: 15, cacheWrite: 3.75, cacheWrite1h: 6, cacheRead: 0.3 },
|
|
@@ -29,6 +38,15 @@ const PRICE_FAMILIES = {
|
|
|
29
38
|
'claude-3-opus': { in: 15, out: 75, cacheWrite: 18.75, cacheWrite1h: 30, cacheRead: 1.5 },
|
|
30
39
|
'claude-3-haiku': { in: 0.25, out: 1.25, cacheWrite: 0.3, cacheWrite1h: 0.5, cacheRead: 0.03 },
|
|
31
40
|
};
|
|
41
|
+
const PROMOS = [
|
|
42
|
+
{
|
|
43
|
+
// Sonnet 5 introductory pricing: $2/$10 per Mtok through 2026-08-31.
|
|
44
|
+
prefix: 'claude-sonnet-5',
|
|
45
|
+
fromMs: Date.UTC(2026, 5, 30), // launched 2026-06-30
|
|
46
|
+
untilMs: Date.UTC(2026, 7, 31, 23, 59, 59, 999),
|
|
47
|
+
price: { in: 2, out: 10, cacheWrite: 2.5, cacheWrite1h: 4, cacheRead: 0.2 },
|
|
48
|
+
},
|
|
49
|
+
];
|
|
32
50
|
/**
|
|
33
51
|
* Reduce a transcript/gateway model id to the bare Anthropic id:
|
|
34
52
|
* 'anthropic/claude-opus-4-8' → 'claude-opus-4-8'
|
|
@@ -47,9 +65,20 @@ export function normalizeTranscriptModelId(raw) {
|
|
|
47
65
|
id = id.replace(/-v\d+$/, ''); // Bedrock '-v2'
|
|
48
66
|
return id;
|
|
49
67
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Longest-prefix price lookup; undefined = unpriced (report it, don't guess).
|
|
70
|
+
* Pass the transcript entry's timestamp as `atMs` to get date-ranged promo
|
|
71
|
+
* rates (e.g. Sonnet 5 intro pricing); omitted → sticker price.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveTranscriptPrice(rawModelId, atMs) {
|
|
52
74
|
const id = normalizeTranscriptModelId(rawModelId);
|
|
75
|
+
if (atMs !== undefined) {
|
|
76
|
+
for (const promo of PROMOS) {
|
|
77
|
+
if (id.startsWith(promo.prefix) && atMs >= promo.fromMs && atMs <= promo.untilMs) {
|
|
78
|
+
return promo.price;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
53
82
|
let best;
|
|
54
83
|
let bestLen = 0;
|
|
55
84
|
for (const [prefix, price] of Object.entries(PRICE_FAMILIES)) {
|
|
@@ -182,7 +182,7 @@ function toUsageEvent(line, project, seen, unpriced) {
|
|
|
182
182
|
const cacheWrite1hTokens = usage.cache_creation?.ephemeral_1h_input_tokens ?? 0;
|
|
183
183
|
let costUsd;
|
|
184
184
|
let costSource;
|
|
185
|
-
const price = resolveTranscriptPrice(model);
|
|
185
|
+
const price = resolveTranscriptPrice(model, ts.getTime());
|
|
186
186
|
if (typeof line.costUSD === 'number') {
|
|
187
187
|
costUsd = line.costUSD;
|
|
188
188
|
costSource = 'transcript';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmdo/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
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",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"test:pattern-store": "npx tsx src/transfer/store/tests/standalone-test.ts",
|
|
84
84
|
"postinstall": "node ./scripts/postinstall.cjs",
|
|
85
85
|
"build:standalone": "node scripts/build-standalone.mjs",
|
|
86
|
-
"prepublishOnly": "node -e \"if (process.env.npm_command === 'publish') { console.error('\\n@swarmdo/cli must be published from the self-contained staging dir (file:../ siblings do not ship from here):\\n\\n npm run build && npm run build:standalone && npm publish dist-standalone/\\n'); process.exit(1); } // pnpm runs prepublishOnly when packing local directory deps during install
|
|
86
|
+
"prepublishOnly": "node -e \"if (process.env.npm_command === 'publish') { console.error('\\n@swarmdo/cli must be published from the self-contained staging dir (file:../ siblings do not ship from here):\\n\\n npm run build && npm run build:standalone && npm publish dist-standalone/\\n'); process.exit(1); } // pnpm runs prepublishOnly when packing local directory deps during install — that path must not fail\""
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
89
|
"@types/better-sqlite3": "^7.6.0",
|