@tomato414941/foundation 0.1.0 → 0.2.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/guide.mjs +14 -10
- package/package.json +1 -1
- package/runtime.mjs +10 -8
package/guide.mjs
CHANGED
|
@@ -26,16 +26,20 @@ export function guide(connectors) {
|
|
|
26
26
|
'Nothing here needs a shell. With one, use foundation api to attach the key and foundation exec to deliver values',
|
|
27
27
|
'to a command. api prints responses: use function save options when output should not enter your context.',
|
|
28
28
|
'Never ask the owner to paste passwords, keys or tokens into chat. Use a storage request or OAuth URL instead.', '',
|
|
29
|
-
'
|
|
30
|
-
'
|
|
29
|
+
'WHO YOU ARE',
|
|
30
|
+
' Everything that comes to Foundation is a principal: a person, an AI, an app. You are one, and your key is what',
|
|
31
|
+
' proves it: a secret of your own making, 43 URL-safe base64 characters after `fdn_`. Generate one, keep it private,',
|
|
31
32
|
' and never print it. If you can write a private file, keep it there; otherwise keep it wherever your secrets go.',
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
33
|
+
' What you may reach follows from lines between principals: whoever you act for (actor), whoever made you (owner).',
|
|
34
|
+
' POST /v1/requests {"kind": "actor", "input": {"name": "<what to call you>"}} with your key as the bearer.',
|
|
35
|
+
' Asks whoever opens it to let you act for them. Returns verification_uri and confirmation_code. Give the person',
|
|
36
|
+
' both; they open the URL and type the code. Until they do you act for nobody: everything below answers as',
|
|
37
|
+
' your own, empty, holdings. Retry GET /v1/principals/me every few seconds and look at acts_for. Do not hammer it.',
|
|
38
|
+
' GET /v1/principals/me who you are: principal, acts_for (whom you act for), owners, credentials, your open requests.',
|
|
39
|
+
' Acting for exactly one principal, their holdings are what the calls below reach. For several, name one: ?as=<id>.',
|
|
40
|
+
' PATCH /v1/principals/me {"name"} DELETE /v1/principals/me a new name; leaving (your key stops working).',
|
|
41
|
+
' GET /v1/requests/<id> one of your requests and what happened at its page (events). DELETE cancels it.',
|
|
42
|
+
' GET /v1/relations every line you are on. GET /v1/records what was done in your name or to you.', '',
|
|
39
43
|
'WHAT IS KEPT',
|
|
40
44
|
' PUT /v1/secrets?name=<name>&secret=true body: raw bytes, up to 1MB. The same exact name replaces that value.',
|
|
41
45
|
' secret=true blocks direct GET by an access key. The owner can read it; authorized delivery can still return it.',
|
|
@@ -103,7 +107,7 @@ export function guide(connectors) {
|
|
|
103
107
|
' Request feedback expires with the request. A done result is a connection_id or the names saved at completion.',
|
|
104
108
|
' Why a registration failed: invalid_values (wrong shape) / invalid_credential (the connector would not take it) /',
|
|
105
109
|
' reconnect_required (the service rejected it) / already_connected. A key approval shows its own events at',
|
|
106
|
-
' GET /v1/
|
|
110
|
+
' GET /v1/requests/<id>: confirmation_required (a wrong code) / confirmation_locked (5 tries).', '',
|
|
107
111
|
'A PLACE FOR FILES (object storage the owner did not have to sign up for)',
|
|
108
112
|
' PUT /v1/objects/<key> body is the bytes; the Content-Type you send is what a reader gets back. Up to 25MB.',
|
|
109
113
|
' GET /v1/objects/<key> the bytes. DELETE removes it. GET /v1/objects?prefix=<p>&cursor=<c> lists what is there.',
|
package/package.json
CHANGED
package/runtime.mjs
CHANGED
|
@@ -206,20 +206,22 @@ async function main() {
|
|
|
206
206
|
// Asking the owner to approve this key. The key itself is never printed: it stays in the file.
|
|
207
207
|
// A key the owner already approved has nothing to ask; connecting again only changes which server is remembered.
|
|
208
208
|
if (action === 'connect') {
|
|
209
|
-
|
|
209
|
+
// A key someone already accepted has nothing to ask; connecting again only changes which server is remembered.
|
|
210
|
+
let me = null;
|
|
211
|
+
try { me = await send('/v1/principals/me', undefined, { method: 'GET' }); } catch {}
|
|
212
|
+
const answer = me?.acts_for?.length ? null : await send('/v1/requests', { kind: 'actor', input: { name: name ?? hostname() + ' の ' + (agentName || 'AI') } });
|
|
210
213
|
if (connectTo !== undefined) await saveUrl(url.origin);
|
|
211
|
-
console.log(answer
|
|
214
|
+
console.log(answer === null ? 'Already approved on ' + url.origin + '.' : JSON.stringify(answer, null, 2));
|
|
212
215
|
console.log('\nKey file: ' + keyPath + '\nServer: ' + url.origin + (connectTo !== undefined ? ' (saved to ' + configPath() + ')' : '') + '\nEverything else is HTTP: Authorization: Bearer <the contents of that file>');
|
|
213
216
|
return;
|
|
214
217
|
}
|
|
215
|
-
//
|
|
218
|
+
// Nothing runs before someone has accepted this key: a key that acts for nobody reaches only its own empty holdings,
|
|
219
|
+
// and the person it asked has yet to answer.
|
|
220
|
+
const current = await send('/v1/principals/me', undefined, { method: 'GET' });
|
|
221
|
+
if (!current.acts_for?.length) throw new Error('Foundation request failed (401, not_approved). This key acts for nobody yet' + (current.requests?.[0] ? '; it is waiting for approval at ' + current.requests[0].verification_uri : '') + '.');
|
|
216
222
|
let delivery;
|
|
217
223
|
if (names.length) ({ delivery } = await send('/v1/deliveries', { names }));
|
|
218
|
-
else {
|
|
219
|
-
const current = await send('/v1/keys/current', undefined, { method: 'GET' });
|
|
220
|
-
if (!current.key) throw new Error('Foundation request failed (401, not_approved). This key is waiting for approval at ' + current.request?.verification_uri + '.');
|
|
221
|
-
delivery = { environment: {}, files: [] };
|
|
222
|
-
}
|
|
224
|
+
else delivery = { environment: {}, files: [] };
|
|
223
225
|
if (!delivery || typeof delivery.environment !== 'object' || !Array.isArray(delivery.files)) throw new Error('Foundation returned an invalid delivery.');
|
|
224
226
|
// What each of them sets is the server's to say; this applies it and refuses anything it may not set.
|
|
225
227
|
const environment = { ...process.env };
|