@rubytech/create-realagent 1.0.772 → 1.0.775
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/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/entitlement/PUBKEY-HASH.txt +1 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.d.ts +26 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.d.ts.map +1 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.js +54 -0
- package/payload/platform/lib/entitlement/dist/canonicalize.js.map +1 -0
- package/payload/platform/lib/entitlement/dist/index.d.ts +76 -0
- package/payload/platform/lib/entitlement/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/entitlement/dist/index.js +293 -0
- package/payload/platform/lib/entitlement/dist/index.js.map +1 -0
- package/payload/platform/lib/entitlement/rubytech-pubkey.pem +3 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +32 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +140 -10
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +5 -6
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +5 -6
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +10 -5
- package/payload/platform/scripts/generate-entitlement-fixture.mjs +152 -0
- package/payload/server/chunk-2HBD6IRL.js +3242 -0
- package/payload/server/chunk-MIP54X7Q.js +3244 -0
- package/payload/server/chunk-PIMJJCOQ.js +9563 -0
- package/payload/server/chunk-TM3EQSID.js +9800 -0
- package/payload/server/client-pool-4MZN42GG.js +28 -0
- package/payload/server/client-pool-U3A5YUO7.js +28 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/{Checkbox-DEE8t2QO.js → Checkbox-C_KxaLc-.js} +1 -1
- package/payload/server/public/assets/{admin-CFttroHB.js → admin-xbKPR6ZI.js} +30 -30
- package/payload/server/public/assets/data-D23IzpJ2.js +1 -0
- package/payload/server/public/assets/graph-D2AS9zFS.js +1 -0
- package/payload/server/public/assets/{jsx-runtime-DSbkOE76.css → jsx-runtime-BZtBxBng.css} +1 -1
- package/payload/server/public/assets/{page-YUT5e7hL.js → page-CjTfZ3O6.js} +2 -2
- package/payload/server/public/assets/{page-ZATk95ZG.js → page-DEWgk_nR.js} +1 -1
- package/payload/server/public/assets/{public-BLi3J8KU.js → public-CehiL-qZ.js} +1 -1
- package/payload/server/public/assets/{share-2-DS7Pnkkq.js → share-2-BG1VXt3z.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-pEHqS1ib.js → useVoiceRecorder-1Dvb-yHn.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +52 -17
- package/payload/server/public/assets/data-ryPag-T-.js +0 -1
- package/payload/server/public/assets/graph-BPnH-UZB.js +0 -1
- /package/payload/server/public/assets/{jsx-runtime-DeNudFNA.js → jsx-runtime-DrneHL3t.js} +0 -0
|
@@ -203,13 +203,12 @@ Invoke the `business-profile` skill. Follow its first-run path: create the `Admi
|
|
|
203
203
|
|
|
204
204
|
### `personal`
|
|
205
205
|
|
|
206
|
-
Personal mode does not register a `LocalBusiness`.
|
|
206
|
+
Personal mode does not register a `LocalBusiness`. The `AdminUser` and personal-profile `Person` nodes were written deterministically at PIN setup time (Task 830 — `writeAdminUserAndPerson`), so this step only enriches the existing Person with an email:
|
|
207
207
|
|
|
208
|
-
1. **Ask the user for their email** in one short conversational message — {{productName}} needs an email or phone number on the personal-profile node
|
|
209
|
-
2. **
|
|
210
|
-
3. **
|
|
211
|
-
4. **
|
|
212
|
-
5. **Mark step 9 complete.** Call `onboarding-complete-step` with step 9.
|
|
208
|
+
1. **Ask the user for their email** in one short conversational message — {{productName}} needs an email or phone number on the personal-profile node for downstream features (notifications, contact-method matching).
|
|
209
|
+
2. **Locate the personal-profile `Person`.** Call `memory-search` with the user's name from `admin-identity` plus `role: "admin-personal"` to find the existing node bound to the `AdminUser` via `OWNS`.
|
|
210
|
+
3. **Attach the email.** Call `memory-update` on that Person with `properties: { email }`. Do NOT create a new Person — the set-pin path already created and bound it.
|
|
211
|
+
4. **Mark step 9 complete.** Call `onboarding-complete-step` with step 9.
|
|
213
212
|
|
|
214
213
|
After step 9 completes in personal mode, tell the user that {{productName}} is configured for personal use — their employer (if any) is not registered here. If they later become the operator for a business of their own, they can ask {{productName}} to set up a business profile, which invokes the `business-profile` skill directly.
|
|
215
214
|
|
|
@@ -20,10 +20,9 @@ External Claude Code plugins (Stripe, Playground):
|
|
|
20
20
|
|
|
21
21
|
Built-in plugins under `$PLATFORM_ROOT/plugins/`:
|
|
22
22
|
|
|
23
|
-
- Enable:
|
|
24
|
-
- Disable:
|
|
25
|
-
-
|
|
26
|
-
- Validate: before enabling, confirm the plugin directory exists under `$PLATFORM_ROOT/plugins/` and its PLUGIN.md has `optional: true` in `metadata.platform`.
|
|
23
|
+
- Enable: call `plugin-toggle-enabled` with `pluginName` and `action: "enable"`. Activates the plugin's behaviour embed and MCP server from the next session. Plugins with scheduled behaviour (declared via `lifecycle` in PLUGIN.md frontmatter) are activated automatically by the platform heartbeat within one minute — no separate setup command needed.
|
|
24
|
+
- Disable: call `plugin-toggle-enabled` with `pluginName` and `action: "disable"`. Deactivates from the next session. Any scheduled Events owned by the plugin (`sourcePlugin` field) are cancelled automatically by the platform heartbeat.
|
|
25
|
+
- The tool refuses core plugins (admin, memory, docs, cloudflare, anthropic) and refuses plugins not installed under `$PLATFORM_ROOT/plugins/`. Direct `Edit` of `account.json` is denied by the pre-tool-use hook (Task 831) — `plugin-toggle-enabled` is the only legitimate path.
|
|
27
26
|
|
|
28
27
|
## Premium Plugins
|
|
29
28
|
|
|
@@ -39,7 +38,13 @@ When the user asks about a specific premium plugin (e.g., "tell me about the tea
|
|
|
39
38
|
|
|
40
39
|
### Recording a purchase
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
`purchasedPlugins` is an entitlement-bearing field (Task 831): the effective list derives from the Rubytech-signed entitlement payload, not from raw `account.json`. The pre-tool-use hook denies any agent write to `account.json`. Direct purchase recording is therefore unavailable to the agent.
|
|
42
|
+
|
|
43
|
+
- **Production path:** Task 832 — Rubytech-side issuance endpoint signs an updated entitlement payload after a Stripe purchase event and delivers it to `~/<configDir>/entitlement.json`. The verifier picks up the new payload at the next session start.
|
|
44
|
+
- **Pre-launch / dev path:** the founder runs `node platform/scripts/generate-entitlement-fixture.mjs sign --account-id <id> --email <e> --tier <t> --plugins a,b,c --out ~/<configDir>/entitlement.json` to produce a signed test payload. The agent does not invoke this script.
|
|
45
|
+
- **Personal-mode installs (`brand.json.commercialMode: false`, the default today):** purchasedPlugins is read from raw `account.json` via implicit-trust mode. Pre-launch the agent has no way to add purchases without operator intervention; this is intentional during the gap before Task 832 ships.
|
|
46
|
+
|
|
47
|
+
If the user asks the agent to record a purchase, explain that their purchase is processed by Rubytech billing and the entitlement payload arrives on their device automatically — no agent action is required.
|
|
43
48
|
|
|
44
49
|
### Delivering a premium plugin
|
|
45
50
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* One-shot Rubytech-side entitlement fixture generator.
|
|
4
|
+
*
|
|
5
|
+
* RUN BY FOUNDER ONCE; NEVER ON CUSTOMER DEVICES.
|
|
6
|
+
*
|
|
7
|
+
* Produces:
|
|
8
|
+
* - platform/lib/entitlement/rubytech-pubkey.pem (vendored, committed)
|
|
9
|
+
* - platform/lib/entitlement/PUBKEY-HASH.txt (sha256 of pubkey, committed)
|
|
10
|
+
* - .secrets/rubytech-private-key.pem (LOCAL ONLY — never commit)
|
|
11
|
+
* - <out-dir>/entitlement.json (signed payload fixture)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node platform/scripts/generate-entitlement-fixture.mjs init
|
|
15
|
+
* → generates a fresh keypair + writes the pubkey + hash
|
|
16
|
+
*
|
|
17
|
+
* node platform/scripts/generate-entitlement-fixture.mjs sign \
|
|
18
|
+
* --account-id <id> --email <email> --tier <solo|family|pro> \
|
|
19
|
+
* --plugins <comma-list> --days <n> --out <path>
|
|
20
|
+
* → signs a payload using the existing private key
|
|
21
|
+
*
|
|
22
|
+
* The verifier at platform/lib/entitlement/src/index.ts has PUBKEY_SHA256
|
|
23
|
+
* baked into source. After running `init` the script prints the new hash —
|
|
24
|
+
* paste it into the verifier and rebuild.
|
|
25
|
+
*
|
|
26
|
+
* For Task 832 (Rubytech-side issuance endpoint), this script will be
|
|
27
|
+
* replaced by a server-side equivalent. Until then, it stands in.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
generateKeyPairSync,
|
|
32
|
+
createPublicKey,
|
|
33
|
+
createPrivateKey,
|
|
34
|
+
createHash,
|
|
35
|
+
sign as cryptoSign,
|
|
36
|
+
} from "node:crypto";
|
|
37
|
+
import { writeFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
38
|
+
import { resolve, dirname } from "node:path";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
|
|
41
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
42
|
+
const __dirname = dirname(__filename);
|
|
43
|
+
const PLATFORM_ROOT = resolve(__dirname, "..");
|
|
44
|
+
const REPO_ROOT = resolve(PLATFORM_ROOT, "..");
|
|
45
|
+
const PUBKEY_PATH = resolve(PLATFORM_ROOT, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
46
|
+
const HASH_PATH = resolve(PLATFORM_ROOT, "lib", "entitlement", "PUBKEY-HASH.txt");
|
|
47
|
+
const SECRET_DIR = resolve(REPO_ROOT, ".secrets");
|
|
48
|
+
const PRIVKEY_PATH = resolve(SECRET_DIR, "rubytech-private-key.pem");
|
|
49
|
+
|
|
50
|
+
function canonicalize(value) {
|
|
51
|
+
if (value === null) return "null";
|
|
52
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
53
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
54
|
+
if (typeof value === "number") {
|
|
55
|
+
if (!Number.isFinite(value)) throw new Error("non-finite number");
|
|
56
|
+
if (Object.is(value, -0)) throw new Error("negative zero");
|
|
57
|
+
return JSON.stringify(value);
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(value)) return "[" + value.map(canonicalize).join(",") + "]";
|
|
60
|
+
if (typeof value === "object") {
|
|
61
|
+
const keys = Object.keys(value).sort();
|
|
62
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canonicalize(value[k])).join(",") + "}";
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`unsupported value type ${typeof value}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function init() {
|
|
68
|
+
if (existsSync(PRIVKEY_PATH)) {
|
|
69
|
+
console.error(`ABORT: private key already exists at ${PRIVKEY_PATH}.`);
|
|
70
|
+
console.error("Delete it manually if you really want to regenerate (ALL EXISTING SIGNED PAYLOADS WILL BREAK).");
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
74
|
+
const pubPem = publicKey.export({ type: "spki", format: "pem" });
|
|
75
|
+
const privPem = privateKey.export({ type: "pkcs8", format: "pem" });
|
|
76
|
+
|
|
77
|
+
if (!existsSync(SECRET_DIR)) mkdirSync(SECRET_DIR, { recursive: true });
|
|
78
|
+
writeFileSync(PRIVKEY_PATH, privPem, { mode: 0o600 });
|
|
79
|
+
writeFileSync(PUBKEY_PATH, pubPem, "utf-8");
|
|
80
|
+
|
|
81
|
+
const hash = createHash("sha256").update(pubPem).digest("hex");
|
|
82
|
+
writeFileSync(HASH_PATH, hash + "\n", "utf-8");
|
|
83
|
+
|
|
84
|
+
console.log(`Generated keypair.`);
|
|
85
|
+
console.log(` Public key : ${PUBKEY_PATH}`);
|
|
86
|
+
console.log(` Hash file : ${HASH_PATH} (${hash})`);
|
|
87
|
+
console.log(` Private key : ${PRIVKEY_PATH} (DO NOT COMMIT — verify .gitignore)`);
|
|
88
|
+
console.log("");
|
|
89
|
+
console.log(`NEXT: paste the hash into platform/lib/entitlement/src/index.ts:`);
|
|
90
|
+
console.log(` export const PUBKEY_SHA256 = "${hash}";`);
|
|
91
|
+
console.log(`Then run npm --prefix platform run build:lib`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseArgs(argv) {
|
|
95
|
+
const out = {};
|
|
96
|
+
for (let i = 0; i < argv.length; i += 2) {
|
|
97
|
+
const key = argv[i].replace(/^--/, "");
|
|
98
|
+
out[key] = argv[i + 1];
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function sign(args) {
|
|
104
|
+
const required = ["account-id", "email", "tier", "out"];
|
|
105
|
+
for (const k of required) {
|
|
106
|
+
if (!args[k]) {
|
|
107
|
+
console.error(`Missing --${k}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!existsSync(PRIVKEY_PATH)) {
|
|
112
|
+
console.error(`Private key missing at ${PRIVKEY_PATH}. Run 'init' first.`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const days = Number(args.days ?? "365");
|
|
116
|
+
const plugins = (args.plugins ?? "")
|
|
117
|
+
.split(",")
|
|
118
|
+
.map((s) => s.trim())
|
|
119
|
+
.filter(Boolean);
|
|
120
|
+
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
const issued = new Date(now).toISOString();
|
|
123
|
+
const expires = new Date(now + days * 86400 * 1000).toISOString();
|
|
124
|
+
|
|
125
|
+
const payload = {
|
|
126
|
+
accountId: args["account-id"],
|
|
127
|
+
customerEmail: args.email,
|
|
128
|
+
tier: args.tier,
|
|
129
|
+
purchasedPlugins: plugins,
|
|
130
|
+
issued,
|
|
131
|
+
expires,
|
|
132
|
+
};
|
|
133
|
+
const canonical = canonicalize(payload);
|
|
134
|
+
const privKey = createPrivateKey(readFileSync(PRIVKEY_PATH, "utf-8"));
|
|
135
|
+
const sigBuf = cryptoSign(null, Buffer.from(canonical, "utf-8"), privKey);
|
|
136
|
+
const envelope = { payload, signature: sigBuf.toString("base64") };
|
|
137
|
+
writeFileSync(args.out, JSON.stringify(envelope, null, 2) + "\n", "utf-8");
|
|
138
|
+
console.log(`Signed payload written to ${args.out}`);
|
|
139
|
+
console.log(` tier=${payload.tier} plugins=${plugins.length} expires=${expires}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const cmd = process.argv[2];
|
|
143
|
+
if (cmd === "init") {
|
|
144
|
+
init();
|
|
145
|
+
} else if (cmd === "sign") {
|
|
146
|
+
sign(parseArgs(process.argv.slice(3)));
|
|
147
|
+
} else {
|
|
148
|
+
console.error("Usage:");
|
|
149
|
+
console.error(" generate-entitlement-fixture.mjs init");
|
|
150
|
+
console.error(" generate-entitlement-fixture.mjs sign --account-id <id> --email <e> --tier <t> [--plugins a,b] [--days N] --out <path>");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|