@schoolai/shipyard 1.0.0 → 1.1.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/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @schoolai/shipyard
2
+
3
+ Ship responsibly. Agent management hub for human-agent collaboration.
4
+
5
+ Shipyard is the collaboration workspace for mixed human-agent teams. Agents create tasks with proof. Humans review in real-time. Feedback flows both ways.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @schoolai/shipyard@latest
11
+ ```
12
+
13
+ Or run directly:
14
+
15
+ ```bash
16
+ npx @schoolai/shipyard --help
17
+ ```
18
+
19
+ ## Authentication
20
+
21
+ ```bash
22
+ shipyard login # Device flow auth (opens browser)
23
+ shipyard login --check # Check current auth status
24
+ shipyard logout # Clear stored credentials
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ # Run a task with a prompt
31
+ shipyard --prompt "Fix the bug in auth.ts"
32
+
33
+ # Resume an existing session
34
+ shipyard --resume <session-id> --task-id <id>
35
+
36
+ # Run in serve mode (signaling + agent spawning)
37
+ shipyard --serve
38
+
39
+ # Check version
40
+ shipyard --version
41
+ ```
42
+
43
+ ## CLI Options
44
+
45
+ | Option | Short | Description |
46
+ |--------|-------|-------------|
47
+ | `--prompt <text>` | `-p` | Prompt for the agent |
48
+ | `--task-id <id>` | `-t` | Task ID (auto-generated if omitted) |
49
+ | `--resume <id>` | `-r` | Resume session by session ID |
50
+ | `--data-dir <path>` | `-d` | Data directory (default: `~/.shipyard/data`) |
51
+ | `--cwd <path>` | | Working directory for agent |
52
+ | `--model <name>` | `-m` | Model to use |
53
+ | `--serve` | `-s` | Run in serve mode |
54
+ | `--version` | `-v` | Show version |
55
+ | `--help` | `-h` | Show help |
56
+
57
+ ## Environment Variables
58
+
59
+ | Variable | Default | Description |
60
+ |----------|---------|-------------|
61
+ | `ANTHROPIC_API_KEY` | | API key for Claude (optional, overrides OAuth) |
62
+ | `SHIPYARD_DEV` | | Set to `1` for dev mode |
63
+ | `SHIPYARD_DATA_DIR` | `~/.shipyard/data` | Data directory |
64
+ | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, `error` |
65
+ | `SHIPYARD_SIGNALING_URL` | (auto) | Signaling server WebSocket URL |
66
+
67
+ ## Documentation
68
+
69
+ - [Installation Guide](https://github.com/SchoolAI/shipyard/blob/main/docs/installation.md)
70
+ - [Architecture](https://github.com/SchoolAI/shipyard/blob/main/docs/architecture.md)
71
+ - [Development](https://github.com/SchoolAI/shipyard/blob/main/docs/development.md)
72
+
73
+ ## License
74
+
75
+ [FSL-1.1-ALv2](https://github.com/SchoolAI/shipyard/blob/main/LICENSE.md) (Functional Source License) - Free for all non-competing use, converts to Apache 2.0 in 2 years.
@@ -4122,7 +4122,13 @@ var AuthVerifyResponseSchema = external_exports.discriminatedUnion("valid", [
4122
4122
  reason: external_exports.enum(["invalid_token", "user_not_found"])
4123
4123
  })
4124
4124
  ]);
4125
- var CollaboratorRoleSchema = external_exports.enum([
4125
+ var ParticipantRoleSchema = external_exports.enum([
4126
+ "owner",
4127
+ "collaborator-full",
4128
+ "collaborator-review",
4129
+ "viewer"
4130
+ ]);
4131
+ var CollaboratorRoleSchema = ParticipantRoleSchema.extract([
4126
4132
  "collaborator-full",
4127
4133
  "collaborator-review",
4128
4134
  "viewer"
@@ -4130,8 +4136,8 @@ var CollaboratorRoleSchema = external_exports.enum([
4130
4136
  var CollabCreateRequestSchema = external_exports.object({
4131
4137
  /** ID of the task to collaborate on */
4132
4138
  taskId: external_exports.string().min(1, "taskId is required"),
4133
- /** How long the collaboration link should be valid (1-1440 minutes, default 60) */
4134
- expiresInMinutes: external_exports.number().min(1).max(1440).default(60),
4139
+ /** How long the collaboration link should be valid (1-10080 minutes / 7 days max, default 60) */
4140
+ expiresInMinutes: external_exports.number().min(1).max(10080).default(60),
4135
4141
  /** Permission level for the invitee (defaults to 'collaborator-full') */
4136
4142
  role: CollaboratorRoleSchema.optional()
4137
4143
  });
@@ -4274,6 +4280,15 @@ var NotifyTaskSchema = external_exports.object({
4274
4280
  machineId: external_exports.string(),
4275
4281
  taskId: external_exports.string()
4276
4282
  });
4283
+ var NotifyCollabRoomSchema = external_exports.object({
4284
+ type: external_exports.literal("notify-collab-room"),
4285
+ requestId: external_exports.string(),
4286
+ machineId: external_exports.string(),
4287
+ taskId: external_exports.string(),
4288
+ roomId: external_exports.string(),
4289
+ token: external_exports.string().min(1),
4290
+ expiresAt: external_exports.number().positive()
4291
+ });
4277
4292
  var TaskAckSchema = external_exports.object({
4278
4293
  type: external_exports.literal("task-ack"),
4279
4294
  requestId: external_exports.string(),
@@ -4362,6 +4377,7 @@ var PersonalRoomClientMessageSchema = external_exports.discriminatedUnion("type"
4362
4377
  WebRTCAnswerSchema,
4363
4378
  WebRTCIceSchema,
4364
4379
  NotifyTaskSchema,
4380
+ NotifyCollabRoomSchema,
4365
4381
  TaskAckSchema,
4366
4382
  CancelTaskSchema,
4367
4383
  ControlAckSchema,
@@ -4412,6 +4428,7 @@ var PersonalRoomServerMessageSchema = external_exports.discriminatedUnion("type"
4412
4428
  AgentLeftSchema,
4413
4429
  AgentStatusChangedSchema,
4414
4430
  NotifyTaskSchema,
4431
+ NotifyCollabRoomSchema,
4415
4432
  TaskAckSchema,
4416
4433
  CancelTaskSchema,
4417
4434
  ControlAckSchema,
@@ -4451,7 +4468,7 @@ var ParticipantSchema = external_exports.object({
4451
4468
  userId: external_exports.string(),
4452
4469
  username: external_exports.string(),
4453
4470
  avatarUrl: external_exports.string().nullable().optional(),
4454
- role: external_exports.enum(["owner", "collaborator-full", "collaborator-review", "viewer"])
4471
+ role: ParticipantRoleSchema
4455
4472
  });
4456
4473
  var CollabAuthenticatedSchema = external_exports.object({
4457
4474
  type: external_exports.literal("authenticated"),
@@ -4499,6 +4516,164 @@ var DevicePollPendingSchema = external_exports.object({
4499
4516
  error: external_exports.enum(["authorization_pending", "slow_down", "expired_token"])
4500
4517
  });
4501
4518
 
4519
+ // ../../packages/session/src/collab-room-connection.ts
4520
+ var CollabRoomConnection = class {
4521
+ state = "disconnected";
4522
+ ws = null;
4523
+ messageHandlers = /* @__PURE__ */ new Set();
4524
+ stateChangeHandlers = /* @__PURE__ */ new Set();
4525
+ config;
4526
+ retryCount = 0;
4527
+ retryTimer = null;
4528
+ intentionalDisconnect = false;
4529
+ constructor(config) {
4530
+ this.config = config;
4531
+ }
4532
+ getState() {
4533
+ return this.state;
4534
+ }
4535
+ connect() {
4536
+ this.intentionalDisconnect = false;
4537
+ if (this.retryTimer !== null) {
4538
+ clearTimeout(this.retryTimer);
4539
+ this.retryTimer = null;
4540
+ }
4541
+ if (this.ws) {
4542
+ this.ws.onopen = null;
4543
+ this.ws.onclose = null;
4544
+ this.ws.onerror = null;
4545
+ this.ws.onmessage = null;
4546
+ this.ws.close();
4547
+ this.ws = null;
4548
+ }
4549
+ const Impl = this.config.WebSocketImpl ?? WebSocket;
4550
+ try {
4551
+ this.ws = new Impl(this.config.url);
4552
+ } catch {
4553
+ this.setState("error");
4554
+ this.reconnectWithBackoff();
4555
+ return;
4556
+ }
4557
+ this.setState("connecting");
4558
+ this.ws.onopen = () => {
4559
+ this.setState("connected");
4560
+ };
4561
+ this.ws.onclose = (ev) => {
4562
+ if (this.state !== "error" && this.state !== "reconnecting") {
4563
+ this.setState("disconnected");
4564
+ }
4565
+ if (!this.intentionalDisconnect && extractCloseCode(ev) !== 4001) {
4566
+ this.reconnectWithBackoff();
4567
+ }
4568
+ };
4569
+ this.ws.onerror = () => {
4570
+ this.setState("error");
4571
+ if (!this.intentionalDisconnect) {
4572
+ this.reconnectWithBackoff();
4573
+ }
4574
+ };
4575
+ this.ws.onmessage = (event) => {
4576
+ let raw;
4577
+ try {
4578
+ raw = JSON.parse(event.data);
4579
+ } catch {
4580
+ return;
4581
+ }
4582
+ const result = CollabRoomServerMessageSchema.safeParse(raw);
4583
+ if (!result.success) {
4584
+ console.warn(
4585
+ "[CollabRoom] Dropped unrecognized server message:",
4586
+ JSON.stringify(raw),
4587
+ result.error.issues
4588
+ );
4589
+ return;
4590
+ }
4591
+ for (const handler of [...this.messageHandlers]) {
4592
+ handler(result.data);
4593
+ }
4594
+ };
4595
+ }
4596
+ send(msg) {
4597
+ try {
4598
+ this.ws?.send(JSON.stringify(msg));
4599
+ } catch {
4600
+ }
4601
+ }
4602
+ onMessage(handler) {
4603
+ this.messageHandlers.add(handler);
4604
+ return () => {
4605
+ this.messageHandlers.delete(handler);
4606
+ };
4607
+ }
4608
+ onStateChange(handler) {
4609
+ this.stateChangeHandlers.add(handler);
4610
+ return () => {
4611
+ this.stateChangeHandlers.delete(handler);
4612
+ };
4613
+ }
4614
+ reconnect() {
4615
+ this.intentionalDisconnect = false;
4616
+ if (this.retryTimer !== null) {
4617
+ clearTimeout(this.retryTimer);
4618
+ this.retryTimer = null;
4619
+ }
4620
+ this.retryCount = 0;
4621
+ this.connect();
4622
+ }
4623
+ disconnect() {
4624
+ this.intentionalDisconnect = true;
4625
+ if (this.retryTimer !== null) {
4626
+ clearTimeout(this.retryTimer);
4627
+ this.retryTimer = null;
4628
+ }
4629
+ this.retryCount = 0;
4630
+ if (this.ws) {
4631
+ this.ws.onopen = null;
4632
+ this.ws.onclose = null;
4633
+ this.ws.onerror = null;
4634
+ this.ws.onmessage = null;
4635
+ this.ws.close();
4636
+ this.ws = null;
4637
+ }
4638
+ this.setState("disconnected");
4639
+ }
4640
+ reconnectWithBackoff() {
4641
+ if (this.retryTimer !== null) return;
4642
+ const maxRetries = this.config.maxRetries;
4643
+ if (maxRetries === void 0 || maxRetries === 0) {
4644
+ return;
4645
+ }
4646
+ if (maxRetries !== -1 && this.retryCount >= maxRetries) {
4647
+ return;
4648
+ }
4649
+ this.setState("reconnecting");
4650
+ if (this.intentionalDisconnect) return;
4651
+ const initialDelay = this.config.initialDelayMs ?? 1e3;
4652
+ const maxDelay = this.config.maxDelayMs ?? 3e4;
4653
+ const multiplier = this.config.backoffMultiplier ?? 2;
4654
+ const delay = Math.min(initialDelay * multiplier ** this.retryCount, maxDelay);
4655
+ this.retryCount++;
4656
+ this.retryTimer = setTimeout(() => {
4657
+ this.retryTimer = null;
4658
+ this.connect();
4659
+ }, delay);
4660
+ }
4661
+ setState(newState) {
4662
+ this.state = newState;
4663
+ if (newState === "connected") {
4664
+ this.retryCount = 0;
4665
+ }
4666
+ for (const handler of [...this.stateChangeHandlers]) {
4667
+ handler(newState);
4668
+ }
4669
+ }
4670
+ };
4671
+ function extractCloseCode(ev) {
4672
+ if (typeof ev !== "object" || ev === null || !("code" in ev)) return void 0;
4673
+ const code = ev.code;
4674
+ return typeof code === "number" ? code : void 0;
4675
+ }
4676
+
4502
4677
  // ../../packages/session/src/personal-room-connection.ts
4503
4678
  var PersonalRoomConnection = class {
4504
4679
  state = "disconnected";
@@ -4564,6 +4739,11 @@ var PersonalRoomConnection = class {
4564
4739
  }
4565
4740
  const result = PersonalRoomServerMessageSchema.safeParse(raw);
4566
4741
  if (!result.success) {
4742
+ console.warn(
4743
+ "[PersonalRoom] Dropped unrecognized server message:",
4744
+ JSON.stringify(raw),
4745
+ result.error.issues
4746
+ );
4567
4747
  return;
4568
4748
  }
4569
4749
  for (const handler of [...this.messageHandlers]) {
@@ -4589,6 +4769,15 @@ var PersonalRoomConnection = class {
4589
4769
  this.stateChangeHandlers.delete(handler);
4590
4770
  };
4591
4771
  }
4772
+ reconnect() {
4773
+ this.intentionalDisconnect = false;
4774
+ if (this.retryTimer !== null) {
4775
+ clearTimeout(this.retryTimer);
4776
+ this.retryTimer = null;
4777
+ }
4778
+ this.retryCount = 0;
4779
+ this.connect();
4780
+ }
4592
4781
  disconnect() {
4593
4782
  this.intentionalDisconnect = true;
4594
4783
  if (this.retryTimer !== null) {
@@ -4650,6 +4839,7 @@ export {
4650
4839
  CollabCreateRequestSchema,
4651
4840
  CollabCreateResponseSchema,
4652
4841
  PermissionModeSchema,
4842
+ CollabRoomConnection,
4653
4843
  PersonalRoomConnection
4654
4844
  };
4655
- //# sourceMappingURL=chunk-FNYWUFGS.js.map
4845
+ //# sourceMappingURL=chunk-4IVLSSKL.js.map