loadout-ai 0.7.0 → 0.9.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/CHANGELOG.md +148 -1
- package/README.md +160 -315
- package/SECURITY.md +21 -1
- package/catalog/discovered.json +31269 -26003
- package/catalog/packages.json +4 -4
- package/dist/src/cli.js +13 -0
- package/dist/src/commands/agents.js +3 -1
- package/dist/src/commands/catalog-candidate.js +150 -0
- package/dist/src/commands/catalog-workflows.js +147 -0
- package/dist/src/commands/catalog.js +9 -367
- package/dist/src/commands/coordinate.js +586 -0
- package/dist/src/commands/coordination-discussions.js +194 -0
- package/dist/src/commands/coordination-sessions.js +197 -0
- package/dist/src/commands/inventory.js +4 -2
- package/dist/src/core/agents/agent-inspection.js +26 -4
- package/dist/src/core/{routing → agents}/model-config.js +7 -2
- package/dist/src/core/catalog/catalog.js +1 -0
- package/dist/src/core/catalog/registry.js +44 -10
- package/dist/src/core/catalog/safety.js +36 -7
- package/dist/src/core/coordination/adapters/claude-code.js +154 -0
- package/dist/src/core/coordination/adapters/codex.js +137 -0
- package/dist/src/core/coordination/adapters/types.js +64 -0
- package/dist/src/core/coordination/auth.js +59 -0
- package/dist/src/core/coordination/bridge-lease.js +79 -0
- package/dist/src/core/coordination/conflict-preview.js +167 -0
- package/dist/src/core/coordination/contract-diff.js +106 -0
- package/dist/src/core/coordination/coordinator.js +552 -0
- package/dist/src/core/coordination/crash-recovery.js +169 -0
- package/dist/src/core/coordination/daemon.js +667 -0
- package/dist/src/core/coordination/discussion.js +340 -0
- package/dist/src/core/coordination/events.js +161 -0
- package/dist/src/core/coordination/http-api.js +118 -0
- package/dist/src/core/coordination/interrupt-policy.js +89 -0
- package/dist/src/core/coordination/lock.js +110 -0
- package/dist/src/core/coordination/mcp-server.js +424 -0
- package/dist/src/core/coordination/redaction.js +85 -0
- package/dist/src/core/coordination/replay.js +188 -0
- package/dist/src/core/coordination/retention.js +128 -0
- package/dist/src/core/coordination/runtime.js +21 -0
- package/dist/src/core/coordination/session-manager.js +366 -0
- package/dist/src/core/coordination/watcher.js +128 -0
- package/dist/src/core/{routing → delegation}/first-party-skills.js +25 -13
- package/dist/src/core/{routing → delegation}/handoff.js +130 -63
- package/dist/src/core/discovery/candidate-intelligence-evidence.js +108 -0
- package/dist/src/core/discovery/candidate-intelligence-types.js +1 -0
- package/dist/src/core/discovery/candidate-intelligence-validation.js +108 -0
- package/dist/src/core/discovery/candidate-intelligence.js +3 -214
- package/dist/src/core/discovery/community.js +12 -4
- package/dist/src/core/discovery/github-discovery.js +6 -2
- package/dist/src/core/discovery/private-discovery.js +6 -2
- package/dist/src/core/install/reconcile.js +1 -1
- package/dist/src/core/install/source.js +21 -7
- package/dist/src/core/install/uninstall.js +39 -3
- package/dist/src/core/reporting/cli-guide.js +10 -6
- package/dist/src/core/reporting/completion.js +61 -109
- package/dist/src/core/reporting/doctor.js +4 -6
- package/dist/src/core/runtime/bounded-json.js +65 -0
- package/dist/src/core/runtime/github.js +30 -16
- package/dist/src/core/runtime/mcp-recipes.js +1 -1
- package/dist/src/core/workspace/active-policy.js +1 -1
- package/docs/CANDIDATE_INTELLIGENCE.md +9 -2
- package/docs/CATALOG.md +1 -1
- package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +1 -1
- package/docs/DEMO_SCRIPT.md +19 -23
- package/docs/DISCOVERED.md +251 -250
- package/docs/FEATURE_TEST_MATRIX.md +10 -263
- package/docs/GITHUB_AUTHORIZATION.md +5 -0
- package/docs/LIVE_COLLABORATION.md +234 -0
- package/docs/PROVENANCE_AND_COMPARISON.md +1 -1
- package/docs/REFERENCE.md +163 -0
- package/docs/RELEASE_REVIEW.md +1 -2
- package/docs/TESTING.md +17 -1
- package/docs/USER_TEST_GUIDE.md +138 -3
- package/docs/assets/loadout-discover-activate.webp +0 -0
- package/docs/assets/loadout-handoff-coordinate.webp +0 -0
- package/docs/assets/loadout-social-preview.png +0 -0
- package/docs/decisions/001-coordination-jsonl-locking.md +35 -0
- package/docs/decisions/002-local-daemon-authentication.md +32 -0
- package/docs/decisions/003-bounded-agent-discussions.md +91 -0
- package/docs/specs/BOUNDED_AGENT_DISCUSSIONS.md +169 -0
- package/docs/superpowers/plans/2026-09-03-coordination-hardening.md +231 -0
- package/docs/superpowers/plans/2026-09-03-release-readiness.md +232 -0
- package/docs/superpowers/plans/2026-09-04-bounded-agent-discussions.md +121 -0
- package/package.json +18 -7
- package/skills/loadout-handoff/SKILL.md +238 -0
- package/MASTER_PLAN.md +0 -2207
- package/dist/src/core/routing/route.js +0 -539
- package/docs/ACTIVE_SET.md +0 -53
- package/docs/COMPATIBILITY_POLICY.md +0 -22
- package/docs/CONVERSION_AND_SANDBOX.md +0 -27
- package/docs/EVALUATION_PROTOCOL_V1.md +0 -300
- package/docs/HEAD_TO_HEAD_EVALUATION.md +0 -79
- package/docs/PROVIDER_CONFIGURATION.md +0 -45
- package/docs/README_RESEARCH.md +0 -36
- package/docs/REPOSITORY_STABILIZATION.md +0 -190
- package/docs/SAFE_UPDATE_DEMO.md +0 -25
- package/docs/SCHEMA_DECISIONS.md +0 -25
- package/docs/SUBMISSION_COPY.md +0 -90
- package/docs/TEAM_POLICY.md +0 -18
- package/docs/assets/loadout-workflow.png +0 -0
- package/docs/superpowers/plans/2026-07-19-relatable-readme-hero.md +0 -283
- package/docs/superpowers/plans/2026-07-20-loadout-readme-explainer.md +0 -116
- package/docs/superpowers/plans/2026-07-20-project-activation-safety.md +0 -469
- package/docs/superpowers/specs/2026-07-19-relatable-readme-hero-design.md +0 -80
- package/docs/superpowers/specs/2026-07-20-loadout-readme-explainer-design.md +0 -55
- package/docs/superpowers/specs/2026-07-20-project-activation-safety-design.md +0 -228
- package/skills/loadout-router/SKILL.md +0 -120
- /package/dist/src/core/{routing → agents}/credentials.js +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crash recovery for the coordination daemon.
|
|
3
|
+
*
|
|
4
|
+
* - PID file management for singleton daemon
|
|
5
|
+
* - Stale PID detection and cleanup
|
|
6
|
+
* - State persistence and recovery
|
|
7
|
+
* - Kill switch: immediately halt all coordination
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, writeFile, unlink, mkdir } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
const COORD_DIR = ".handoff";
|
|
12
|
+
const PID_FILE = "daemon.pid";
|
|
13
|
+
const KILL_SWITCH_FILE = "KILL_SWITCH";
|
|
14
|
+
/**
|
|
15
|
+
* Write the daemon PID file.
|
|
16
|
+
*/
|
|
17
|
+
export async function writePidFile(projectRoot, port) {
|
|
18
|
+
const dir = join(projectRoot, COORD_DIR);
|
|
19
|
+
await mkdir(dir, { recursive: true });
|
|
20
|
+
const info = {
|
|
21
|
+
pid: process.pid,
|
|
22
|
+
port,
|
|
23
|
+
startedAt: new Date().toISOString(),
|
|
24
|
+
projectRoot,
|
|
25
|
+
};
|
|
26
|
+
await writeFile(join(dir, PID_FILE), JSON.stringify(info, null, 2) + "\n", {
|
|
27
|
+
encoding: "utf-8",
|
|
28
|
+
mode: 0o600,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read the daemon PID file.
|
|
33
|
+
*/
|
|
34
|
+
export async function readPidFile(projectRoot) {
|
|
35
|
+
try {
|
|
36
|
+
const raw = await readFile(join(projectRoot, COORD_DIR, PID_FILE), "utf-8");
|
|
37
|
+
return JSON.parse(raw);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Remove the daemon PID file.
|
|
45
|
+
*/
|
|
46
|
+
export async function removePidFile(projectRoot) {
|
|
47
|
+
try {
|
|
48
|
+
await unlink(join(projectRoot, COORD_DIR, PID_FILE));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Already removed
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if a daemon process is still running.
|
|
56
|
+
*/
|
|
57
|
+
export function isProcessRunning(pid) {
|
|
58
|
+
try {
|
|
59
|
+
process.kill(pid, 0);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a daemon is running for this project.
|
|
68
|
+
* If the PID file exists but the process is dead, clean up.
|
|
69
|
+
*/
|
|
70
|
+
export async function getDaemonStatus(projectRoot) {
|
|
71
|
+
const info = await readPidFile(projectRoot);
|
|
72
|
+
if (!info) {
|
|
73
|
+
return { running: false, info: null, stale: false };
|
|
74
|
+
}
|
|
75
|
+
if (isProcessRunning(info.pid)) {
|
|
76
|
+
return { running: true, info, stale: false };
|
|
77
|
+
}
|
|
78
|
+
// Stale PID file — process died without cleanup
|
|
79
|
+
await removePidFile(projectRoot);
|
|
80
|
+
return { running: false, info, stale: true };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Stop a running daemon by sending SIGTERM.
|
|
84
|
+
*/
|
|
85
|
+
export async function stopDaemon(projectRoot) {
|
|
86
|
+
const status = await getDaemonStatus(projectRoot);
|
|
87
|
+
if (!status.running) {
|
|
88
|
+
if (status.stale) {
|
|
89
|
+
return { stopped: false, pid: status.info.pid, stale: true };
|
|
90
|
+
}
|
|
91
|
+
return { stopped: false };
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
process.kill(status.info.pid, "SIGTERM");
|
|
95
|
+
await removePidFile(projectRoot);
|
|
96
|
+
return { stopped: true, pid: status.info.pid };
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return { stopped: false, pid: status.info.pid };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Kill switch
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* Activate the kill switch — immediately halts all coordination.
|
|
107
|
+
*
|
|
108
|
+
* Creates a KILL_SWITCH file that the daemon, watcher, and adapters
|
|
109
|
+
* check before any operation. While active:
|
|
110
|
+
* - Daemon refuses new events
|
|
111
|
+
* - Watcher stops broadcasting
|
|
112
|
+
* - Adapters refuse to inject
|
|
113
|
+
* - CLI commands print a warning
|
|
114
|
+
*/
|
|
115
|
+
export async function activateKillSwitch(projectRoot, reason) {
|
|
116
|
+
const dir = join(projectRoot, COORD_DIR);
|
|
117
|
+
await mkdir(dir, { recursive: true });
|
|
118
|
+
const data = {
|
|
119
|
+
activatedAt: new Date().toISOString(),
|
|
120
|
+
activatedBy: "user",
|
|
121
|
+
reason,
|
|
122
|
+
};
|
|
123
|
+
await writeFile(join(dir, KILL_SWITCH_FILE), JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
124
|
+
// Also stop the daemon if running
|
|
125
|
+
await stopDaemon(projectRoot);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Deactivate the kill switch — resume coordination.
|
|
129
|
+
*/
|
|
130
|
+
export async function deactivateKillSwitch(projectRoot) {
|
|
131
|
+
try {
|
|
132
|
+
await unlink(join(projectRoot, COORD_DIR, KILL_SWITCH_FILE));
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if the kill switch is active.
|
|
141
|
+
*/
|
|
142
|
+
export async function isKillSwitchActive(projectRoot) {
|
|
143
|
+
let raw;
|
|
144
|
+
try {
|
|
145
|
+
raw = await readFile(join(projectRoot, COORD_DIR, KILL_SWITCH_FILE), "utf-8");
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (typeof error === "object" &&
|
|
149
|
+
error !== null &&
|
|
150
|
+
"code" in error &&
|
|
151
|
+
error.code === "ENOENT") {
|
|
152
|
+
return { active: false };
|
|
153
|
+
}
|
|
154
|
+
return { active: true, reason: "Kill-switch file is unreadable" };
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const data = JSON.parse(raw);
|
|
158
|
+
return {
|
|
159
|
+
active: true,
|
|
160
|
+
...(typeof data.reason === "string" ? { reason: data.reason } : {}),
|
|
161
|
+
...(typeof data.activatedAt === "string"
|
|
162
|
+
? { activatedAt: data.activatedAt }
|
|
163
|
+
: {}),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return { active: true, reason: "Kill-switch file is unreadable" };
|
|
168
|
+
}
|
|
169
|
+
}
|