@kubitnodes/stellaris 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/LICENSE +21 -0
- package/README.md +3 -2
- package/dist/cli/index.js +167 -12
- package/dist/server/index.js +543 -32
- package/package.json +2 -1
- package/web/dist/assets/ChannelView-O1FQ_Cbf.js +1 -0
- package/web/dist/assets/CitizenView-D0rSRBnj.js +2 -0
- package/web/dist/assets/CitizensView-BPx5ChvL.js +1 -0
- package/web/dist/assets/KnowledgeView-Cjf5Axu5.js +1 -0
- package/web/dist/assets/Markdown-Dkiv3bKi.js +29 -0
- package/web/dist/assets/MessageItem-sep2BGUh.js +1 -0
- package/web/dist/assets/MetricsView-BIH8FLob.js +1 -0
- package/web/dist/assets/NeedsYouView-CuB7daZ0.js +1 -0
- package/web/dist/assets/Overview-C6Ae0n9b.js +1 -0
- package/web/dist/assets/Pane-BXpuXst6.js +1 -0
- package/web/dist/assets/ProjectView-CpTcrvFa.js +1 -0
- package/web/dist/assets/ProposalView-BXisoFis.js +1 -0
- package/web/dist/assets/ProposalsView-BjPeXIxG.js +1 -0
- package/web/dist/assets/RunnersView-0ou0ekMc.js +1 -0
- package/web/dist/assets/SocietyView-C8lU_XY4.js +1 -0
- package/web/dist/assets/SubjectThread-BWbOV_wk.js +1 -0
- package/web/dist/assets/TaskView-CDLRRfS6.js +1 -0
- package/web/dist/assets/TasksView-p6PdvdWY.js +1 -0
- package/web/dist/assets/ThreadCard-BisvLnYg.js +1 -0
- package/web/dist/assets/ThreadForms-DZ1yLsjU.js +1 -0
- package/web/dist/assets/ThreadView-CQUPQ5oR.js +1 -0
- package/web/dist/assets/{citizen-BXVebeiP.js → citizen-BwK8Ciw3.js} +1 -1
- package/web/dist/assets/format-DZLzLk7S.js +55 -0
- package/web/dist/assets/index-CbJnPhSw.js +21 -0
- package/web/dist/assets/index-DJ30ENcc.css +2 -0
- package/web/dist/assets/{tasks-rltmWd5a.js → tasks-DZgkXWwu.js} +1 -1
- package/web/dist/assets/{useStickyScroll-DDS3s21P.js → useStickyScroll-CVTdIoKj.js} +1 -1
- package/web/dist/index.html +4 -4
- package/web/dist/assets/ChannelView-B8BZLsf1.js +0 -1
- package/web/dist/assets/CitizenView-GomLDcrr.js +0 -2
- package/web/dist/assets/CitizensView-yNv8WtND.js +0 -1
- package/web/dist/assets/KnowledgeView--jxofSSN.js +0 -1
- package/web/dist/assets/Markdown-BpYzeV5r.js +0 -28
- package/web/dist/assets/MessageItem-BGPpqgpq.js +0 -1
- package/web/dist/assets/MetricsView-CcqLr6S1.js +0 -1
- package/web/dist/assets/NeedsYouView-r7gJGgVG.js +0 -1
- package/web/dist/assets/Overview-Cmz4_gfI.js +0 -1
- package/web/dist/assets/Pane-DRpHmeJ9.js +0 -1
- package/web/dist/assets/ProjectView-CuACZj4L.js +0 -1
- package/web/dist/assets/ProposalView-BiVcNEDL.js +0 -1
- package/web/dist/assets/ProposalsView-BIdkOfZO.js +0 -1
- package/web/dist/assets/SocietyView-Dya97szC.js +0 -1
- package/web/dist/assets/SubjectThread-2j_msY38.js +0 -1
- package/web/dist/assets/TaskView-CcJr7xnH.js +0 -1
- package/web/dist/assets/TasksView-BUvHntvK.js +0 -1
- package/web/dist/assets/ThreadCard-tzMGvn9j.js +0 -1
- package/web/dist/assets/ThreadForms-DE2yJEhz.js +0 -1
- package/web/dist/assets/ThreadView-FsNOTyVC.js +0 -1
- package/web/dist/assets/format-Ca2VAvEx.js +0 -77
- package/web/dist/assets/index-CtuchAFa.css +0 -2
- package/web/dist/assets/index-D4GJkeKU.js +0 -237
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kr4t0n
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -22,10 +22,11 @@ export STELLARIS_DATA_DIR=~/stellaris-data
|
|
|
22
22
|
stellaris init --name my-society # prints your user token once
|
|
23
23
|
stellaris agent add desk --role concierge --cli claude # the front desk, which routes what you ask
|
|
24
24
|
stellaris agent add stew --role steward --cli claude # the steward, which reads the society's signals
|
|
25
|
-
stellaris runner add laptop # prints the runner's token once
|
|
26
25
|
stellaris-server # http://127.0.0.1:4700
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
Open the server's address and enter the user token. Then start a runner
|
|
28
|
+
Open the server's address and enter the user token. Then start a runner on any machine that reaches the server; it prints a code to approve on the board, under runners.
|
|
29
|
+
|
|
30
|
+
To sign in with GitHub instead, create a GitHub OAuth app whose callback URL is the server's address followed by `/auth/github/callback`, and start the server with `STELLARIS_GITHUB_CLIENT_ID`, `STELLARIS_GITHUB_CLIENT_SECRET`, and `STELLARIS_GITHUB_USERS`, the logins allowed in. A lost user token is replaced with `stellaris user token --rotate`, which a running server takes after a restart.
|
|
30
31
|
|
|
31
32
|
The CLI writes the data directory directly, so run its setup commands before the server starts; once it runs, act as the user through the interface or the HTTP API. `STELLARIS_HOST` and `STELLARIS_PORT` set where the server listens (`127.0.0.1:4700`); every setting is a `STELLARIS_*` variable, listed in the [repository's README](https://github.com/kr4t0n/stellaris#environment-variables). The server is also published as a Docker image, `kr4t0n/stellaris-server`, and a Helm chart.
|
package/dist/cli/index.js
CHANGED
|
@@ -670,6 +670,9 @@ var BOARD_EVENT_TYPES = [
|
|
|
670
670
|
"knowledge.written",
|
|
671
671
|
"skill.promoted",
|
|
672
672
|
"runner.added",
|
|
673
|
+
"user.signed_in",
|
|
674
|
+
"user.signed_out",
|
|
675
|
+
"user.token_rotated",
|
|
673
676
|
"runner.changed",
|
|
674
677
|
"ops.signal",
|
|
675
678
|
"paused.changed",
|
|
@@ -771,6 +774,36 @@ var RunnerHelloSchema = z6.object({
|
|
|
771
774
|
turns: z6.array(UlidSchema).default([])
|
|
772
775
|
});
|
|
773
776
|
var RunnerWelcomeSchema = z6.object({ name: NameSchema, version: z6.string() });
|
|
777
|
+
var RunnerEnrollRequestSchema = z6.object({
|
|
778
|
+
protocol: z6.number().int().positive(),
|
|
779
|
+
version: z6.string().min(1).max(64),
|
|
780
|
+
hostname: z6.string().min(1).max(253),
|
|
781
|
+
os: RunnerOsSchema,
|
|
782
|
+
clis: z6.array(CliKindSchema).max(8),
|
|
783
|
+
capabilities: z6.array(z6.string().min(1).max(64)).max(32).default([])
|
|
784
|
+
});
|
|
785
|
+
var RunnerEnrollmentSchema = z6.object({
|
|
786
|
+
deviceCode: z6.string().min(1),
|
|
787
|
+
userCode: z6.string().min(1),
|
|
788
|
+
expiresAt: IsoDateTimeSchema,
|
|
789
|
+
intervalMs: z6.number().int().positive()
|
|
790
|
+
});
|
|
791
|
+
var RunnerEnrollPollSchema = z6.object({ deviceCode: z6.string().min(1) });
|
|
792
|
+
var RunnerEnrollStatusSchema = z6.discriminatedUnion("status", [
|
|
793
|
+
z6.object({ status: z6.literal("pending") }),
|
|
794
|
+
z6.object({ status: z6.literal("approved"), name: NameSchema, token: z6.string().min(1) }),
|
|
795
|
+
z6.object({ status: z6.literal("denied") })
|
|
796
|
+
]);
|
|
797
|
+
var PendingEnrollmentSchema = z6.object({
|
|
798
|
+
userCode: z6.string().min(1),
|
|
799
|
+
hostname: z6.string(),
|
|
800
|
+
os: RunnerOsSchema,
|
|
801
|
+
clis: z6.array(CliKindSchema),
|
|
802
|
+
capabilities: z6.array(z6.string()),
|
|
803
|
+
version: z6.string(),
|
|
804
|
+
requestedAt: IsoDateTimeSchema,
|
|
805
|
+
expiresAt: IsoDateTimeSchema
|
|
806
|
+
});
|
|
774
807
|
var ProjectRepoSchema = z6.object({
|
|
775
808
|
slug: NameSchema,
|
|
776
809
|
origin: z6.string().nullable(),
|
|
@@ -1077,6 +1110,12 @@ var MetricsSchema = z9.object({
|
|
|
1077
1110
|
// packages/shared/dist/config.js
|
|
1078
1111
|
import { z as z10 } from "zod";
|
|
1079
1112
|
var LogLevelSchema = z10.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
|
|
1113
|
+
var GithubSignInSchema = z10.object({
|
|
1114
|
+
clientId: z10.string().min(1),
|
|
1115
|
+
clientSecret: z10.string().min(1),
|
|
1116
|
+
/** Logins, lowercased; GitHub logins are case-insensitive. */
|
|
1117
|
+
users: z10.array(z10.string().min(1)).min(1)
|
|
1118
|
+
});
|
|
1080
1119
|
var ServerConfigSchema = z10.object({
|
|
1081
1120
|
dataDir: z10.string().min(1),
|
|
1082
1121
|
host: z10.string().min(1),
|
|
@@ -1094,13 +1133,23 @@ var ServerConfigSchema = z10.object({
|
|
|
1094
1133
|
/** Rounds of tool calls one Claude turn may take, or null for no limit. */
|
|
1095
1134
|
toolRounds: z10.number().int().positive().nullable(),
|
|
1096
1135
|
/** How long a resident session stays warm after its last turn. */
|
|
1097
|
-
residentIdleMs: z10.number().int().positive()
|
|
1136
|
+
residentIdleMs: z10.number().int().positive(),
|
|
1137
|
+
/** Signing in to the board with GitHub, or null when only a token lets anyone in. */
|
|
1138
|
+
github: GithubSignInSchema.nullable(),
|
|
1139
|
+
/**
|
|
1140
|
+
* Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
|
|
1141
|
+
* rate limits on what anyone may ask without a token: 0 when clients connect directly.
|
|
1142
|
+
*/
|
|
1143
|
+
trustedProxies: z10.number().int().min(0).max(16)
|
|
1098
1144
|
});
|
|
1099
1145
|
var RunnerConfigSchema = z10.object({
|
|
1100
1146
|
/** The board server, for example http://127.0.0.1:4700. */
|
|
1101
1147
|
serverUrl: z10.string().url(),
|
|
1102
|
-
/**
|
|
1103
|
-
|
|
1148
|
+
/**
|
|
1149
|
+
* The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
|
|
1150
|
+
* to enroll it.
|
|
1151
|
+
*/
|
|
1152
|
+
token: z10.string().min(1).nullable(),
|
|
1104
1153
|
/** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
|
|
1105
1154
|
dataDir: z10.string().min(1),
|
|
1106
1155
|
logLevel: LogLevelSchema,
|
|
@@ -1111,7 +1160,7 @@ var RunnerConfigSchema = z10.object({
|
|
|
1111
1160
|
});
|
|
1112
1161
|
|
|
1113
1162
|
// packages/shared/dist/version.js
|
|
1114
|
-
var STELLARIS_VERSION = "0.
|
|
1163
|
+
var STELLARIS_VERSION = "0.2.0";
|
|
1115
1164
|
|
|
1116
1165
|
// packages/board-core/dist/errors.js
|
|
1117
1166
|
var BoardError = class extends Error {
|
|
@@ -2141,6 +2190,14 @@ var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".cod
|
|
|
2141
2190
|
var RunnerTokensSchema = z12.object({
|
|
2142
2191
|
runners: z12.record(z12.string(), z12.object({ tokenHash: z12.string().min(1) }))
|
|
2143
2192
|
});
|
|
2193
|
+
var SignInsSchema = z12.object({
|
|
2194
|
+
signIns: z12.array(z12.object({
|
|
2195
|
+
tokenHash: z12.string().min(1),
|
|
2196
|
+
login: z12.string().min(1),
|
|
2197
|
+
createdAt: IsoDateTimeSchema,
|
|
2198
|
+
expiresAt: IsoDateTimeSchema
|
|
2199
|
+
})).default([])
|
|
2200
|
+
});
|
|
2144
2201
|
var TurnHistoryPayloadSchema = z12.object({
|
|
2145
2202
|
project: NameSchema,
|
|
2146
2203
|
thread: UlidSchema.optional(),
|
|
@@ -2346,6 +2403,8 @@ var Board = class _Board {
|
|
|
2346
2403
|
turnTokens = /* @__PURE__ */ new Map();
|
|
2347
2404
|
/** Runner token hashes to runner names. */
|
|
2348
2405
|
runnerTokens = /* @__PURE__ */ new Map();
|
|
2406
|
+
/** Sign-ins by token hash, each acting as the user until it expires. */
|
|
2407
|
+
signIns = /* @__PURE__ */ new Map();
|
|
2349
2408
|
files = new FileTree();
|
|
2350
2409
|
homes;
|
|
2351
2410
|
constructor(dataDir, options) {
|
|
@@ -2374,6 +2433,7 @@ var Board = class _Board {
|
|
|
2374
2433
|
await board.mutex.run(() => board.applyAlignments());
|
|
2375
2434
|
await board.loadTokenIndex();
|
|
2376
2435
|
await board.loadRunnerTokens();
|
|
2436
|
+
await board.loadSignIns();
|
|
2377
2437
|
await board.homes.installHooks();
|
|
2378
2438
|
return board;
|
|
2379
2439
|
}
|
|
@@ -2621,7 +2681,7 @@ var Board = class _Board {
|
|
|
2621
2681
|
}
|
|
2622
2682
|
}
|
|
2623
2683
|
}
|
|
2624
|
-
await this.updateAgent(USER_NAME, (
|
|
2684
|
+
await this.updateAgent(USER_NAME, (user2) => ({ ...user2, subscriptions: [] }));
|
|
2625
2685
|
await this.refreshMember(USER_NAME);
|
|
2626
2686
|
}
|
|
2627
2687
|
/** Writes every missing seed charter and aligns the existing ones with their seed. */
|
|
@@ -2696,6 +2756,14 @@ ${charter.purpose}
|
|
|
2696
2756
|
if (persistent !== void 0) {
|
|
2697
2757
|
return persistent;
|
|
2698
2758
|
}
|
|
2759
|
+
const signIn = this.signIns.get(hash);
|
|
2760
|
+
if (signIn !== void 0) {
|
|
2761
|
+
if (signIn.expiresAt > this.now().getTime()) {
|
|
2762
|
+
return this.userActor();
|
|
2763
|
+
}
|
|
2764
|
+
this.signIns.delete(hash);
|
|
2765
|
+
return null;
|
|
2766
|
+
}
|
|
2699
2767
|
const temporary = this.turnTokens.get(hash);
|
|
2700
2768
|
if (temporary === void 0) {
|
|
2701
2769
|
return null;
|
|
@@ -2740,6 +2808,77 @@ ${charter.purpose}
|
|
|
2740
2808
|
userActor() {
|
|
2741
2809
|
return { name: USER_NAME, role: USER_ROLE };
|
|
2742
2810
|
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Signs the user in, as `login` on the identity provider, for `ttlMs`, and returns the sign-in's
|
|
2813
|
+
* token, shown once. Only its hash is kept, in `state/sign-ins.json`, so a sign-in outlives a
|
|
2814
|
+
* restart; it acts as the user, like the user's own token, until it expires or is signed out.
|
|
2815
|
+
*/
|
|
2816
|
+
async signIn(login, ttlMs) {
|
|
2817
|
+
return this.mutex.run(async () => {
|
|
2818
|
+
const token = mintToken();
|
|
2819
|
+
const now = this.now().getTime();
|
|
2820
|
+
const record = {
|
|
2821
|
+
tokenHash: hashToken(token),
|
|
2822
|
+
login,
|
|
2823
|
+
createdAt: new Date(now).toISOString(),
|
|
2824
|
+
expiresAt: new Date(now + ttlMs).toISOString()
|
|
2825
|
+
};
|
|
2826
|
+
const live = (await this.readSignIns()).filter((each) => Date.parse(each.expiresAt) > now);
|
|
2827
|
+
await writeJson(this.signInsFile(), { signIns: [...live, record] });
|
|
2828
|
+
this.signIns.set(record.tokenHash, { login, expiresAt: Date.parse(record.expiresAt) });
|
|
2829
|
+
await this.events.append("user.signed_in", USER_NAME, { login });
|
|
2830
|
+
return token;
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
/** Ends the sign-in a token belongs to; false for a token that is no sign-in's. */
|
|
2834
|
+
async signOut(token) {
|
|
2835
|
+
const hash = hashToken(token);
|
|
2836
|
+
return this.mutex.run(async () => {
|
|
2837
|
+
const signIn = this.signIns.get(hash);
|
|
2838
|
+
if (signIn === void 0) {
|
|
2839
|
+
return false;
|
|
2840
|
+
}
|
|
2841
|
+
this.signIns.delete(hash);
|
|
2842
|
+
await writeJson(this.signInsFile(), {
|
|
2843
|
+
signIns: (await this.readSignIns()).filter((each) => each.tokenHash !== hash)
|
|
2844
|
+
});
|
|
2845
|
+
await this.events.append("user.signed_out", USER_NAME, { login: signIn.login });
|
|
2846
|
+
return true;
|
|
2847
|
+
});
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Issues the user a new token and revokes the old one, returning the new one, shown once: the way
|
|
2851
|
+
* back in when the token is lost. A server already running keeps the old token's hash in memory
|
|
2852
|
+
* until it restarts, since the admin CLI that calls this writes the data directory beside it.
|
|
2853
|
+
*/
|
|
2854
|
+
async rotateUserToken() {
|
|
2855
|
+
return this.mutex.run(async () => {
|
|
2856
|
+
const previous = await this.readAgent(USER_NAME);
|
|
2857
|
+
const token = mintToken();
|
|
2858
|
+
await this.updateAgent(USER_NAME, (agent2) => ({ ...agent2, tokenHash: hashToken(token) }));
|
|
2859
|
+
this.tokenIndex.delete(previous.tokenHash);
|
|
2860
|
+
this.tokenIndex.set(hashToken(token), this.userActor());
|
|
2861
|
+
await this.events.append("user.token_rotated", USER_NAME, {});
|
|
2862
|
+
return token;
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
signInsFile() {
|
|
2866
|
+
return path6.join(this.paths.state(), "sign-ins.json");
|
|
2867
|
+
}
|
|
2868
|
+
async readSignIns() {
|
|
2869
|
+
const file = this.signInsFile();
|
|
2870
|
+
return await exists(file) ? (await readJson(file, SignInsSchema)).signIns : [];
|
|
2871
|
+
}
|
|
2872
|
+
async loadSignIns() {
|
|
2873
|
+
this.signIns.clear();
|
|
2874
|
+
const now = this.now().getTime();
|
|
2875
|
+
for (const signIn of await this.readSignIns()) {
|
|
2876
|
+
const expiresAt = Date.parse(signIn.expiresAt);
|
|
2877
|
+
if (expiresAt > now) {
|
|
2878
|
+
this.signIns.set(signIn.tokenHash, { login: signIn.login, expiresAt });
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2743
2882
|
async actorFor(name) {
|
|
2744
2883
|
const agent2 = await this.readAgent(name);
|
|
2745
2884
|
return { name: agent2.name, role: agent2.role };
|
|
@@ -3074,9 +3213,9 @@ ${charter.purpose}
|
|
|
3074
3213
|
|
|
3075
3214
|
Agents may edit this file. It is rendered by the board UI.
|
|
3076
3215
|
`);
|
|
3077
|
-
await this.updateAgent(USER_NAME, (
|
|
3078
|
-
...
|
|
3079
|
-
memberships: [.../* @__PURE__ */ new Set([...
|
|
3216
|
+
await this.updateAgent(USER_NAME, (user2) => ({
|
|
3217
|
+
...user2,
|
|
3218
|
+
memberships: [.../* @__PURE__ */ new Set([...user2.memberships, project2.slug])]
|
|
3080
3219
|
}));
|
|
3081
3220
|
await this.refreshMember(USER_NAME);
|
|
3082
3221
|
await this.events.append("project.added", by, {
|
|
@@ -4736,8 +4875,9 @@ ${rationale}`}`);
|
|
|
4736
4875
|
/**
|
|
4737
4876
|
* Registers a runner and mints its token, returned once; only its hash is kept, outside the
|
|
4738
4877
|
* projection. The runner reports its operating system, CLIs, and capabilities when it connects.
|
|
4878
|
+
* An enrolled runner names the machine that asked, which the event records.
|
|
4739
4879
|
*/
|
|
4740
|
-
async addRunner(actor, name) {
|
|
4880
|
+
async addRunner(actor, name, enrolled) {
|
|
4741
4881
|
if (actor.role !== USER_ROLE) {
|
|
4742
4882
|
throw new BoardError("FORBIDDEN", "only the user adds runners");
|
|
4743
4883
|
}
|
|
@@ -4761,7 +4901,10 @@ ${rationale}`}`);
|
|
|
4761
4901
|
runners: { ...tokens, [parsed]: { tokenHash: hashToken(token) } }
|
|
4762
4902
|
});
|
|
4763
4903
|
this.runnerTokens.set(hashToken(token), parsed);
|
|
4764
|
-
await this.events.append("runner.added", actor.name, {
|
|
4904
|
+
await this.events.append("runner.added", actor.name, {
|
|
4905
|
+
name: parsed,
|
|
4906
|
+
...enrolled === void 0 ? {} : { enrolledFrom: enrolled.hostname }
|
|
4907
|
+
});
|
|
4765
4908
|
return { runner: runner2, token };
|
|
4766
4909
|
});
|
|
4767
4910
|
}
|
|
@@ -4958,7 +5101,7 @@ ${charter.purpose}
|
|
|
4958
5101
|
await writeJson(this.paths.pausedFile(), { paused: false });
|
|
4959
5102
|
const userToken = mintToken();
|
|
4960
5103
|
const userCharter = await this.readRole(USER_ROLE);
|
|
4961
|
-
const
|
|
5104
|
+
const user2 = AgentSchema.parse({
|
|
4962
5105
|
name: USER_NAME,
|
|
4963
5106
|
role: USER_ROLE,
|
|
4964
5107
|
cli: null,
|
|
@@ -4968,7 +5111,7 @@ ${charter.purpose}
|
|
|
4968
5111
|
createdAt,
|
|
4969
5112
|
tokenHash: hashToken(userToken)
|
|
4970
5113
|
});
|
|
4971
|
-
await this.writeAgentHome(
|
|
5114
|
+
await this.writeAgentHome(user2, userCharter);
|
|
4972
5115
|
await this.events.append("society.initialized", USER_NAME, { name: society.name });
|
|
4973
5116
|
return userToken;
|
|
4974
5117
|
}
|
|
@@ -5871,6 +6014,18 @@ program.command("init").description("Create a society in the data directory and
|
|
|
5871
6014
|
`User token (shown once): ${userToken}`
|
|
5872
6015
|
].join("\n"));
|
|
5873
6016
|
});
|
|
6017
|
+
var user = program.command("user").description("The user's own access");
|
|
6018
|
+
user.command("token").description("Issue the user a new token and print it once; the old one stops working").option("--rotate", "replace the token", false).action(async (opts) => {
|
|
6019
|
+
if (!opts.rotate) {
|
|
6020
|
+
throw new BoardError("VALIDATION", "the board keeps only a hash of the user token, so it cannot show it again; `user token --rotate` issues a new one");
|
|
6021
|
+
}
|
|
6022
|
+
const board = await open();
|
|
6023
|
+
const userToken = await board.rotateUserToken();
|
|
6024
|
+
print({ userToken }, () => [
|
|
6025
|
+
`User token (shown once): ${userToken}`,
|
|
6026
|
+
"A board server running on this data directory reads the new token only when it restarts."
|
|
6027
|
+
].join("\n"));
|
|
6028
|
+
});
|
|
5874
6029
|
var project = program.command("project").description("Manage projects");
|
|
5875
6030
|
project.command("add <slug>").description("Add a project with its default channels").option("--name <name>", "display name").option("--repo <url>", "git remote").option("--on-done <effect>", "what finishing a task does: none, or merge its branch").action(async (slug, opts) => {
|
|
5876
6031
|
const board = await open();
|