brainclaw 1.23.0 → 1.24.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/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli/register-cloud.js +121 -13
- package/dist/commands/cloud.js +534 -39
- package/dist/core/federation-emit.js +283 -0
- package/dist/core/federation-grant-transport.js +196 -0
- package/dist/core/federation-grant.js +223 -0
- package/dist/core/federation-keyring.js +39 -0
- package/dist/core/federation-opaque-ids.js +111 -0
- package/dist/core/federation-outbox-v2.js +36 -2
- package/dist/core/federation-pairing.js +87 -12
- package/dist/core/federation-pull.js +375 -0
- package/dist/core/federation-push.js +274 -0
- package/dist/core/federation-rotation.js +124 -0
- package/dist/core/federation-state.js +81 -6
- package/dist/facts.js +7 -7
- package/dist/facts.json +6 -6
- package/docs/design/federation-onboarding-usecases.md +254 -0
- package/docs/design/pairing-v3-brief.md +80 -0
- package/package.json +1 -1
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runCloudStatus, runCloudConnect, runCloudAwait, runCloudDisconnect, } from '../commands/cloud.js';
|
|
1
|
+
import { runCloudStatus, runCloudConnect, runCloudAwait, runCloudDisconnect, runCloudPull, runCloudPush, runCloudGrant, runCloudGrantWeb, runCloudRotate, runCloudAcceptSoloRisk, } from '../commands/cloud.js';
|
|
2
2
|
/** Adresse du cloud. Fournie par `--url`, sans quoi la commande demande de la préciser. */
|
|
3
3
|
const DEFAULT_URL_HINT = 'https://<votre-déploiement>.workers.dev';
|
|
4
4
|
function fail(message) {
|
|
@@ -24,14 +24,125 @@ export function registerCloudCommands(program) {
|
|
|
24
24
|
runCloudStatus({ json: options.json });
|
|
25
25
|
});
|
|
26
26
|
cloud
|
|
27
|
-
.command('
|
|
28
|
-
.description(
|
|
29
|
-
.
|
|
30
|
-
.
|
|
27
|
+
.command('push')
|
|
28
|
+
.description('Projette les plans et la mémoire projet vers le cloud : scelle, met en file, puis envoie')
|
|
29
|
+
.option('--url <url>', `Adresse du déploiement cloud (ex. ${DEFAULT_URL_HINT})`)
|
|
30
|
+
.option('--dry-run', "N'écrit ni n'envoie rien : rapporte ce qui partirait")
|
|
31
|
+
.option('--api-key <key>', 'Clé porteuse exigée par l ingestion (ou BRAINCLAW_CLOUD_API_KEY)')
|
|
32
|
+
.option('--limit <n>', 'Borne le lot envoyé', (v) => Number.parseInt(v, 10))
|
|
31
33
|
.option('--json', 'Sortie JSON')
|
|
32
|
-
.action(async (
|
|
34
|
+
.action(async (options) => {
|
|
35
|
+
try {
|
|
36
|
+
await runCloudPush({ ...options, apiKey: options.apiKey });
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
cloud
|
|
43
|
+
.command('pull')
|
|
44
|
+
.description('Tire le delta cloud, vérifie chaque enveloppe, puis matérialise les objets acceptés')
|
|
45
|
+
.option('--url <url>', `Adresse du déploiement cloud (ex. ${DEFAULT_URL_HINT})`)
|
|
46
|
+
.option('--api-key <key>', 'Clé porteuse exigée par l ingestion (ou BRAINCLAW_CLOUD_API_KEY)')
|
|
47
|
+
.option('--limit <n>', 'Borne le delta reçu', (v) => Number.parseInt(v, 10))
|
|
48
|
+
.option('--json', 'Sortie JSON')
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
try {
|
|
51
|
+
await runCloudPull({ ...options, apiKey: options.apiKey });
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
cloud
|
|
58
|
+
.command('grant <agentId>')
|
|
59
|
+
.description("Remet des clés d'epoch à un appareil approuvé — seul un détenteur actif le peut")
|
|
60
|
+
.option('--url <url>', `Adresse du déploiement cloud (ex. ${DEFAULT_URL_HINT})`)
|
|
61
|
+
// Le défaut est `current` (dec#163 §1) : un membre invité voit à partir de son
|
|
62
|
+
// arrivée. `all` est réservé à un autre appareil DE LA MÊME personne — c'est un choix
|
|
63
|
+
// explicite, jamais un effet de bord.
|
|
64
|
+
.option('--horizon <all|current>', "Étendue remise : 'all' (vos propres appareils) ou 'current' (invité)", 'current')
|
|
65
|
+
.option('--epoch <n...>', 'Epochs précis à remettre (outrepasse --horizon)', (v, acc) => {
|
|
66
|
+
acc.push(Number.parseInt(v, 10));
|
|
67
|
+
return acc;
|
|
68
|
+
}, [])
|
|
69
|
+
.option('--json', 'Sortie JSON')
|
|
70
|
+
.action(async (agentId, options) => {
|
|
71
|
+
try {
|
|
72
|
+
await runCloudGrant({
|
|
73
|
+
to: agentId,
|
|
74
|
+
url: options.url,
|
|
75
|
+
horizon: options.horizon,
|
|
76
|
+
epochs: options.epoch?.length ? options.epoch : undefined,
|
|
77
|
+
json: options.json,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
cloud
|
|
85
|
+
.command('grant-web <fingerprint>')
|
|
86
|
+
.description("Remet des clés d'epoch à une session NAVIGATEUR — recopiez l'empreinte affichée par le navigateur")
|
|
87
|
+
.option('--url <url>', `Adresse du déploiement cloud (ex. ${DEFAULT_URL_HINT})`)
|
|
88
|
+
.option('--horizon <all|current>', "Étendue remise : 'all' ou 'current'", 'current')
|
|
89
|
+
.option('--epoch <n...>', 'Epochs précis à remettre (outrepasse --horizon)', (v, acc) => {
|
|
90
|
+
acc.push(Number.parseInt(v, 10));
|
|
91
|
+
return acc;
|
|
92
|
+
}, [])
|
|
93
|
+
.option('--api-key <key>', "Clé porteuse exigée par l'ingestion (ou BRAINCLAW_CLOUD_API_KEY)")
|
|
94
|
+
.option('--json', 'Sortie JSON')
|
|
95
|
+
.action(async (fingerprint, options) => {
|
|
96
|
+
try {
|
|
97
|
+
await runCloudGrantWeb({
|
|
98
|
+
fingerprint,
|
|
99
|
+
url: options.url,
|
|
100
|
+
horizon: options.horizon,
|
|
101
|
+
epochs: options.epoch?.length ? options.epoch : undefined,
|
|
102
|
+
apiKey: options.apiKey,
|
|
103
|
+
json: options.json,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
cloud
|
|
111
|
+
.command('rotate')
|
|
112
|
+
.description("Crée l'epoch suivant et y bascule les écritures — ferme la lecture FUTURE à un révoqué")
|
|
113
|
+
// `--force` existe mais n'est PAS le premier réflexe : le refus de quorum nomme
|
|
114
|
+
// d'abord `accept-solo-risk`, qui laisse une trace datée. Forcer n'en laisse aucune.
|
|
115
|
+
.option('--force', 'Passer outre le quorum de récupération SANS consigner de consentement')
|
|
116
|
+
.option('--json', 'Sortie JSON')
|
|
117
|
+
.action(async (options) => {
|
|
118
|
+
try {
|
|
119
|
+
await runCloudRotate(options);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
cloud
|
|
126
|
+
.command('accept-solo-risk')
|
|
127
|
+
.description('Consigne votre acceptation du risque solo (perte de cette machine = perte du passé)')
|
|
128
|
+
.option('--json', 'Sortie JSON')
|
|
129
|
+
.action(async (options) => {
|
|
130
|
+
try {
|
|
131
|
+
await runCloudAcceptSoloRisk(options);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
cloud
|
|
138
|
+
.command('connect <url|code>')
|
|
139
|
+
.description("Rejoint un projet cloud depuis l'URL d'activation ou un code ; attend ensuite l'approbation humaine")
|
|
140
|
+
.option('--url <url>', `Origine du déploiement si vous fournissez un code nu (ex. ${DEFAULT_URL_HINT})`)
|
|
141
|
+
.requiredOption('--agent <id>', "Identifiant d'agent à enrôler (4 à 64 caractères : a-z, A-Z, 0-9, _ ou -)")
|
|
142
|
+
.option('--json', 'Sortie JSON')
|
|
143
|
+
.action(async (activation, options) => {
|
|
33
144
|
await runCloudConnect({
|
|
34
|
-
inviteCode,
|
|
145
|
+
inviteCode: activation,
|
|
35
146
|
url: options.url,
|
|
36
147
|
agentId: options.agent,
|
|
37
148
|
json: options.json,
|
|
@@ -39,11 +150,8 @@ export function registerCloudCommands(program) {
|
|
|
39
150
|
});
|
|
40
151
|
cloud
|
|
41
152
|
.command('await')
|
|
42
|
-
.description("
|
|
43
|
-
|
|
44
|
-
// n'est pas borné. Bloquer indéfiniment sur un tiers ferait un mauvais citoyen dans
|
|
45
|
-
// un script, et une interruption doit rester reprenable.
|
|
46
|
-
.requiredOption('--url <url>', 'Adresse du déploiement cloud')
|
|
153
|
+
.description("Reprend l'attente d'approbation humaine après une interruption (maximum 15 min)")
|
|
154
|
+
.option('--url <url>', 'Adresse du déploiement cloud (utilise celle mémorisée après appairage)')
|
|
47
155
|
.action(async (options) => {
|
|
48
156
|
await runCloudAwait({ url: options.url })
|
|
49
157
|
.catch((err) => fail(`Erreur : ${err instanceof Error ? err.message : String(err)}`));
|
|
@@ -51,7 +159,7 @@ export function registerCloudCommands(program) {
|
|
|
51
159
|
cloud
|
|
52
160
|
.command('disconnect')
|
|
53
161
|
.description("Retire l'autorisation locale et demande la révocation distante")
|
|
54
|
-
.
|
|
162
|
+
.option('--url <url>', 'Adresse du déploiement cloud (utilise celle mémorisée après appairage)')
|
|
55
163
|
// Effacer le trousseau rend DÉFINITIVEMENT illisible tout ce qui a été scellé sous
|
|
56
164
|
// ces epochs. Ce n'est donc pas le défaut : on le demande explicitement.
|
|
57
165
|
.option('--forget-keys', "Efface aussi les clés d'epoch de ce projet (le passé scellé devient illisible ici)")
|