@ours.network/cowork 1.0.7 → 1.0.9-nightly.20260903.9d2f23e
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 +1 -1
- package/dist/cli.js +81 -7
- package/dist/daemon.js +320 -10
- package/dist/web/assets/app.js +8 -8
- package/docs/01-prerequisites.md +1 -1
- package/docs/02-installation.md +1 -1
- package/docs/09-service-management.md +3 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ The localhost HTTP console has no authentication. Keep it bound to `127.0.0.1`;
|
|
|
15
15
|
|
|
16
16
|
The same listener describes its own room management REST API: `http://127.0.0.1:3052/openapi.json` is the OpenAPI 3.1 document and `http://127.0.0.1:3052/docs` is the browser UI for it. Both are read-only, load no remote assets, and follow the console's loopback-only exposure rules.
|
|
17
17
|
|
|
18
|
-
Start or install the shared daemon with `@ours.network/cli` 2.
|
|
18
|
+
Start or install the shared daemon with `@ours.network/cli` 2.7.0 before starting cowork. Cowork never embeds, starts, stops, or silently substitutes an ours daemon. It uses the SDK-standard shared selection (the default `~/.ours` daemon, `OURS_CONFIG`, or a coherent `OURS_PORT` plus `OURS_STATE_DIR` selection) and fails clearly when that daemon is unavailable or mismatched.
|
|
19
19
|
|
|
20
20
|
The shared daemon retains application payload history outside its protocol packets: each identity has a `history.sqlite3` database and immutable content-addressed file blobs. Cowork authorizes unread metadata by authenticated CID, reads the corresponding persistent history or blob, durably archives the room item and its complete fan-out, and only then advances that exact SDK unread item. There is no packet-inbox fallback, defer queue, host outbox, or cross-store transaction.
|
|
21
21
|
|
package/dist/cli.js
CHANGED
|
@@ -4311,6 +4311,12 @@ var LowerCrockfordUlidSchema = external_exports.string().regex(
|
|
|
4311
4311
|
/^[0-7][0-9a-hjkmnp-tv-z]{25}$/,
|
|
4312
4312
|
"must be a 26-character lowercase Crockford ULID"
|
|
4313
4313
|
);
|
|
4314
|
+
var ContainerIdSchema = external_exports.string().regex(/^[0-9a-f]{64}$/i, "must be a 64-character hexadecimal CID").transform((value) => value.toUpperCase());
|
|
4315
|
+
var RuntimeCommandNameSchema = external_exports.enum(["list-members", "remove-member"]);
|
|
4316
|
+
var RuntimeCommandGrantSchema = external_exports.object({
|
|
4317
|
+
caller_cid: ContainerIdSchema,
|
|
4318
|
+
command: RuntimeCommandNameSchema
|
|
4319
|
+
}).strict();
|
|
4314
4320
|
function isStrictRfc3339(value) {
|
|
4315
4321
|
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-](\d{2}):(\d{2}))$/.exec(value);
|
|
4316
4322
|
if (!match) return false;
|
|
@@ -4626,6 +4632,8 @@ var CurrentRoomSchema = external_exports.object({
|
|
|
4626
4632
|
seen.add(role);
|
|
4627
4633
|
}
|
|
4628
4634
|
}),
|
|
4635
|
+
/** Operator-managed, default-deny grants for the room identity's runtime commands. */
|
|
4636
|
+
command_grants: external_exports.array(RuntimeCommandGrantSchema),
|
|
4629
4637
|
anonymous: external_exports.boolean(),
|
|
4630
4638
|
quiet_membership: external_exports.boolean(),
|
|
4631
4639
|
membership_epoch: external_exports.number().int().nonnegative().safe(),
|
|
@@ -4686,6 +4694,25 @@ var CurrentRoomSchema = external_exports.object({
|
|
|
4686
4694
|
});
|
|
4687
4695
|
}
|
|
4688
4696
|
}
|
|
4697
|
+
const seenCommandGrants = /* @__PURE__ */ new Set();
|
|
4698
|
+
for (const [index, grant] of room.command_grants.entries()) {
|
|
4699
|
+
const key = `${grant.caller_cid}\0${grant.command}`;
|
|
4700
|
+
if (seenCommandGrants.has(key)) {
|
|
4701
|
+
context.addIssue({
|
|
4702
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4703
|
+
path: ["command_grants", index],
|
|
4704
|
+
message: "runtime command grants must be unique by caller CID and command"
|
|
4705
|
+
});
|
|
4706
|
+
}
|
|
4707
|
+
seenCommandGrants.add(key);
|
|
4708
|
+
if (!room.seats.some((seat) => seat.state === "active" && seat.identity === grant.caller_cid)) {
|
|
4709
|
+
context.addIssue({
|
|
4710
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4711
|
+
path: ["command_grants", index, "caller_cid"],
|
|
4712
|
+
message: "runtime command grants require an active room identity"
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4689
4716
|
for (const [index, seat] of room.seats.entries()) {
|
|
4690
4717
|
if (seat.replaces_seat === void 0) continue;
|
|
4691
4718
|
const predecessor = byParticipant.get(seat.replaces_seat);
|
|
@@ -4726,6 +4753,7 @@ var RoomSchema = external_exports.preprocess((value) => {
|
|
|
4726
4753
|
}
|
|
4727
4754
|
}
|
|
4728
4755
|
if (!Object.hasOwn(value, "rest_roles")) patch.rest_roles = [];
|
|
4756
|
+
if (!Object.hasOwn(value, "command_grants")) patch.command_grants = [];
|
|
4729
4757
|
if (Object.keys(patch).length === 0) return value;
|
|
4730
4758
|
return { ...value, ...patch };
|
|
4731
4759
|
}, CurrentRoomSchema);
|
|
@@ -4760,7 +4788,6 @@ var PostAsRoleInputSchema = external_exports.object({
|
|
|
4760
4788
|
var RestRoleInputSchema = external_exports.object({
|
|
4761
4789
|
role: RoleSchema
|
|
4762
4790
|
}).strict();
|
|
4763
|
-
var ContainerIdSchema = external_exports.string().regex(/^[0-9a-f]{64}$/i, "must be a 64-character hexadecimal CID").transform((value) => value.toUpperCase());
|
|
4764
4791
|
var AcceptExternalInviteInputSchema = external_exports.object({
|
|
4765
4792
|
role: RoleSchema,
|
|
4766
4793
|
invite: external_exports.string().refine(
|
|
@@ -4770,6 +4797,24 @@ var AcceptExternalInviteInputSchema = external_exports.object({
|
|
|
4770
4797
|
expected_cid: ContainerIdSchema.optional(),
|
|
4771
4798
|
replaces_seat: LowerCrockfordUlidSchema.optional()
|
|
4772
4799
|
}).strict();
|
|
4800
|
+
var ListMembersCommandInputSchema = external_exports.object({}).strict();
|
|
4801
|
+
var CommandIdempotencyKeySchema = external_exports.string().regex(
|
|
4802
|
+
/^[A-Za-z0-9._:-]{1,128}$/,
|
|
4803
|
+
"must contain 1-128 portable idempotency-key characters"
|
|
4804
|
+
);
|
|
4805
|
+
var RemoveMemberCommandInputSchema = external_exports.object({
|
|
4806
|
+
participant_id: LowerCrockfordUlidSchema,
|
|
4807
|
+
expected_membership_epoch: external_exports.number().int().nonnegative().safe(),
|
|
4808
|
+
confirm: external_exports.literal(true),
|
|
4809
|
+
idempotency_key: CommandIdempotencyKeySchema
|
|
4810
|
+
}).strict();
|
|
4811
|
+
var RuntimeCommandAuditSchema = external_exports.object({
|
|
4812
|
+
sender_cid: NonEmptyStringSchema,
|
|
4813
|
+
sender_participant_id: LowerCrockfordUlidSchema,
|
|
4814
|
+
request_wire_id: NonEmptyStringSchema,
|
|
4815
|
+
idempotency_key: CommandIdempotencyKeySchema,
|
|
4816
|
+
expected_membership_epoch: external_exports.number().int().nonnegative().safe()
|
|
4817
|
+
}).strict();
|
|
4773
4818
|
var AuthorSnapshotSchema = external_exports.object({
|
|
4774
4819
|
identity: NonEmptyStringSchema,
|
|
4775
4820
|
display_name: NonEmptyStringSchema,
|
|
@@ -4880,7 +4925,8 @@ var MembershipIntentShape = {
|
|
|
4880
4925
|
role: RoleSchema,
|
|
4881
4926
|
alias: NonEmptyStringSchema.optional(),
|
|
4882
4927
|
epoch: PositiveSafeIntegerSchema,
|
|
4883
|
-
notify: external_exports.boolean()
|
|
4928
|
+
notify: external_exports.boolean(),
|
|
4929
|
+
command: RuntimeCommandAuditSchema.optional()
|
|
4884
4930
|
};
|
|
4885
4931
|
var MembershipResultShape = {
|
|
4886
4932
|
kind: external_exports.literal("membership_result"),
|
|
@@ -5057,7 +5103,9 @@ var NATIVE_MUTATION_METHODS = /* @__PURE__ */ new Set([
|
|
|
5057
5103
|
"room.recover.confirm",
|
|
5058
5104
|
"room.rebind",
|
|
5059
5105
|
"room.participant.remove",
|
|
5060
|
-
"room.participant.replace"
|
|
5106
|
+
"room.participant.replace",
|
|
5107
|
+
"room.command.grant",
|
|
5108
|
+
"room.command.revoke"
|
|
5061
5109
|
]);
|
|
5062
5110
|
function rpcTimeoutForMethod(method) {
|
|
5063
5111
|
return NATIVE_MUTATION_METHODS.has(method) ? NATIVE_RPC_TIMEOUT_MS : RPC_TIMEOUT_MS;
|
|
@@ -5101,6 +5149,9 @@ Room commands:
|
|
|
5101
5149
|
list
|
|
5102
5150
|
show <room-id>
|
|
5103
5151
|
participants <room-id>
|
|
5152
|
+
command-grants <room-id>
|
|
5153
|
+
command-grant <room-id> <caller-cid> <list-members|remove-member>
|
|
5154
|
+
command-revoke <room-id> <caller-cid> <list-members|remove-member>
|
|
5104
5155
|
history <room-id> [--after <seq>] [--limit <n>] [--view operator|participant]
|
|
5105
5156
|
message <room-id> --text <text>
|
|
5106
5157
|
say <room-id> --role <label> --text <text>
|
|
@@ -5296,6 +5347,25 @@ async function roomRequest(command, args) {
|
|
|
5296
5347
|
const [roomId] = exactPositionals(parseOptions(args), 1, `room ${command}`);
|
|
5297
5348
|
return { method: `room.${command}`, params: { room_id: roomId } };
|
|
5298
5349
|
}
|
|
5350
|
+
case "command-grants": {
|
|
5351
|
+
const [roomId] = exactPositionals(parseOptions(args), 1, "room command-grants");
|
|
5352
|
+
return { method: "room.command.grants", params: { room_id: roomId } };
|
|
5353
|
+
}
|
|
5354
|
+
case "command-grant":
|
|
5355
|
+
case "command-revoke": {
|
|
5356
|
+
const [roomId, callerCid, runtimeCommand] = exactPositionals(
|
|
5357
|
+
parseOptions(args),
|
|
5358
|
+
3,
|
|
5359
|
+
`room ${command}`
|
|
5360
|
+
);
|
|
5361
|
+
if (runtimeCommand !== "list-members" && runtimeCommand !== "remove-member") {
|
|
5362
|
+
usageError("runtime command must be list-members or remove-member");
|
|
5363
|
+
}
|
|
5364
|
+
return {
|
|
5365
|
+
method: command === "command-grant" ? "room.command.grant" : "room.command.revoke",
|
|
5366
|
+
params: { room_id: roomId, caller_cid: callerCid, command: runtimeCommand }
|
|
5367
|
+
};
|
|
5368
|
+
}
|
|
5299
5369
|
case "history": {
|
|
5300
5370
|
const parsed = parseOptions(args, ["--after", "--limit", "--view"]);
|
|
5301
5371
|
const [roomId] = exactPositionals(parsed, 1, "room history");
|
|
@@ -5719,7 +5789,11 @@ function serviceEnvironment(config) {
|
|
|
5719
5789
|
};
|
|
5720
5790
|
}
|
|
5721
5791
|
function validateServiceConfiguration(config) {
|
|
5722
|
-
const values = {
|
|
5792
|
+
const values = {
|
|
5793
|
+
node_executable: process.execPath,
|
|
5794
|
+
cowork_cli: SELF,
|
|
5795
|
+
...serviceEnvironment(config)
|
|
5796
|
+
};
|
|
5723
5797
|
for (const [label, value] of Object.entries(values)) {
|
|
5724
5798
|
if (/[\x00-\x1f\x7f-\x9f]/.test(value)) {
|
|
5725
5799
|
throw new CliError(EXIT.invalidState, "invalid_state", `${label} contains a control character unsafe for a service definition`);
|
|
@@ -5731,7 +5805,7 @@ function systemdValueQuote(value) {
|
|
|
5731
5805
|
}
|
|
5732
5806
|
function systemdExecutableQuote(value) {
|
|
5733
5807
|
if (value.includes('"') || /[\0\n\r]/.test(value)) {
|
|
5734
|
-
throw new CliError(EXIT.invalidState, "invalid_state", "
|
|
5808
|
+
throw new CliError(EXIT.invalidState, "invalid_state", "node_executable contains a character unsupported by systemd ExecStart");
|
|
5735
5809
|
}
|
|
5736
5810
|
return `"${value.replaceAll("\\", "\\\\").replaceAll("%", "%%")}"`;
|
|
5737
5811
|
}
|
|
@@ -5761,7 +5835,7 @@ StartLimitIntervalSec=0
|
|
|
5761
5835
|
|
|
5762
5836
|
[Service]
|
|
5763
5837
|
Type=simple
|
|
5764
|
-
ExecStart=${systemdExecutableQuote(SELF)} serve
|
|
5838
|
+
ExecStart=${systemdExecutableQuote(process.execPath)} ${systemdValueQuote(SELF)} serve
|
|
5765
5839
|
${environment}
|
|
5766
5840
|
Restart=on-failure
|
|
5767
5841
|
RestartSec=5
|
|
@@ -5798,7 +5872,7 @@ function installLaunchd(config) {
|
|
|
5798
5872
|
<plist version="1.0"><dict>
|
|
5799
5873
|
<key>Label</key><string>${LAUNCHD_LABEL}</string>
|
|
5800
5874
|
<key>ProgramArguments</key><array>
|
|
5801
|
-
<string>${xml(SELF)}</string><string>serve</string>
|
|
5875
|
+
<string>${xml(process.execPath)}</string><string>${xml(SELF)}</string><string>serve</string>
|
|
5802
5876
|
</array>
|
|
5803
5877
|
<key>EnvironmentVariables</key><dict>
|
|
5804
5878
|
${environment}
|