create-openagent 0.2.0 → 0.3.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 +9 -0
- package/README.md +3 -3
- package/dist/index.js +23 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog — create-openagent
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## [0.3.0] - 2026-10-12
|
|
5
|
+
|
|
6
|
+
- Give every starter selector an inset arrow and room for its label, with a
|
|
7
|
+
native-control fallback for forced colors.
|
|
8
|
+
- Pin SDK 0.5.0 and populate family/kind choices from its catalog, including all
|
|
9
|
+
holiday families. Keep Autos default, face framing, real verified-request state
|
|
10
|
+
and stable animated eye nodes across appearance changes.
|
|
11
|
+
|
|
3
12
|
## [0.2.0] - 2026-10-11
|
|
4
13
|
|
|
5
14
|
- Generate a complete local identity and animated-avatar application using SDK
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ explicit receiver trust, authenticated HTTP requests and animated avatars run
|
|
|
5
5
|
locally without a Life account or a hosted identity service.
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npx create-openagent@0.
|
|
8
|
+
npx create-openagent@0.3.0 my-agent-app --yes
|
|
9
9
|
cd my-agent-app
|
|
10
10
|
npm install
|
|
11
11
|
npm run dev
|
|
@@ -13,8 +13,8 @@ npm run dev
|
|
|
13
13
|
|
|
14
14
|
In a second terminal, run `npm run agent`. It signs an actual server-issued
|
|
15
15
|
challenge; the receiver verifies the signature and current trust and consumes
|
|
16
|
-
the challenge exactly once. The viewer uses Autos by default,
|
|
17
|
-
and updates from actual verified requests. It uses the same SDK player you can
|
|
16
|
+
the challenge exactly once. The viewer uses Autos by default, offers all 17 families and 62 kinds with face
|
|
17
|
+
framing (including SpaceX and holiday characters), and updates from actual verified requests. It uses the same SDK player you can
|
|
18
18
|
mount in your own UI.
|
|
19
19
|
|
|
20
20
|
Node 20+ is required. Private keys and receiver state stay in the generated
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "url";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "create-openagent",
|
|
11
|
-
version: "0.
|
|
11
|
+
version: "0.3.0",
|
|
12
12
|
description: "Create a working OpenAgentID app with local identity, real verification and live avatars.",
|
|
13
13
|
license: "Apache-2.0 OR MIT",
|
|
14
14
|
author: "L1fe Labs, Inc. <eng@l1fe.ai>",
|
|
@@ -155,7 +155,7 @@ function generateStarterTemplate(projectName) {
|
|
|
155
155
|
identity: "node src/identity.mjs",
|
|
156
156
|
test: "node --test test/*.test.mjs"
|
|
157
157
|
},
|
|
158
|
-
dependencies: { "@openagentid/sdk": "0.
|
|
158
|
+
dependencies: { "@openagentid/sdk": "0.5.0" }
|
|
159
159
|
}, null, 2) + "\n" },
|
|
160
160
|
{ path: ".gitignore", content: "node_modules/\n.openagent/\ncoverage/\n.env\n" },
|
|
161
161
|
{ path: "src/workspaces.mjs", content: workspaces },
|
|
@@ -430,17 +430,27 @@ var html = String.raw`<!doctype html>
|
|
|
430
430
|
<title>My OpenAgent</title><link rel="stylesheet" href="/style.css"><script type="module" src="/viewer.js"></script></head>
|
|
431
431
|
<body><main><p class="eyebrow">OpenAgent · local starter</p><h1>Your agent, alive.</h1>
|
|
432
432
|
<div id="avatar" aria-label="Agent avatar"></div><p id="status" role="status">Connecting to the local receiver…</p>
|
|
433
|
-
<p id="identity"></p><div class="controls"><label>
|
|
433
|
+
<p id="identity"></p><div class="controls"><label>Family <select id="skin"></select></label>
|
|
434
|
+
<label>Kind <select id="shape"></select></label>
|
|
434
435
|
<label>Expression <select id="expression"><option value="">Follow actual status</option></select></label></div>
|
|
435
436
|
<p>In another terminal, run:</p><pre>npm run agent -- "Hello from my agent"</pre>
|
|
436
437
|
<p>This viewer is read-only. A completed request appears after the receiver verifies a fresh signed proof.</p>
|
|
437
438
|
<p>Keys stay on this computer. No account or identity service is required.</p></main></body></html>
|
|
438
439
|
`;
|
|
439
|
-
var css = String.raw`:root{font-family:system-ui,sans-serif;color:#ecf0f5;background:#10151c;color-scheme:dark}body{margin:0}main{max-width:760px;margin:0 auto;padding:48px 24px}h1{font-size:clamp(2rem,6vw,3.8rem);letter-spacing:-.05em;margin:12px 0}p{line-height:1.6;color:#bdc8d6}.eyebrow{font-size:.85rem;letter-spacing:.1em;text-transform:uppercase}#avatar{height:300px;display:flex;align-items:center;justify-content:center;margin:12px 0}#avatar svg{max-width:100%;height:280px}#identity{font-family:monospace;font-size:.85rem;overflow-wrap:anywhere}.controls{display:flex;gap:24px;flex-wrap:wrap}label{display:flex;gap:10px;align-items:center}select{padding:8px;border-radius:8px;background:#222d3b;color:inherit;border:1px solid #516176}pre{padding:18px;white-space:pre-wrap;background:#1b2532;border-radius:12px;border:1px solid #344458}#status{font-weight:600;color:#fff}
|
|
440
|
+
var css = String.raw`:root{font-family:system-ui,sans-serif;color:#ecf0f5;background:#10151c;color-scheme:dark}body{margin:0}main{max-width:760px;margin:0 auto;padding:48px 24px}h1{font-size:clamp(2rem,6vw,3.8rem);letter-spacing:-.05em;margin:12px 0}p{line-height:1.6;color:#bdc8d6}.eyebrow{font-size:.85rem;letter-spacing:.1em;text-transform:uppercase}#avatar{height:300px;display:flex;align-items:center;justify-content:center;margin:12px 0}#avatar svg{max-width:100%;height:280px;border-radius:50%;overflow:hidden}#identity{font-family:monospace;font-size:.85rem;overflow-wrap:anywhere}.controls{display:flex;gap:24px;flex-wrap:wrap}label{display:flex;gap:10px;align-items:center}select{appearance:none;padding:8px 38px 8px 12px;border-radius:8px;background-color:#222d3b;background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);background-position:right 17px center,right 12px center;background-size:5px 5px;background-repeat:no-repeat;color:inherit;border:1px solid #516176}@media(forced-colors:active){select{appearance:auto;background-image:none}}pre{padding:18px;white-space:pre-wrap;background:#1b2532;border-radius:12px;border:1px solid #344458}#status{font-weight:600;color:#fff}
|
|
440
441
|
`;
|
|
441
|
-
var viewer = String.raw`import { mountCharacter, getCharacterExpressions } from '/character-player.js';
|
|
442
|
+
var viewer = String.raw`import { mountCharacter, getCharacterExpressions, getCharacterSkins } from '/character-player.js';
|
|
442
443
|
|
|
443
444
|
const skin = document.querySelector('#skin');
|
|
445
|
+
const shape = document.querySelector('#shape');
|
|
446
|
+
const catalog = getCharacterSkins();
|
|
447
|
+
const display = value => value.replaceAll('-', ' ').replace(/^./, letter => letter.toUpperCase());
|
|
448
|
+
skin.replaceChildren(...catalog.map(entry => new Option(entry.label, entry.id)));
|
|
449
|
+
skin.value = 'autos';
|
|
450
|
+
function kinds() {
|
|
451
|
+
shape.replaceChildren(new Option('From identity', ''), ...catalog.find(entry => entry.id === skin.value).shapes.map(value => new Option(display(value), value)));
|
|
452
|
+
}
|
|
453
|
+
kinds();
|
|
444
454
|
const expression = document.querySelector('#expression');
|
|
445
455
|
const label = document.querySelector('#status');
|
|
446
456
|
const identity = document.querySelector('#identity');
|
|
@@ -449,7 +459,8 @@ for (const value of getCharacterExpressions()) {
|
|
|
449
459
|
expression.append(option);
|
|
450
460
|
}
|
|
451
461
|
let player, did, revision = -1, latestStatus = 'idle', stopped = false, timer;
|
|
452
|
-
skin.addEventListener('change', () => player?.setAppearance({ skin: skin.value }));
|
|
462
|
+
skin.addEventListener('change', () => { kinds(); player?.setAppearance({ skin: skin.value }); });
|
|
463
|
+
shape.addEventListener('change', () => player?.setAppearance({ shape: shape.value || null }));
|
|
453
464
|
expression.addEventListener('change', () => player?.update({ status: latestStatus, expression: expression.value || null }));
|
|
454
465
|
async function refresh() {
|
|
455
466
|
try {
|
|
@@ -461,7 +472,7 @@ async function refresh() {
|
|
|
461
472
|
!['idle', 'working', 'success'].includes(state.status) || !Number.isSafeInteger(state.completedRequests) || state.completedRequests < 0) throw new Error('Invalid receiver state.');
|
|
462
473
|
if (!player || state.did !== did) {
|
|
463
474
|
player?.dispose(); document.querySelector('#avatar').replaceChildren();
|
|
464
|
-
did = state.did; player = mountCharacter(document.querySelector('#avatar'), did, { skin: skin.value, size: 280, reducedMotion: 'system' });
|
|
475
|
+
did = state.did; player = mountCharacter(document.querySelector('#avatar'), did, { skin: skin.value, ...(shape.value ? { shape: shape.value } : {}), size: 280, reducedMotion: 'system' });
|
|
465
476
|
identity.textContent = did; revision = -1;
|
|
466
477
|
}
|
|
467
478
|
if (state.revision !== revision) {
|
|
@@ -482,7 +493,7 @@ Requires Node 20+. Run npm install, then npm run dev. Open the numeric loopback
|
|
|
482
493
|
|
|
483
494
|
npm run agent -- "Hello from my agent"
|
|
484
495
|
|
|
485
|
-
The command obtains a receiver-issued challenge, signs it with a persisted Ed25519 key, and sends a proof. After verification, the receiver hashes and echoes the message. The browser shows the real completed-request count, animated Autos by default, optional SpaceX and selectable expressions. It does not simulate work or broadcast runtime state elsewhere. Reduced motion follows your browser preference.
|
|
496
|
+
The command obtains a receiver-issued challenge, signs it with a persisted Ed25519 key, and sends a proof. After verification, the receiver hashes and echoes the message. The browser shows the real completed-request count, animated Autos by default, 16 optional families (including SpaceX and seasonal characters), distinct kinds, face framing and selectable expressions. It does not simulate work or broadcast runtime state elsewhere. Reduced motion follows your browser preference.
|
|
486
497
|
|
|
487
498
|
On first setup, src/workspaces.mjs creates two separate local authorities, persists a unique receiver audience and explicitly imports the signer's public DID/key document into the receiver with trustIdentity. The receiver has no signing key for that agent. The public export is .openagent/identity.json. Private keys, challenge and replay state remain under .openagent/ and are excluded from git. Inspect public identity with npm run identity -- export. Never publish .openagent/ or serve it as static assets.
|
|
488
499
|
|
|
@@ -494,7 +505,7 @@ Revocation is the receiver's durable local trust decision. Restarting does not r
|
|
|
494
505
|
|
|
495
506
|
The HTTP service listens only on 127.0.0.1:3210. Set PORT consistently for the server and agent command to choose another port, or set OPENAGENT_RECEIVER_URL on the command to the exact printed numeric origin. Host checks prevent DNS rebinding, cross-origin browser controls are refused, and only fixed public assets are served. Trust/revoke are local operator actions, never HTTP controls. GET /state contains only public DID and transient request presentation metadata; it contains no message, output, token or key.
|
|
496
507
|
|
|
497
|
-
This starter deliberately has no cloud-deployment, MCP, enterprise bridge or optional identity-stack dependency. Historical 0.1 templates need migration and are not generated by create-openagent 0.
|
|
508
|
+
This starter deliberately has no cloud-deployment, MCP, enterprise bridge or optional identity-stack dependency. Historical 0.1 templates need migration and are not generated by create-openagent 0.3.
|
|
498
509
|
`;
|
|
499
510
|
var tests = String.raw`import test from 'node:test';
|
|
500
511
|
import assert from 'node:assert/strict';
|
|
@@ -623,7 +634,9 @@ test('host, browser-origin, closed-schema and private/static paths are refused',
|
|
|
623
634
|
const viewer = await fetch(f.app.url + '/');
|
|
624
635
|
assert.equal(viewer.status, 200); assert.equal(viewer.headers.get('cache-control'), 'no-store');
|
|
625
636
|
assert.match(viewer.headers.get('content-security-policy'), /frame-ancestors 'none'/);
|
|
626
|
-
|
|
637
|
+
const markup = await viewer.text();
|
|
638
|
+
assert.match(markup, /<select id="skin"><\/select>/);
|
|
639
|
+
assert.match(markup, /<select id="shape"><\/select>/);
|
|
627
640
|
const script = await fetch(f.app.url + '/character-player.js');
|
|
628
641
|
assert.equal(script.status, 200); assert.match(await script.text(), /mountCharacter/);
|
|
629
642
|
const huge = await post(f.app, '/request', { value: 'x'.repeat(25000) }); assert.equal(huge.status, 413);
|
package/package.json
CHANGED