theslopmachine 0.6.2 → 0.7.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/MANUAL.md +21 -6
- package/README.md +55 -7
- package/RELEASE.md +15 -0
- package/assets/agents/developer.md +41 -1
- package/assets/agents/slopmachine-claude.md +100 -60
- package/assets/agents/slopmachine.md +40 -17
- package/assets/claude/agents/developer.md +42 -5
- package/assets/skills/clarification-gate/SKILL.md +25 -5
- package/assets/skills/claude-worker-management/SKILL.md +280 -57
- package/assets/skills/developer-session-lifecycle/SKILL.md +81 -37
- package/assets/skills/development-guidance/SKILL.md +21 -1
- package/assets/skills/evaluation-triage/SKILL.md +32 -23
- package/assets/skills/final-evaluation-orchestration/SKILL.md +86 -50
- package/assets/skills/hardening-gate/SKILL.md +17 -3
- package/assets/skills/integrated-verification/SKILL.md +3 -3
- package/assets/skills/planning-gate/SKILL.md +32 -3
- package/assets/skills/planning-guidance/SKILL.md +72 -13
- package/assets/skills/retrospective-analysis/SKILL.md +2 -2
- package/assets/skills/scaffold-guidance/SKILL.md +129 -124
- package/assets/skills/submission-packaging/SKILL.md +33 -27
- package/assets/skills/verification-gates/SKILL.md +44 -14
- package/assets/slopmachine/backend-evaluation-prompt.md +1 -1
- package/assets/slopmachine/frontend-evaluation-prompt.md +5 -5
- package/assets/slopmachine/scaffold-playbooks/android-kotlin-compose.md +81 -0
- package/assets/slopmachine/scaffold-playbooks/android-kotlin-views.md +191 -0
- package/assets/slopmachine/scaffold-playbooks/android-native-java.md +203 -0
- package/assets/slopmachine/scaffold-playbooks/angular-default.md +181 -0
- package/assets/slopmachine/scaffold-playbooks/backend-baseline.md +142 -0
- package/assets/slopmachine/scaffold-playbooks/backend-family-matrix.md +80 -0
- package/assets/slopmachine/scaffold-playbooks/database-module-matrix.md +80 -0
- package/assets/slopmachine/scaffold-playbooks/django-default.md +166 -0
- package/assets/slopmachine/scaffold-playbooks/docker-baseline.md +189 -0
- package/assets/slopmachine/scaffold-playbooks/docker-shared-contract.md +334 -0
- package/assets/slopmachine/scaffold-playbooks/electron-vite-default.md +124 -0
- package/assets/slopmachine/scaffold-playbooks/expo-react-native-default.md +73 -0
- package/assets/slopmachine/scaffold-playbooks/fastapi-default.md +134 -0
- package/assets/slopmachine/scaffold-playbooks/frontend-baseline.md +160 -0
- package/assets/slopmachine/scaffold-playbooks/frontend-family-matrix.md +134 -0
- package/assets/slopmachine/scaffold-playbooks/generic-unknown-tech-guide.md +136 -0
- package/assets/slopmachine/scaffold-playbooks/go-chi-default.md +160 -0
- package/assets/slopmachine/scaffold-playbooks/ios-linux-portable.md +93 -0
- package/assets/slopmachine/scaffold-playbooks/ios-native-objective-c.md +151 -0
- package/assets/slopmachine/scaffold-playbooks/ios-native-swift.md +188 -0
- package/assets/slopmachine/scaffold-playbooks/laravel-default.md +216 -0
- package/assets/slopmachine/scaffold-playbooks/livewire-default.md +265 -0
- package/assets/slopmachine/scaffold-playbooks/overlay-module-matrix.md +130 -0
- package/assets/slopmachine/scaffold-playbooks/platform-family-matrix.md +79 -0
- package/assets/slopmachine/scaffold-playbooks/selection-matrix.md +72 -0
- package/assets/slopmachine/scaffold-playbooks/spring-boot-default.md +182 -0
- package/assets/slopmachine/scaffold-playbooks/tauri-default.md +80 -0
- package/assets/slopmachine/scaffold-playbooks/vue-vite-default.md +162 -0
- package/assets/slopmachine/scaffold-playbooks/web-default.md +96 -0
- package/assets/slopmachine/templates/AGENTS.md +41 -3
- package/assets/slopmachine/templates/CLAUDE.md +111 -0
- package/assets/slopmachine/utils/claude_create_session.mjs +1 -0
- package/assets/slopmachine/utils/claude_live_channel.mjs +188 -0
- package/assets/slopmachine/utils/claude_live_common.mjs +406 -0
- package/assets/slopmachine/utils/claude_live_hook.py +47 -0
- package/assets/slopmachine/utils/claude_live_launch.mjs +181 -0
- package/assets/slopmachine/utils/claude_live_status.mjs +25 -0
- package/assets/slopmachine/utils/claude_live_stop.mjs +45 -0
- package/assets/slopmachine/utils/claude_live_turn.mjs +250 -0
- package/assets/slopmachine/utils/claude_resume_session.mjs +1 -0
- package/assets/slopmachine/utils/claude_wait_for_rate_limit_reset.mjs +23 -0
- package/assets/slopmachine/utils/claude_wait_for_rate_limit_reset.sh +5 -0
- package/assets/slopmachine/utils/claude_worker_common.mjs +224 -4
- package/assets/slopmachine/utils/cleanup_delivery_artifacts.py +4 -0
- package/assets/slopmachine/utils/export_ai_session.mjs +1 -1
- package/assets/slopmachine/utils/normalize_claude_session.py +153 -0
- package/assets/slopmachine/utils/package_claude_session.mjs +96 -0
- package/assets/slopmachine/utils/prepare_strict_audit_workspace.mjs +65 -0
- package/package.json +1 -1
- package/src/constants.js +42 -3
- package/src/init.js +173 -28
- package/src/install.js +75 -0
- package/src/send-data.js +56 -57
package/src/install.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
OPCODE_VERSION,
|
|
12
12
|
PACKAGE_ROOT,
|
|
13
13
|
REQUIRED_SKILL_DIRS,
|
|
14
|
+
REQUIRED_SLOPMACHINE_ROOT_FILES,
|
|
14
15
|
REQUIRED_SLOPMACHINE_FILES,
|
|
15
16
|
} from './constants.js'
|
|
16
17
|
import {
|
|
@@ -376,6 +377,30 @@ async function tryInstallCoreDependency(name) {
|
|
|
376
377
|
winget: ['winget', ['install', '--id', 'Python.Python.3.11', '-e']],
|
|
377
378
|
choco: ['choco', ['install', 'python', '--version=3.11.7', '-y']],
|
|
378
379
|
},
|
|
380
|
+
bash: {
|
|
381
|
+
brew: ['brew', ['install', 'bash']],
|
|
382
|
+
apt: ['sudo', ['apt-get', 'install', '-y', 'bash']],
|
|
383
|
+
dnf: ['sudo', ['dnf', 'install', '-y', 'bash']],
|
|
384
|
+
},
|
|
385
|
+
curl: {
|
|
386
|
+
brew: ['brew', ['install', 'curl']],
|
|
387
|
+
apt: ['sudo', ['apt-get', 'install', '-y', 'curl']],
|
|
388
|
+
dnf: ['sudo', ['dnf', 'install', '-y', 'curl']],
|
|
389
|
+
},
|
|
390
|
+
tar: {
|
|
391
|
+
apt: ['sudo', ['apt-get', 'install', '-y', 'tar']],
|
|
392
|
+
dnf: ['sudo', ['dnf', 'install', '-y', 'tar']],
|
|
393
|
+
},
|
|
394
|
+
tmux: {
|
|
395
|
+
brew: ['brew', ['install', 'tmux']],
|
|
396
|
+
apt: ['sudo', ['apt-get', 'install', '-y', 'tmux']],
|
|
397
|
+
dnf: ['sudo', ['dnf', 'install', '-y', 'tmux']],
|
|
398
|
+
},
|
|
399
|
+
zip: {
|
|
400
|
+
brew: ['brew', ['install', 'zip']],
|
|
401
|
+
apt: ['sudo', ['apt-get', 'install', '-y', 'zip']],
|
|
402
|
+
dnf: ['sudo', ['dnf', 'install', '-y', 'zip']],
|
|
403
|
+
},
|
|
379
404
|
}
|
|
380
405
|
|
|
381
406
|
const platformKey = managers.brew
|
|
@@ -587,6 +612,31 @@ async function checkInitShellSupport() {
|
|
|
587
612
|
}
|
|
588
613
|
}
|
|
589
614
|
|
|
615
|
+
async function checkClaudeCli() {
|
|
616
|
+
const claudeVersion = await getCommandVersion('claude')
|
|
617
|
+
if (!claudeVersion) {
|
|
618
|
+
warn('Claude CLI is required for the `slopmachine-claude` backend and was not found in PATH. Install Claude Code before using the Claude-backed workflow.')
|
|
619
|
+
return
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
log(`claude detected: ${claudeVersion}`)
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
async function checkArchiveSupport() {
|
|
626
|
+
if (process.platform === 'win32') {
|
|
627
|
+
const shell = await resolveCommand('pwsh') || await resolveCommand('powershell')
|
|
628
|
+
if (!shell) {
|
|
629
|
+
warn('PowerShell is required on Windows for archive packaging paths such as send-data and Claude session packaging.')
|
|
630
|
+
return
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
log(`archive shell detected: ${shell}`)
|
|
634
|
+
return
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
await ensureDependency({ name: 'zip', checkCommand: 'zip', requiredVersion: null, installable: true })
|
|
638
|
+
}
|
|
639
|
+
|
|
590
640
|
async function findLegacyInstallItems(paths) {
|
|
591
641
|
const legacyItems = []
|
|
592
642
|
const scanTargets = [
|
|
@@ -744,6 +794,18 @@ async function installSlopmachineAssets(paths) {
|
|
|
744
794
|
}
|
|
745
795
|
}
|
|
746
796
|
|
|
797
|
+
for (const relativePath of REQUIRED_SLOPMACHINE_ROOT_FILES) {
|
|
798
|
+
const targetPath = path.join(paths.slopmachineDir, relativePath)
|
|
799
|
+
const result = await copyFileReplacing(path.join(PACKAGE_ROOT, relativePath), targetPath)
|
|
800
|
+
if (result.replaced) {
|
|
801
|
+
log(`Refreshed asset: ${relativePath}`)
|
|
802
|
+
summary.refreshed.push(relativePath)
|
|
803
|
+
} else {
|
|
804
|
+
log(`Installed asset: ${relativePath}`)
|
|
805
|
+
summary.installed.push(relativePath)
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
747
809
|
return summary
|
|
748
810
|
}
|
|
749
811
|
|
|
@@ -880,11 +942,24 @@ export async function runInstall() {
|
|
|
880
942
|
log(`Configuring theslopmachine in ${paths.home}`)
|
|
881
943
|
|
|
882
944
|
section('Dependencies')
|
|
945
|
+
await ensureDependency({ name: 'npm', checkCommand: 'npm', requiredVersion: null, installable: false })
|
|
883
946
|
await ensureDependency({ name: 'git', checkCommand: 'git', installable: true })
|
|
884
947
|
await ensureDependency({ name: 'python3', checkCommand: 'python3', installable: true })
|
|
948
|
+
if (process.platform !== 'win32') {
|
|
949
|
+
await ensureDependency({ name: 'bash', checkCommand: 'bash', installable: true })
|
|
950
|
+
}
|
|
951
|
+
if (process.platform !== 'win32') {
|
|
952
|
+
await ensureDependency({ name: 'curl', checkCommand: 'curl', installable: true })
|
|
953
|
+
}
|
|
954
|
+
if (process.platform === 'linux') {
|
|
955
|
+
await ensureDependency({ name: 'tar', checkCommand: 'tar', installable: true })
|
|
956
|
+
}
|
|
885
957
|
await ensureDependency({ name: 'opencode', checkCommand: 'opencode', requiredVersion: OPCODE_VERSION, installable: true })
|
|
886
958
|
await ensureDependency({ name: 'beads_rust (br)', checkCommand: 'br', requiredVersion: null, installable: true })
|
|
887
959
|
await checkDocker()
|
|
960
|
+
await ensureDependency({ name: 'tmux', checkCommand: 'tmux', requiredVersion: null, installable: process.platform !== 'win32' })
|
|
961
|
+
await checkClaudeCli()
|
|
962
|
+
await checkArchiveSupport()
|
|
888
963
|
await checkInitShellSupport()
|
|
889
964
|
|
|
890
965
|
section('Legacy Cleanup')
|
package/src/send-data.js
CHANGED
|
@@ -23,7 +23,7 @@ const RETROSPECTIVE_FILENAMES = (runId) => [
|
|
|
23
23
|
`improvement-actions-${runId}.md`,
|
|
24
24
|
]
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const EVALUATION_REPORTS_DIR = '.tmp'
|
|
27
27
|
|
|
28
28
|
function sha256Hex(buffer) {
|
|
29
29
|
return createHash('sha256').update(buffer).digest('hex')
|
|
@@ -368,7 +368,7 @@ async function buildManifest(stagingDir, projectId, runId, label, workspaceRoot)
|
|
|
368
368
|
project_id: projectId,
|
|
369
369
|
run_id: runId,
|
|
370
370
|
label,
|
|
371
|
-
bundle_categories: ['sessions', '
|
|
371
|
+
bundle_categories: ['sessions', 'evaluation', 'retrospective', 'beads', 'metadata'],
|
|
372
372
|
files,
|
|
373
373
|
file_count: files.length,
|
|
374
374
|
total_bytes: totalBytes,
|
|
@@ -386,67 +386,33 @@ async function buildManifest(stagingDir, projectId, runId, label, workspaceRoot)
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
async function exportDeveloperSessionArtifacts(session, workspaceRoot, stagingDir) {
|
|
389
|
+
if (session.backend === 'claude' || session.backend === 'claude-live') {
|
|
390
|
+
throw new Error(`Claude-backed sessions should be exported through the shared project archive, not per-session packaging (${session.label})`)
|
|
391
|
+
}
|
|
392
|
+
|
|
389
393
|
const utilsDir = path.join(buildPaths().slopmachineDir, 'utils')
|
|
390
|
-
const exportScript = path.join(utilsDir, 'export_ai_session.mjs')
|
|
391
394
|
const stripScript = path.join(utilsDir, 'strip_session_parent.py')
|
|
392
|
-
const convertScript = path.join(utilsDir, 'convert_exported_ai_session.mjs')
|
|
393
|
-
const converterPythonScript = path.join(utilsDir, 'convert_ai_session.py')
|
|
394
395
|
|
|
395
|
-
const
|
|
396
|
-
const rootSessionFile = path.join(stagingDir, `session-${exportNumber}.json`)
|
|
397
|
-
const convertedSessionFile = path.join(stagingDir, 'sessions', `${session.label}.json`)
|
|
396
|
+
const cleanedSessionFile = path.join(stagingDir, 'sessions', `${session.label}.json`)
|
|
398
397
|
const rawSessionFile = path.join(stagingDir, `.session-export-${session.label}.raw`)
|
|
399
398
|
|
|
400
|
-
await
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const exportResult = await runCommand(process.execPath, [
|
|
404
|
-
exportScript,
|
|
405
|
-
'--backend',
|
|
406
|
-
'claude',
|
|
407
|
-
'--cwd',
|
|
408
|
-
workspaceRoot,
|
|
409
|
-
'--session-id',
|
|
410
|
-
session.sessionId,
|
|
411
|
-
'--output',
|
|
412
|
-
rootSessionFile,
|
|
413
|
-
])
|
|
414
|
-
|
|
415
|
-
if (exportResult.code !== 0) {
|
|
416
|
-
throw new Error(`Failed to export session ${session.label}: ${(exportResult.stderr || exportResult.stdout).trim()}`)
|
|
417
|
-
}
|
|
418
|
-
} else {
|
|
419
|
-
const opencodeCommand = await resolveCommand('opencode')
|
|
420
|
-
if (!opencodeCommand) {
|
|
421
|
-
throw new Error('Unable to find `opencode` for developer session export')
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
await exportOpenCodeSession(opencodeCommand, session.sessionId, rawSessionFile, workspaceRoot)
|
|
425
|
-
|
|
426
|
-
const stripResult = await runCommand('python3', [
|
|
427
|
-
stripScript,
|
|
428
|
-
rawSessionFile,
|
|
429
|
-
'--output',
|
|
430
|
-
rootSessionFile,
|
|
431
|
-
])
|
|
432
|
-
|
|
433
|
-
if (stripResult.code !== 0) {
|
|
434
|
-
throw new Error(`Failed to clean exported session ${session.label}: ${(stripResult.stderr || stripResult.stdout).trim()}`)
|
|
435
|
-
}
|
|
399
|
+
const opencodeCommand = await resolveCommand('opencode')
|
|
400
|
+
if (!opencodeCommand) {
|
|
401
|
+
throw new Error('Unable to find `opencode` for developer session export')
|
|
436
402
|
}
|
|
437
403
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
404
|
+
await ensureDir(path.dirname(cleanedSessionFile))
|
|
405
|
+
await exportOpenCodeSession(opencodeCommand, session.sessionId, rawSessionFile, workspaceRoot)
|
|
406
|
+
|
|
407
|
+
const stripResult = await runCommand('python3', [
|
|
408
|
+
stripScript,
|
|
409
|
+
rawSessionFile,
|
|
444
410
|
'--output',
|
|
445
|
-
|
|
411
|
+
cleanedSessionFile,
|
|
446
412
|
])
|
|
447
413
|
|
|
448
|
-
if (
|
|
449
|
-
throw new Error(`Failed to
|
|
414
|
+
if (stripResult.code !== 0) {
|
|
415
|
+
throw new Error(`Failed to clean exported session ${session.label}: ${(stripResult.stderr || stripResult.stdout).trim()}`)
|
|
450
416
|
}
|
|
451
417
|
|
|
452
418
|
if (await pathExists(rawSessionFile)) {
|
|
@@ -454,6 +420,33 @@ async function exportDeveloperSessionArtifacts(session, workspaceRoot, stagingDi
|
|
|
454
420
|
}
|
|
455
421
|
}
|
|
456
422
|
|
|
423
|
+
async function exportClaudeProjectArtifacts(claudeSessions, workspaceRoot, stagingDir) {
|
|
424
|
+
if (claudeSessions.length === 0) {
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const utilsDir = path.join(buildPaths().slopmachineDir, 'utils')
|
|
429
|
+
const packageClaudeSessionScript = path.join(utilsDir, 'package_claude_session.mjs')
|
|
430
|
+
const outputPath = path.join(stagingDir, 'claude-sessions.zip')
|
|
431
|
+
const anchorSession = claudeSessions[0]
|
|
432
|
+
|
|
433
|
+
const packageResult = await runCommand(process.execPath, [
|
|
434
|
+
packageClaudeSessionScript,
|
|
435
|
+
'--cwd',
|
|
436
|
+
workspaceRoot,
|
|
437
|
+
'--session-id',
|
|
438
|
+
anchorSession.sessionId,
|
|
439
|
+
'--label',
|
|
440
|
+
'claude-sessions',
|
|
441
|
+
'--output',
|
|
442
|
+
outputPath,
|
|
443
|
+
])
|
|
444
|
+
|
|
445
|
+
if (packageResult.code !== 0) {
|
|
446
|
+
throw new Error(`Failed to package Claude project sessions: ${(packageResult.stderr || packageResult.stdout).trim()}`)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
457
450
|
async function createZipArchive(stagingDir, outputPath) {
|
|
458
451
|
await ensureDir(path.dirname(outputPath))
|
|
459
452
|
|
|
@@ -550,15 +543,21 @@ async function stageSendDataBundle({ workspaceRoot, repoPath, ownerSessionId, de
|
|
|
550
543
|
|
|
551
544
|
await exportOpenCodeSession(opencodeCommand, ownerSessionId, path.join(stagingDir, 'owner-session.json'), workspaceRoot)
|
|
552
545
|
|
|
553
|
-
|
|
546
|
+
const sortedSessions = developerSessions.sort((left, right) => left.order - right.order)
|
|
547
|
+
const claudeSessions = sortedSessions.filter((session) => session.backend === 'claude' || session.backend === 'claude-live')
|
|
548
|
+
const nonClaudeSessions = sortedSessions.filter((session) => session.backend !== 'claude' && session.backend !== 'claude-live')
|
|
549
|
+
|
|
550
|
+
for (const session of nonClaudeSessions) {
|
|
554
551
|
await exportDeveloperSessionArtifacts(session, workspaceRoot, stagingDir)
|
|
555
552
|
}
|
|
556
553
|
|
|
554
|
+
await exportClaudeProjectArtifacts(claudeSessions, workspaceRoot, stagingDir)
|
|
555
|
+
|
|
557
556
|
await copyOptionalPath(
|
|
558
|
-
path.join(workspaceRoot,
|
|
559
|
-
path.join(stagingDir,
|
|
557
|
+
path.join(workspaceRoot, EVALUATION_REPORTS_DIR),
|
|
558
|
+
path.join(stagingDir, EVALUATION_REPORTS_DIR),
|
|
560
559
|
warnings,
|
|
561
|
-
|
|
560
|
+
EVALUATION_REPORTS_DIR,
|
|
562
561
|
)
|
|
563
562
|
|
|
564
563
|
const retrospectiveDir = path.join(buildPaths().slopmachineDir, 'retrospectives')
|