@augurworks/augur 0.15.8 → 0.15.9
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/README.md +21 -0
- package/package.json +1 -1
- package/scripts/connect.mjs +17 -1
- package/scripts/lib/adapters.mjs +6 -1
- package/scripts/open.mjs +8 -2
- package/src/_worker.js +33 -14
- package/src/chrome/appchrome.mjs +8 -2
package/README.md
CHANGED
|
@@ -53,6 +53,27 @@ contracts in [agents/](./agents/) does the same job. Screens in the demo space
|
|
|
53
53
|
carry the session that made them: [open the repo and read one](https://github.com/andratwiro/augur-space-fulla/tree/main/garden/prompts).
|
|
54
54
|
The follow-ups read like design direction, because that is what they are.
|
|
55
55
|
|
|
56
|
+
## Let an assistant in from a link
|
|
57
|
+
|
|
58
|
+
Someone on the team gives their assistant the workspace address and asks for a
|
|
59
|
+
change. Nothing else is needed from them, and no password ever changes hands.
|
|
60
|
+
The workspace tells the assistant how to get in (`/llms.txt` on every instance),
|
|
61
|
+
and the flow is device pairing:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx @augurworks/augur connect --origin https://<the workspace>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
It prints a link and a code. The person opens the link in the browser they are
|
|
68
|
+
already signed in to and types the code; that pairs the one terminal that printed
|
|
69
|
+
it, to publish as them. From then on the assistant opens a prototype as a draft
|
|
70
|
+
(`augur open <opportunity>/<prototype>`), edits it, live at the draft's own
|
|
71
|
+
address, and lands it (`augur land`), which moves the real URL. Signed-in members
|
|
72
|
+
see the same instructions under Help › Building and at `/__connect`, so a person
|
|
73
|
+
who knows nothing technical can still confirm what their assistant was told. The
|
|
74
|
+
package on npm is this repository, and nothing else: `npm view @augurworks/augur
|
|
75
|
+
repository`.
|
|
76
|
+
|
|
56
77
|
## Boards where the prototypes run
|
|
57
78
|
|
|
58
79
|
Drop a live prototype next to the stickies and drive it. Everyone on the board
|
package/package.json
CHANGED
package/scripts/connect.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import path from "node:path";
|
|
|
19
19
|
import os from "node:os";
|
|
20
20
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
21
|
import { resolveOrigin } from "./lib/store.mjs";
|
|
22
|
+
import { augurOnPath } from "./lib/adapters.mjs";
|
|
22
23
|
|
|
23
24
|
const C = { dim: "\x1b[2m", bold: "\x1b[1m", ok: "\x1b[32m", warn: "\x1b[33m", off: "\x1b[0m" };
|
|
24
25
|
const log = (m) => console.log(`\x1b[35m[connect]\x1b[0m ${m}`);
|
|
@@ -70,6 +71,11 @@ async function post(pathPart, body) {
|
|
|
70
71
|
// token still answers, say so and stop; `--again` pairs afresh on purpose, and a token the
|
|
71
72
|
// workspace no longer honours (revoked, another workspace's) falls through to a new pairing.
|
|
72
73
|
const AGAIN = argv.includes("--again");
|
|
74
|
+
// Whether this workspace serves drafts, from its own door — the success line names the
|
|
75
|
+
// right next verb, not `publish` on a workspace that refuses it. Asked before any path
|
|
76
|
+
// that can finish, including the one that collects a pairing started earlier.
|
|
77
|
+
let draftsHere = false;
|
|
78
|
+
try { const j = await (await fetch(`${ORIGIN}/.well-known/augur.json`, { headers: { Accept: "application/json" } })).json(); draftsHere = !!(j && j.drafts && j.drafts.enabled); } catch (e) { draftsHere = false; }
|
|
73
79
|
const TOKENS_FILE = path.join(os.homedir(), ".config", "augur", "tokens.json");
|
|
74
80
|
function savedToken() {
|
|
75
81
|
try { const t = JSON.parse(readFileSync(TOKENS_FILE, "utf8"))[host]; return t && t.token ? t : null; } catch (e) { return null; }
|
|
@@ -178,7 +184,17 @@ all[new URL(ORIGIN).host] = {
|
|
|
178
184
|
writeFileSync(file, JSON.stringify(all, null, 2), { mode: 0o600 });
|
|
179
185
|
|
|
180
186
|
log(`${C.ok}paired — publish access: ${saved.space === "*" ? "all spaces" : saved.space}${C.off}`);
|
|
181
|
-
|
|
187
|
+
// The next verb, spelled so it runs from THIS machine: `augur` after a global install, the
|
|
188
|
+
// package's own `npx` line otherwise — and the verb this workspace takes, which the door
|
|
189
|
+
// knows (drafts: open and land; a whole-tree instance: publish).
|
|
190
|
+
const verb = augurOnPath() ? "augur" : "npx @augurworks/augur";
|
|
191
|
+
if (draftsHere) {
|
|
192
|
+
console.log(`ready — \`${verb} open <opportunity>/<prototype>\` opens one prototype as a draft (live at once at its own address);`);
|
|
193
|
+
console.log(` edit the folder it makes, then \`${verb} land\` in that folder: the real URL moves.`);
|
|
194
|
+
} else {
|
|
195
|
+
console.log(`ready — \`${verb} publish\` will now use this token for ${ORIGIN}`);
|
|
196
|
+
}
|
|
197
|
+
if (verb !== "augur") console.log(`${C.dim}(\`augur\` is not on this machine's PATH; \`npm i -g @augurworks/augur\` puts it there for good.)${C.off}`);
|
|
182
198
|
if (saved.expiresAt) {
|
|
183
199
|
const days = Math.max(0, Math.round((Date.parse(saved.expiresAt) - Date.now()) / 86400000));
|
|
184
200
|
console.log(`${C.dim}It expires in ${days} days (${saved.expiresAt.slice(0, 10)}). Run \`augur connect\` again then.${C.off}`);
|
package/scripts/lib/adapters.mjs
CHANGED
|
@@ -107,7 +107,12 @@ export const hookCommand = (event, { onPath = false } = {}) =>
|
|
|
107
107
|
export function augurOnPath() {
|
|
108
108
|
try {
|
|
109
109
|
const out = execFileSync(process.platform === "win32" ? "where" : "which", ["augur"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
110
|
-
|
|
110
|
+
const found = out.trim().split(/\r?\n/)[0] || "";
|
|
111
|
+
// Inside an `npx` run the package's own bin dir is on PATH and `augur` resolves to a shim
|
|
112
|
+
// in the npx cache — gone the moment npx exits. A hook written as `augur hook pre` from
|
|
113
|
+
// there fails on every later edit (one cold agent's drafts never auto-saved, and its tool
|
|
114
|
+
// showed a "not found" on each write). That resolution counts as NOT on PATH.
|
|
115
|
+
return found.length > 0 && !/[\\/]_npx[\\/]/.test(found);
|
|
111
116
|
} catch (e) { return false; }
|
|
112
117
|
}
|
|
113
118
|
const ours = (h) => !!(h && Array.isArray(h.hooks) && h.hooks.some((x) => x && typeof x.command === "string" && OURS_RE.test(x.command.trim())));
|
package/scripts/open.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import fs from "node:fs";
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { target, buildStamp } from "./lib/store.mjs";
|
|
11
11
|
import { unitClient, doOpen, unitPathFor } from "./lib/draft.mjs";
|
|
12
|
-
import { installAdapters } from "./lib/adapters.mjs";
|
|
12
|
+
import { installAdapters, augurOnPath } from "./lib/adapters.mjs";
|
|
13
13
|
import { normUnit } from "../src/unit-core.mjs";
|
|
14
14
|
|
|
15
15
|
const log = (m) => console.error(`\x1b[35m[open]\x1b[0m ${m}`);
|
|
@@ -51,7 +51,7 @@ log(r.isNew ? `draft ${r.draftId} on ${unit} — a NEW prototype; ${dir} is empt
|
|
|
51
51
|
// here (idempotent; `AUGUR_NO_ADAPTERS=1` skips it — the suite and CI set it).
|
|
52
52
|
if (!process.env.AUGUR_NO_ADAPTERS) {
|
|
53
53
|
for (const a of installAdapters()) {
|
|
54
|
-
if (a.result === "installed") log(`${a.name}:
|
|
54
|
+
if (a.result === "installed") log(`${a.name}: a save hook is now in ${a.path} — after each edit inside a draft folder it runs \`augur hook post\`, which saves that draft to ${origin}; before an edit it refuses writes into a shared checkout's prototypes. It does nothing outside draft folders and talks to nothing else; \`augur hook remove\` takes it out.`);
|
|
55
55
|
else if (a.result === "updated") log(`${a.name}: editor hooks updated (${a.path}).`);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -60,4 +60,10 @@ if (r.others.length) {
|
|
|
60
60
|
for (const o of r.others) log(` ${o.session || "someone"} (${o.active ? "active" : "idle"})`);
|
|
61
61
|
log("nothing here stops you; if you both land, the second one syncs first.");
|
|
62
62
|
}
|
|
63
|
+
// The next two steps, spelled so they run from this machine (`augur` only after a global
|
|
64
|
+
// install; the package's `npx` line otherwise).
|
|
65
|
+
const verb = augurOnPath() ? "augur" : "npx @augurworks/augur";
|
|
66
|
+
log(r.isNew
|
|
67
|
+
? `next: write ${path.join(dir, "index.html")} (self-contained static HTML); it is live at the address below as soon as it saves. When it is ready: \`cd ${path.basename(dir)} && ${verb} land\` — the last line printed is the live URL.`
|
|
68
|
+
: `next: edit the files in ${dir}; every save is live at the address below. When it is ready: \`cd ${path.basename(dir)} && ${verb} land\` — the last line printed is the live URL.`);
|
|
63
69
|
console.log(r.address);
|
package/src/_worker.js
CHANGED
|
@@ -3748,7 +3748,7 @@ async function mintPublishToken(kv, tctx, u, { label = null, env = null } = {})
|
|
|
3748
3748
|
* Self-contained, like the login and 404 pages beside it: this must render for somebody
|
|
3749
3749
|
* whose terminal is already waiting, so it depends on no chrome bundle and no space.
|
|
3750
3750
|
*/
|
|
3751
|
-
function connectPage(tctx, me) {
|
|
3751
|
+
function connectPage(tctx, me, origin) {
|
|
3752
3752
|
const body = roleOf(me) === "viewer"
|
|
3753
3753
|
? `<h1>Connect a terminal</h1>
|
|
3754
3754
|
<p>This account can look around but not publish, so it cannot approve a terminal.</p>
|
|
@@ -3761,6 +3761,10 @@ function connectPage(tctx, me) {
|
|
|
3761
3761
|
<p class="warn">Only approve a code from a terminal you started or an assistant you
|
|
3762
3762
|
are talking to right now. A code that arrives by mail, from a stranger, or out of
|
|
3763
3763
|
the blue is not yours — do not type it.</p>
|
|
3764
|
+
<p>Where the code comes from: the terminal or assistant runs
|
|
3765
|
+
<code>npx @augurworks/augur connect --origin ${escapeHtml(origin || "")}</code>, this
|
|
3766
|
+
workspace's own command-line tool, and it shows the code. An assistant that has not
|
|
3767
|
+
shown you one yet can be told to run that.</p>
|
|
3764
3768
|
<form id="pairf">
|
|
3765
3769
|
<input id="pairc" autocomplete="off" autocapitalize="characters" spellcheck="false"
|
|
3766
3770
|
placeholder="ABCD-EFGH" aria-label="Pairing code" />
|
|
@@ -9275,22 +9279,37 @@ function doorText(f) {
|
|
|
9275
9279
|
const body = f.pairing.enabled
|
|
9276
9280
|
? `Run, on the machine that will publish:\n\n`
|
|
9277
9281
|
+ ` ${f.connect}\n\n`
|
|
9278
|
-
+ `It prints a link and a code.
|
|
9282
|
+
+ `It prints a link and a code. A member of this workspace opens the link in a\n`
|
|
9279
9283
|
+ `browser they are already signed in to and enters the code. The token lands on\n`
|
|
9280
|
-
+ `that machine, and every verb below uses it from then on.\n
|
|
9281
|
-
+ `
|
|
9282
|
-
+ `
|
|
9283
|
-
+ `
|
|
9284
|
-
+ `
|
|
9285
|
-
+ `
|
|
9286
|
-
+ `
|
|
9287
|
-
+ `
|
|
9288
|
-
+ `
|
|
9289
|
-
+ `
|
|
9290
|
-
+ `
|
|
9284
|
+
+ `that machine and nowhere else, and every verb below uses it from then on.\n`
|
|
9285
|
+
+ `Approving a code lets that one terminal publish as the person who approved it;\n`
|
|
9286
|
+
+ `everything it lands carries their name. A member whose role is viewer cannot\n`
|
|
9287
|
+
+ `approve, and the page says so.\n\n`
|
|
9288
|
+
+ `Members see this same instruction when signed in, at ${f.origin}/__connect and\n`
|
|
9289
|
+
+ `under Help > Building — so the person you are working for can read it there and\n`
|
|
9290
|
+
+ `confirm it is this workspace's own, without knowing anything technical.\n\n`
|
|
9291
|
+
+ `What the command is, for anyone who checks before running it: the CLI is this\n`
|
|
9292
|
+
+ `engine's own, open source at ${f.source} — the same engine that serves this page\n`
|
|
9293
|
+
+ `(${f.origin}/_build.json names the engine commit). \`npm view @augurworks/augur repository\`\n`
|
|
9294
|
+
+ `names that repository; \`npm pack @augurworks/augur\` lets you read it first. It is plain\n`
|
|
9295
|
+
+ `JavaScript with no runtime dependencies; the pairing is scripts/connect.mjs and it\n`
|
|
9296
|
+
+ `talks only to this origin's /__publish/_pair/ routes. It asks for no password, and\n`
|
|
9297
|
+
+ `there is none to give it.\n\n`
|
|
9298
|
+
+ `How the pairing goes when the person approving is not at the keyboard (an\n`
|
|
9299
|
+
+ `assistant working for them): the approval is theirs, in their browser — nobody\n`
|
|
9300
|
+
+ `else can do it, and the command does not try. Send them the line the command\n`
|
|
9301
|
+
+ `prints, as it is. When they will read that message only after the current turn\n`
|
|
9302
|
+
+ `ends, run \`connect --no-wait\`: it prints the line and exits. Once they say they\n`
|
|
9303
|
+
+ `approved, run the same command again — it collects the token for that same code and\n`
|
|
9304
|
+
+ `mints no second one. Waiting inside one turn skips nothing; it only hides the code\n`
|
|
9305
|
+
+ `from them for the five minutes it lives.\n\n`
|
|
9291
9306
|
+ (f.drafts && f.drafts.enabled
|
|
9292
9307
|
? `You need no source tree here: \`augur open <opportunity>/<prototype>\` fetches that one\n`
|
|
9293
9308
|
+ `prototype into a folder of its own (see below). Do not clone the workspace first.\n\n`
|
|
9309
|
+
+ `Until \`npm i -g @augurworks/augur\`, every verb runs as \`npx @augurworks/augur <verb>\`.\n`
|
|
9310
|
+
+ `The first \`open\` on a machine also installs a save hook in the editor tool's\n`
|
|
9311
|
+
+ `settings (it says which file): after each edit inside a draft folder it saves that\n`
|
|
9312
|
+
+ `draft; it does nothing elsewhere, and \`augur hook remove\` takes it out.\n\n`
|
|
9294
9313
|
: `With no source tree yet, \`npx @augurworks/augur clone --space ${f.workspace}\` then fetches\n`
|
|
9295
9314
|
+ `one (it reads the origin from the pairing).\n\n`)
|
|
9296
9315
|
: `Device pairing is switched off on this workspace. Ask an admin for an invite;\n`
|
|
@@ -11922,7 +11941,7 @@ async function handleRequest(request, env, ctx, url, trace) {
|
|
|
11922
11941
|
if (url.pathname === "/__connect" && tctx.DEVICE_PAIRING) {
|
|
11923
11942
|
const who = tctx.USERS.length ? await identify(request, env, tctx.USERS, { sessionKeys: tctx.SESSION_KEYS, tctx }) : null;
|
|
11924
11943
|
if (!who && tctx.USERS.length) return htmlResponse(loginPage(tctx, "/__connect", false, url.href), 200);
|
|
11925
|
-
return htmlResponse(connectPage(tctx, who), 200);
|
|
11944
|
+
return htmlResponse(connectPage(tctx, who, url.origin), 200);
|
|
11926
11945
|
}
|
|
11927
11946
|
if (url.pathname.startsWith("/__publish/_pair/")) {
|
|
11928
11947
|
// Identity is resolved here rather than reusing the gate's `me` below, because this
|
package/src/chrome/appchrome.mjs
CHANGED
|
@@ -386,10 +386,16 @@ function helpDrawer(state) {
|
|
|
386
386
|
<li>The design system is read-only from a prototype. Edit the skill's own source rather than copying its classes out.</li>
|
|
387
387
|
</ul>
|
|
388
388
|
|
|
389
|
+
<h4>Working with an assistant</h4>
|
|
390
|
+
<ul>
|
|
391
|
+
<li>Give it this workspace's address and say what you want changed or made. It reads how to get in from this site and hands you a link and a short code.</li>
|
|
392
|
+
<li>Open the link here (<code>/__connect</code>) and type the code. That pairs its terminal to publish as you; everything it lands carries your name.</li>
|
|
393
|
+
<li>From then on it opens a prototype as a draft, edits it live at the draft's own address, and lands it when you say so. Viewers cannot approve a code.</li>
|
|
394
|
+
</ul>
|
|
395
|
+
|
|
389
396
|
<h4>Comment loop <span class="gvhelp__tag">maintainer</span></h4>
|
|
390
397
|
<ul>
|
|
391
|
-
<li
|
|
392
|
-
<li>The agent fixes, replies, resolves in-thread. Put it on <code>/loop</code> to keep watching.</li>
|
|
398
|
+
<li>In a checkout, <code>npm run review --open</code> lists open threads; an agent fixes, replies and resolves in-thread.</li>
|
|
393
399
|
<li>Not automated. You steer it.</li>
|
|
394
400
|
</ul>${spaceHelpSections(state)}
|
|
395
401
|
</section>
|