claude-multi-session 2.3.1 → 2.3.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/package.json +1 -1
- package/src/artifact-store.js +50 -0
- package/src/mcp-server.js +44 -0
- package/src/prompts.js +52 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-multi-session",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "Multi-session orchestrator for Claude Code CLI — spawn, control, pause, resume, and send multiple inputs to Claude Code sessions programmatically",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/artifact-store.js
CHANGED
|
@@ -469,6 +469,45 @@ class ArtifactStore {
|
|
|
469
469
|
}
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
+
/**
|
|
473
|
+
* Track that a session read an artifact
|
|
474
|
+
* @param {string} artifactId - The artifact that was read
|
|
475
|
+
* @param {string} reader - The session name that read it
|
|
476
|
+
* @param {number} version - The version that was read
|
|
477
|
+
*/
|
|
478
|
+
trackRead(artifactId, reader, version) {
|
|
479
|
+
if (!reader) return; // Skip if no reader identified
|
|
480
|
+
|
|
481
|
+
const readsPath = path.join(this.dataDir, artifactId, 'reads.json');
|
|
482
|
+
|
|
483
|
+
// Read existing reads log
|
|
484
|
+
let reads = readJsonSafe(readsPath, []);
|
|
485
|
+
|
|
486
|
+
// Add this read event
|
|
487
|
+
reads.push({
|
|
488
|
+
reader,
|
|
489
|
+
version,
|
|
490
|
+
readAt: new Date().toISOString(),
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// Write back (not immutable — reads are append-only log)
|
|
494
|
+
const dir = path.join(this.dataDir, artifactId);
|
|
495
|
+
if (!fs.existsSync(dir)) {
|
|
496
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
497
|
+
}
|
|
498
|
+
fs.writeFileSync(readsPath, JSON.stringify(reads, null, 2));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get the read log for an artifact
|
|
503
|
+
* @param {string} artifactId - The artifact to check
|
|
504
|
+
* @returns {Array} Array of read events: [{ reader, version, readAt }]
|
|
505
|
+
*/
|
|
506
|
+
getReads(artifactId) {
|
|
507
|
+
const readsPath = path.join(this.dataDir, artifactId, 'reads.json');
|
|
508
|
+
return readJsonSafe(readsPath, []);
|
|
509
|
+
}
|
|
510
|
+
|
|
472
511
|
/**
|
|
473
512
|
* List artifacts with optional filtering
|
|
474
513
|
* @param {Object} [filters={}] - Filter criteria
|
|
@@ -497,6 +536,17 @@ class ArtifactStore {
|
|
|
497
536
|
results = results.filter(item => item.tags && item.tags.includes(tag));
|
|
498
537
|
}
|
|
499
538
|
|
|
539
|
+
// Enrich with read counts
|
|
540
|
+
results = results.map(item => {
|
|
541
|
+
const reads = this.getReads(item.artifactId);
|
|
542
|
+
const uniqueReaders = [...new Set(reads.map(r => r.reader))];
|
|
543
|
+
return {
|
|
544
|
+
...item,
|
|
545
|
+
readCount: reads.length,
|
|
546
|
+
uniqueReaders,
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
|
|
500
550
|
return results;
|
|
501
551
|
}
|
|
502
552
|
|
package/src/mcp-server.js
CHANGED
|
@@ -561,6 +561,7 @@ const TOOLS = [
|
|
|
561
561
|
properties: {
|
|
562
562
|
artifactId: { type: 'string', description: 'Artifact ID to retrieve' },
|
|
563
563
|
version: { type: 'number', description: 'Specific version number (omit for latest)' },
|
|
564
|
+
reader: { type: 'string', description: 'Session name reading this artifact (for tracking who consumed it)' },
|
|
564
565
|
team: { type: 'string', description: 'Team name (default: "default")' },
|
|
565
566
|
},
|
|
566
567
|
required: ['artifactId'],
|
|
@@ -582,6 +583,20 @@ const TOOLS = [
|
|
|
582
583
|
},
|
|
583
584
|
},
|
|
584
585
|
|
|
586
|
+
{
|
|
587
|
+
name: 'artifact_readers',
|
|
588
|
+
description:
|
|
589
|
+
'Check who has read a specific artifact. Use this to verify that workers actually consumed shared artifacts like conventions or schemas.',
|
|
590
|
+
inputSchema: {
|
|
591
|
+
type: 'object',
|
|
592
|
+
properties: {
|
|
593
|
+
artifactId: { type: 'string', description: 'Artifact ID to check readers for' },
|
|
594
|
+
team: { type: 'string', description: 'Team name (default: "default")' },
|
|
595
|
+
},
|
|
596
|
+
required: ['artifactId'],
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
|
|
585
600
|
{
|
|
586
601
|
name: 'artifact_history',
|
|
587
602
|
description:
|
|
@@ -1161,6 +1176,8 @@ async function executeTool(toolName, args) {
|
|
|
1161
1176
|
return handleArtifactGet(args);
|
|
1162
1177
|
case 'artifact_list':
|
|
1163
1178
|
return handleArtifactList(args);
|
|
1179
|
+
case 'artifact_readers':
|
|
1180
|
+
return handleArtifactReaders(args);
|
|
1164
1181
|
case 'artifact_history':
|
|
1165
1182
|
return handleArtifactHistory(args);
|
|
1166
1183
|
|
|
@@ -1867,6 +1884,11 @@ function handleArtifactGet(args) {
|
|
|
1867
1884
|
return errorResult(`Artifact ${args.artifactId} not found`);
|
|
1868
1885
|
}
|
|
1869
1886
|
|
|
1887
|
+
// Track this read if a reader was specified
|
|
1888
|
+
if (args.reader) {
|
|
1889
|
+
artifactStore.trackRead(args.artifactId, args.reader, artifact.version);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1870
1892
|
return textResult(JSON.stringify({
|
|
1871
1893
|
artifactId: artifact.artifactId,
|
|
1872
1894
|
version: artifact.version,
|
|
@@ -1878,6 +1900,7 @@ function handleArtifactGet(args) {
|
|
|
1878
1900
|
summary: artifact.summary,
|
|
1879
1901
|
lineage: artifact.lineage,
|
|
1880
1902
|
team: teamName,
|
|
1903
|
+
readBy: artifactStore.getReads(args.artifactId),
|
|
1881
1904
|
}, null, 2));
|
|
1882
1905
|
} catch (err) {
|
|
1883
1906
|
return errorResult(err.message);
|
|
@@ -1908,6 +1931,8 @@ function handleArtifactList(args) {
|
|
|
1908
1931
|
createdAt: a.createdAt,
|
|
1909
1932
|
updatedAt: a.updatedAt,
|
|
1910
1933
|
tags: a.tags,
|
|
1934
|
+
readCount: a.readCount,
|
|
1935
|
+
uniqueReaders: a.uniqueReaders,
|
|
1911
1936
|
})),
|
|
1912
1937
|
}, null, 2));
|
|
1913
1938
|
} catch (err) {
|
|
@@ -1915,6 +1940,25 @@ function handleArtifactList(args) {
|
|
|
1915
1940
|
}
|
|
1916
1941
|
}
|
|
1917
1942
|
|
|
1943
|
+
function handleArtifactReaders(args) {
|
|
1944
|
+
try {
|
|
1945
|
+
const teamName = args.team || 'default';
|
|
1946
|
+
const { artifactStore } = getTeamInstances(teamName);
|
|
1947
|
+
|
|
1948
|
+
const reads = artifactStore.getReads(args.artifactId);
|
|
1949
|
+
const uniqueReaders = [...new Set(reads.map(r => r.reader))];
|
|
1950
|
+
|
|
1951
|
+
return textResult(JSON.stringify({
|
|
1952
|
+
artifactId: args.artifactId,
|
|
1953
|
+
totalReads: reads.length,
|
|
1954
|
+
uniqueReaders,
|
|
1955
|
+
reads,
|
|
1956
|
+
}, null, 2));
|
|
1957
|
+
} catch (err) {
|
|
1958
|
+
return errorResult(err.message);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1918
1962
|
function handleArtifactHistory(args) {
|
|
1919
1963
|
try {
|
|
1920
1964
|
const teamName = args.team || 'default';
|
package/src/prompts.js
CHANGED
|
@@ -66,12 +66,20 @@ Your inbox may contain:
|
|
|
66
66
|
- Dependency artifacts you need before starting
|
|
67
67
|
- Updated instructions from the orchestrator
|
|
68
68
|
|
|
69
|
-
### Step 1.5: CHECK FOR SHARED CONVENTIONS
|
|
70
|
-
Call \`mcp__multi-session__artifact_list\` and look for
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
### Step 1.5: CHECK FOR SHARED CONVENTIONS AND DEPENDENCY ARTIFACTS
|
|
70
|
+
Call \`mcp__multi-session__artifact_list\` and look for:
|
|
71
|
+
- A conventions or API contract artifact (e.g., "shared-conventions")
|
|
72
|
+
- Any dependency artifacts your task requires (e.g., "db-schema" if you're building routes)
|
|
73
73
|
|
|
74
|
-
If
|
|
74
|
+
If found, call \`mcp__multi-session__artifact_get\` with your session name as the \`reader\` parameter:
|
|
75
|
+
\`\`\`
|
|
76
|
+
mcp__multi-session__artifact_get({ artifactId: "shared-conventions", reader: "${name}" })
|
|
77
|
+
mcp__multi-session__artifact_get({ artifactId: "db-schema", reader: "${name}" })
|
|
78
|
+
\`\`\`
|
|
79
|
+
|
|
80
|
+
IMPORTANT: The \`reader\` parameter tracks that you consumed the artifact. This is how the orchestrator verifies workers actually read shared data. ALWAYS include your session name as \`reader\`.
|
|
81
|
+
|
|
82
|
+
Follow the conventions STRICTLY. If NO convention artifact exists AND your work must match other workers' output:
|
|
75
83
|
- Use \`team_ask\` to ask the relevant teammate about their format BEFORE writing code
|
|
76
84
|
- NEVER guess or assume format — mismatches cause test failures
|
|
77
85
|
|
|
@@ -517,6 +525,29 @@ mcp__multi-session__artifact_publish({
|
|
|
517
525
|
|
|
518
526
|
NEVER assume workers will independently agree on conventions. Define them explicitly.
|
|
519
527
|
|
|
528
|
+
### Phase Gate: VERIFY Before Spawning
|
|
529
|
+
=== CRITICAL: MANDATORY VERIFICATION STEP ===
|
|
530
|
+
Before spawning ANY worker that depends on a previous phase's output, you MUST:
|
|
531
|
+
1. Call \`artifact_list()\` to confirm the dependency artifact was published
|
|
532
|
+
2. Call \`artifact_get(artifactId)\` to confirm the artifact contains valid data
|
|
533
|
+
3. ONLY THEN spawn the dependent workers
|
|
534
|
+
|
|
535
|
+
Example phased workflow:
|
|
536
|
+
\`\`\`
|
|
537
|
+
// Phase 1: Spawn the database worker
|
|
538
|
+
team_spawn({ name: "db-worker", ... })
|
|
539
|
+
|
|
540
|
+
// PHASE GATE: Verify before Phase 2
|
|
541
|
+
artifact_list() // Confirm "db-schema" appears
|
|
542
|
+
artifact_get({ artifactId: "db-schema" }) // Confirm it has valid table definitions
|
|
543
|
+
|
|
544
|
+
// Phase 2: NOW spawn route workers (they depend on the schema)
|
|
545
|
+
team_spawn({ name: "api-worker", ... })
|
|
546
|
+
team_spawn({ name: "test-worker", ... })
|
|
547
|
+
\`\`\`
|
|
548
|
+
|
|
549
|
+
NEVER skip verification. NEVER rely on a worker's self-reported completion — verify the artifact exists yourself.
|
|
550
|
+
|
|
520
551
|
### Phase 2: Spawn Workers (use team_spawn, NOT delegate_task)
|
|
521
552
|
Spawn all independent workers at once. Example:
|
|
522
553
|
|
|
@@ -726,6 +757,7 @@ const ROLE_PROMPTS = {
|
|
|
726
757
|
- Publish test results as artifacts with type "test-results" including: passed, failed, skipped counts and failure details
|
|
727
758
|
- If tests fail due to bugs in another session's code, use \`team_send_message\` to notify them with the exact error and file path
|
|
728
759
|
- Use the correct status values as defined in the database schema (e.g., "in_progress" not "in-progress")
|
|
760
|
+
- IMPORTANT: When calling artifact_get, ALWAYS include reader: "<your-session-name>" so the orchestrator can verify you read the artifacts
|
|
729
761
|
`,
|
|
730
762
|
|
|
731
763
|
'database': `
|
|
@@ -822,6 +854,8 @@ IMPORTANT: You are the ORCHESTRATOR. Your job is to PLAN, SPAWN, and MONITOR —
|
|
|
822
854
|
|
|
823
855
|
4. **Set up dependencies** — Use \`contract_create\` if Task B needs output from Task A.
|
|
824
856
|
|
|
857
|
+
4.5. **Phase Gate** — Before spawning workers that depend on previous workers' output, VERIFY the dependency artifact exists by calling \`artifact_list()\` and \`artifact_get()\`. Never trust self-reported completion — verify the artifact.
|
|
858
|
+
|
|
825
859
|
5. **Monitor** — Check progress with \`team_roster()\`, \`contract_list()\`, \`artifact_list()\`. Only intervene when a worker is BLOCKED or FAILED.
|
|
826
860
|
|
|
827
861
|
6. **Collect** — When all workers are idle, check \`artifact_list\` for published outputs and summarize results for the user.
|
|
@@ -917,6 +951,19 @@ mcp__multi-session__contract_list() — See contract statuses
|
|
|
917
951
|
mcp__multi-session__artifact_list() — See published outputs
|
|
918
952
|
\`\`\`
|
|
919
953
|
|
|
954
|
+
### Phase Gate Verification
|
|
955
|
+
Between spawn phases, use these to verify dependencies:
|
|
956
|
+
\`\`\`
|
|
957
|
+
mcp__multi-session__artifact_get({ artifactId: "db-schema" }) — Verify artifact content
|
|
958
|
+
mcp__multi-session__artifact_readers({ artifactId: "db-schema" }) — Check who read it
|
|
959
|
+
\`\`\`
|
|
960
|
+
|
|
961
|
+
After all workers complete, verify every worker consumed the artifacts they needed:
|
|
962
|
+
\`\`\`
|
|
963
|
+
mcp__multi-session__artifact_readers({ artifactId: "shared-conventions" })
|
|
964
|
+
// Should list ALL route workers as readers
|
|
965
|
+
\`\`\`
|
|
966
|
+
|
|
920
967
|
### When to Intervene
|
|
921
968
|
|
|
922
969
|
| Worker Status | What to Do |
|