{"_id":"@1agents/wire","name":"@1agents/wire","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@1agents/wire","version":"0.1.0","description":"Shared message wire types and Zod schemas for Happy clients and services","author":{"name":"Kirill Dubovitskiy"},"license":"MIT","type":"module","homepage":"https://github.com/scottzx/1Agents_Server/tree/main/packages/happy-wire","bugs":{"url":"https://github.com/scottzx/1Agents_Server/issues"},"repository":{"type":"git","url":"git+https://github.com/scottzx/1Agents_Server.git"},"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.cts","exports":{".":{"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"},"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"}}},"scripts":{"typecheck":"tsc --noEmit","build":"shx rm -rf dist && tsc --noEmit && pkgroll","test":"$npm_execpath run build && vitest run","prepublishOnly":"$npm_execpath run build && $npm_execpath run test","release":"npx --no-install release-it"},"dependencies":{"@paralleldrive/cuid2":"^2.2.2","zod":"^4.0.0"},"devDependencies":{"@types/node":">=20","pkgroll":"^2.14.2","release-it":"^19.0.6","shx":"^0.3.3","typescript":"5.9.3","vitest":"^3.2.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"packageManager":"pnpm@10.11.0","_id":"@1agents/wire@0.1.0","gitHead":"858bffb37d319fb3a3fcf5a7b7840660d780db1f","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ZQI8iDc+Bzex8w3ZAHOIJpvccUP30pWnSxdpo5RjVuLHZERb0SjWYj288oJTUNoEAZR2K4Um9rxFRPB+7Zsnwg==","shasum":"40ddf6ce88df4f38e02d47bb588f2eb5dfa6e880","tarball":"https://registry.npmjs.org/@1agents/wire/-/wire-0.1.0.tgz","fileCount":7,"unpackedSize":104639,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICtjP8nLZVKJXMqUHNhSYD0XR9Jdft+GAQQUNtkP0YuRAiEAx1lcZ2bvckGHKhNgrXXcUlc5MRgbFL5YMjLXUhtE9WI="}]},"_npmUser":{"name":"scottzx","email":"xiaofengzeng93@outlook.com"},"directories":{},"maintainers":[{"name":"scottzx","email":"xiaofengzeng93@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wire_0.1.0_1781978729543_0.9439196566211832"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-20T18:05:29.448Z","0.1.0":"2026-06-20T18:05:29.690Z","modified":"2026-06-20T18:05:29.903Z"},"maintainers":[{"name":"scottzx","email":"xiaofengzeng93@outlook.com"}],"description":"Shared message wire types and Zod schemas for Happy clients and services","homepage":"https://github.com/scottzx/1Agents_Server/tree/main/packages/happy-wire","repository":{"type":"git","url":"git+https://github.com/scottzx/1Agents_Server.git"},"author":{"name":"Kirill Dubovitskiy"},"bugs":{"url":"https://github.com/scottzx/1Agents_Server/issues"},"license":"MIT","readme":"# @slopus/happy-wire\n\nCanonical wire specification package for Happy clients and services.\n\nThis package defines shared wire contracts as TypeScript types + Zod schemas. It is intentionally small and focused on protocol-level data only.\n\n## Quick Examples (Legacy vs New)\n\nBoth legacy and new formats are transported inside encrypted session messages.\n\nLegacy format examples (decrypted payload):\n\n```json\n{\n  \"role\": \"user\",\n  \"content\": {\n    \"type\": \"text\",\n    \"text\": \"fix the failing test\"\n  },\n  \"meta\": {\n    \"sentFrom\": \"mobile\"\n  }\n}\n```\n\n```json\n{\n  \"role\": \"agent\",\n  \"content\": {\n    \"type\": \"output\",\n    \"data\": {\n      \"type\": \"message\",\n      \"message\": \"I found the issue in api/session.ts\"\n    }\n  },\n  \"meta\": {\n    \"sentFrom\": \"cli\"\n  }\n}\n```\n\nNew session protocol format example (decrypted payload):\n\n```json\n{\n  \"role\": \"session\",\n  \"content\": {\n    \"id\": \"msg_01\",\n    \"time\": 1739347230000,\n    \"role\": \"agent\",\n    \"turn\": \"turn_01\",\n    \"ev\": {\n      \"t\": \"text\",\n      \"text\": \"I found the issue in api/session.ts\"\n    }\n  },\n  \"meta\": {\n    \"sentFrom\": \"cli\"\n  }\n}\n```\n\nModern session protocol user envelope (decrypted payload):\n\n```json\n{\n  \"role\": \"session\",\n  \"content\": {\n    \"id\": \"msg_legacy_user_01\",\n    \"time\": 1739347231000,\n    \"role\": \"user\",\n    \"ev\": {\n      \"t\": \"text\",\n      \"text\": \"fix the failing test\"\n    }\n  },\n  \"meta\": {\n    \"sentFrom\": \"cli\"\n  }\n}\n```\n\nProtocol invariant:\n- outer `role = \"session\"` marks modern session-protocol payloads.\n- inside `content`, envelope `role` is only `\"user\"` or `\"agent\"`.\n\nWire-level encrypted container (same for legacy and new):\n\n```json\n{\n  \"id\": \"msg-db-row-id\",\n  \"seq\": 101,\n  \"localId\": null,\n  \"content\": {\n    \"t\": \"encrypted\",\n    \"c\": \"BASE64_ENCRYPTED_PAYLOAD\"\n  },\n  \"createdAt\": 1739347230000,\n  \"updatedAt\": 1739347230000\n}\n```\n\n## Purpose\n\n`@slopus/happy-wire` centralizes definitions for:\n- encrypted message/update payloads\n- session protocol envelope and event stream\n- helper for creating valid session envelopes\n\nThe goal is to keep CLI/app/server/agent on the same wire contract and avoid schema drift.\n\n## Package Identity\n\n- Name: `@slopus/happy-wire`\n- Workspace path: `packages/happy-wire`\n- Entry: `src/index.ts`\n- Runtime deps: `zod`, `@paralleldrive/cuid2`\n\n## Public Exports\n\n`src/index.ts` exports everything from:\n- `src/messages.ts`\n- `src/legacyProtocol.ts`\n- `src/sessionProtocol.ts`\n\n### `messages.ts` exports\n\nSchemas + inferred types:\n- `SessionMessageContentSchema`\n- `SessionMessage`\n- `SessionMessageSchema`\n- `MessageMetaSchema`\n- `MessageMeta`\n- `SessionProtocolMessageSchema`\n- `SessionProtocolMessage`\n- `MessageContentSchema`\n- `MessageContent`\n- `VersionedEncryptedValueSchema`\n- `VersionedEncryptedValue`\n- `VersionedNullableEncryptedValueSchema`\n- `VersionedNullableEncryptedValue`\n- `UpdateNewMessageBodySchema`\n- `UpdateNewMessageBody`\n- `UpdateSessionBodySchema`\n- `UpdateSessionBody`\n- `VersionedMachineEncryptedValueSchema`\n- `VersionedMachineEncryptedValue`\n- `UpdateMachineBodySchema`\n- `UpdateMachineBody`\n- `CoreUpdateBodySchema`\n- `CoreUpdateBody`\n- `CoreUpdateContainerSchema`\n- `CoreUpdateContainer`\n\nCompatibility aliases:\n- `ApiMessageSchema` -> `SessionMessageSchema`\n- `ApiMessage` -> `SessionMessage`\n- `ApiUpdateNewMessageSchema` -> `UpdateNewMessageBodySchema`\n- `ApiUpdateNewMessage` -> `UpdateNewMessageBody`\n- `ApiUpdateSessionStateSchema` -> `UpdateSessionBodySchema`\n- `ApiUpdateSessionState` -> `UpdateSessionBody`\n- `ApiUpdateMachineStateSchema` -> `UpdateMachineBodySchema`\n- `ApiUpdateMachineState` -> `UpdateMachineBody`\n- `UpdateBodySchema` -> `UpdateNewMessageBodySchema`\n- `UpdateBody` -> `UpdateNewMessageBody`\n- `UpdateSchema` -> `CoreUpdateContainerSchema`\n- `Update` -> `CoreUpdateContainer`\n\n### `legacyProtocol.ts` exports\n\nSchemas + inferred types:\n- `UserMessageSchema`\n- `UserMessage`\n- `AgentMessageSchema`\n- `AgentMessage`\n- `LegacyMessageContentSchema`\n- `LegacyMessageContent`\n\n### `sessionProtocol.ts` exports\n\nSchemas + inferred types:\n- `sessionRoleSchema`\n- `SessionRole`\n- `sessionTextEventSchema`\n- `sessionServiceMessageEventSchema`\n- `sessionToolCallStartEventSchema`\n- `sessionToolCallEndEventSchema`\n- `sessionFileEventSchema`\n- `sessionTurnStartEventSchema`\n- `sessionStartEventSchema`\n- `sessionTurnEndStatusSchema`\n- `SessionTurnEndStatus`\n- `sessionTurnEndEventSchema`\n- `sessionStopEventSchema`\n- `sessionEventSchema`\n- `SessionEvent`\n- `sessionEnvelopeSchema`\n- `SessionEnvelope`\n- `CreateEnvelopeOptions`\n- `createEnvelope(...)`\n\n## Wire Type Specifications\n\n## Common Primitive Rules\n\nThese are schema-level requirements, not just recommendations.\n\n- `id`, `sid`, `machineId`, `call`, `name`, `title`, `description`, `ref`: `string`\n- `seq`, `createdAt`, `updatedAt`, `size`, `width`, `height`, `version`, `activeAt`: `number`\n- All nullable fields are explicitly marked with `.nullable()`.\n- All optional fields are explicitly marked with `.optional()`.\n- `.nullish()` means `undefined | null | <type>`.\n\n## Message/Update Specs (`messages.ts`)\n\n### `SessionMessageContentSchema`\n\n```ts\n{\n  t: 'encrypted';\n  c: string;\n}\n```\n\nMeaning:\n- `t` is a strict discriminator with value `'encrypted'`.\n- `c` is encrypted payload bytes encoded as a string (typically base64 in current usage).\n\n### `SessionMessageSchema`\n\n```ts\n{\n  id: string;\n  seq: number;\n  localId?: string | null;\n  content: SessionMessageContent;\n  createdAt: number;\n  updatedAt: number;\n}\n```\n\nNotes:\n- `localId` is `.nullish()` for compatibility with different producers.\n- `createdAt` and `updatedAt` are required in this shared schema.\n\n### `MessageMetaSchema`\n\n```ts\n{\n  sentFrom?: string;\n  permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'read-only' | 'safe-yolo' | 'yolo';\n  model?: string | null;\n  fallbackModel?: string | null;\n  customSystemPrompt?: string | null;\n  appendSystemPrompt?: string | null;\n  allowedTools?: string[] | null;\n  disallowedTools?: string[] | null;\n  displayText?: string;\n}\n```\n\n## Legacy Decrypted Payload Specs (`legacyProtocol.ts`)\n\n### `UserMessageSchema` (legacy decrypted payload)\n\n```ts\n{\n  role: 'user';\n  content: {\n    type: 'text';\n    text: string;\n  };\n  localKey?: string;\n  meta?: MessageMeta;\n}\n```\n\n### `AgentMessageSchema` (legacy decrypted payload)\n\n```ts\n{\n  role: 'agent';\n  content: {\n    type: string;\n    [key: string]: unknown;\n  };\n  meta?: MessageMeta;\n}\n```\n\n### `LegacyMessageContentSchema`\n\nDiscriminated union on `role`:\n- `'user'` -> `UserMessageSchema`\n- `'agent'` -> `AgentMessageSchema`\n\n## Top-Level Decrypted Payload Specs (`messages.ts`)\n\n### `SessionProtocolMessageSchema` (modern decrypted payload wrapper)\n\n```ts\n{\n  role: 'session';\n  content: SessionEnvelope;\n  meta?: MessageMeta;\n}\n```\n\n### `MessageContentSchema`\n\nDiscriminated union on top-level `role`:\n- `'user'` -> `UserMessageSchema` (legacy)\n- `'agent'` -> `AgentMessageSchema` (legacy)\n- `'session'` -> `SessionProtocolMessageSchema` (modern)\n\n## Message/Update Specs (`messages.ts`) Continued\n\n### `VersionedEncryptedValueSchema`\n\n```ts\n{\n  version: number;\n  value: string;\n}\n```\n\nUsed for encrypted, version-tracked blobs that cannot be null when present.\n\n### `VersionedNullableEncryptedValueSchema`\n\n```ts\n{\n  version: number;\n  value: string | null;\n}\n```\n\nUsed where payload presence can be intentionally reset to null while still versioning.\n\n### `VersionedMachineEncryptedValueSchema`\n\n```ts\n{\n  version: number;\n  value: string;\n}\n```\n\nMachine update variant. Equivalent shape to `VersionedEncryptedValueSchema`.\n\n### `UpdateNewMessageBodySchema`\n\n```ts\n{\n  t: 'new-message';\n  sid: string;\n  message: SessionMessage;\n}\n```\n\n### `UpdateSessionBodySchema`\n\n```ts\n{\n  t: 'update-session';\n  id: string;\n  metadata?: VersionedEncryptedValue | null;\n  agentState?: VersionedNullableEncryptedValue | null;\n}\n```\n\nImportant distinction:\n- `metadata.value` is `string` when metadata block exists.\n- `agentState.value` may be `string` or `null` when block exists.\n\n### `UpdateMachineBodySchema`\n\n```ts\n{\n  t: 'update-machine';\n  machineId: string;\n  metadata?: VersionedMachineEncryptedValue | null;\n  daemonState?: VersionedMachineEncryptedValue | null;\n  active?: boolean;\n  activeAt?: number;\n}\n```\n\n### `CoreUpdateBodySchema`\n\nDiscriminated union on `t` with exactly 3 variants:\n- `'new-message'`\n- `'update-session'`\n- `'update-machine'`\n\n### `CoreUpdateContainerSchema`\n\n```ts\n{\n  id: string;\n  seq: number;\n  body: CoreUpdateBody;\n  createdAt: number;\n}\n```\n\n## Session Protocol Specs (`sessionProtocol.ts`)\n\n## Role\n\n### `sessionRoleSchema`\n\n```ts\n'user' | 'agent'\n```\n\nRole meaning:\n- `'user'`: user-originated envelope.\n- `'agent'`: agent-originated envelope.\n\n## Event Variants\n\n`sessionEventSchema` is a discriminated union on `t` with 9 variants.\n\n### 1) Text event\n\n```ts\n{\n  t: 'text';\n  text: string;\n  thinking?: boolean;\n}\n```\n\n### 2) Service event\n\n```ts\n{\n  t: 'service';\n  text: string;\n}\n```\n\n### 3) Tool-call-start event\n\n```ts\n{\n  t: 'tool-call-start';\n  call: string;\n  name: string;\n  title: string;\n  description: string;\n  args: Record<string, unknown>;\n}\n```\n\n### 4) Tool-call-end event\n\n```ts\n{\n  t: 'tool-call-end';\n  call: string;\n}\n```\n\n### 5) File event\n\n```ts\n{\n  t: 'file';\n  ref: string;\n  name: string;\n  size: number;\n  image?: {\n    width: number;\n    height: number;\n    thumbhash: string;\n  };\n}\n```\n\n### 6) Turn-start event\n\n```ts\n{\n  t: 'turn-start';\n}\n```\n\n### 7) Start event\n\n```ts\n{\n  t: 'start';\n  title?: string;\n}\n```\n\n### 8) Turn-end event\n\n```ts\n{\n  t: 'turn-end';\n  status: 'completed' | 'failed' | 'cancelled';\n}\n```\n\n### 9) Stop event\n\n```ts\n{\n  t: 'stop';\n}\n```\n\n## Envelope\n\n### `sessionEnvelopeSchema`\n\n```ts\n{\n  id: string;\n  time: number;\n  role: 'user' | 'agent';\n  turn?: string;\n  subagent?: string; // must pass cuid2 validation when present\n  ev: SessionEvent;\n}\n```\n\nAdditional validation (`superRefine`):\n- If `ev.t === 'service'`, then `role` MUST be `'agent'`.\n- If `ev.t === 'start'` or `ev.t === 'stop'`, then `role` MUST be `'agent'`.\n- If `subagent` is present, it MUST satisfy `isCuid(...)`.\n\n## Helper Function Contract\n\n### `createEnvelope(role, ev, opts?)`\n\nInput:\n- `role: SessionRole`\n- `ev: SessionEvent`\n- `opts?: { id?: string; time?: number; turn?: string; subagent?: string }`\n\nBehavior:\n- If `opts.id` is absent, generates id using `createId()`.\n- If `opts.time` is absent, sets `time` to `Date.now()`.\n- Includes `turn` only when provided.\n- Includes `subagent` only when provided.\n\nOutput:\n- Returns a `SessionEnvelope` parsed by `sessionEnvelopeSchema`.\n- Throws on invalid combinations (for example `role = 'user'` with `ev.t = 'service'`).\n\n## Normative JSON Examples\n\n## Update container with `new-message`\n\n```json\n{\n  \"id\": \"upd-1\",\n  \"seq\": 100,\n  \"createdAt\": 1739347200000,\n  \"body\": {\n    \"t\": \"new-message\",\n    \"sid\": \"session-1\",\n    \"message\": {\n      \"id\": \"msg-1\",\n      \"seq\": 55,\n      \"localId\": null,\n      \"content\": {\n        \"t\": \"encrypted\",\n        \"c\": \"Zm9v\"\n      },\n      \"createdAt\": 1739347199000,\n      \"updatedAt\": 1739347199000\n    }\n  }\n}\n```\n\n### Decrypted `new-message` content example\n\n`message.content.c` (ciphertext) decrypts into the payload below for a session-protocol message:\n\n```json\n{\n  \"role\": \"session\",\n  \"content\": {\n    \"id\": \"env_01\",\n    \"time\": 1739347232000,\n    \"role\": \"agent\",\n    \"turn\": \"turn_01\",\n    \"ev\": {\n      \"t\": \"text\",\n      \"text\": \"I found 3 TODOs.\"\n    }\n  },\n  \"meta\": {\n    \"sentFrom\": \"cli\"\n  }\n}\n```\n\n## Update container with `update-session`\n\n```json\n{\n  \"id\": \"upd-2\",\n  \"seq\": 101,\n  \"createdAt\": 1739347210000,\n  \"body\": {\n    \"t\": \"update-session\",\n    \"id\": \"session-1\",\n    \"metadata\": {\n      \"version\": 8,\n      \"value\": \"BASE64...\"\n    },\n    \"agentState\": {\n      \"version\": 13,\n      \"value\": null\n    }\n  }\n}\n```\n\n## Update container with `update-machine`\n\n```json\n{\n  \"id\": \"upd-3\",\n  \"seq\": 102,\n  \"createdAt\": 1739347220000,\n  \"body\": {\n    \"t\": \"update-machine\",\n    \"machineId\": \"machine-1\",\n    \"metadata\": {\n      \"version\": 2,\n      \"value\": \"BASE64...\"\n    },\n    \"daemonState\": {\n      \"version\": 3,\n      \"value\": \"BASE64...\"\n    },\n    \"active\": true,\n    \"activeAt\": 1739347220000\n  }\n}\n```\n\n## Session protocol envelope\n\n```json\n{\n  \"id\": \"x8s1k2...\",\n  \"role\": \"agent\",\n  \"turn\": \"turn-42\",\n  \"ev\": {\n    \"t\": \"turn-start\"\n  }\n}\n```\n\n## Parsing/Validation Usage\n\n```ts\nimport {\n  CoreUpdateContainerSchema,\n  sessionEnvelopeSchema,\n} from '@slopus/happy-wire';\n\nconst maybeUpdate = CoreUpdateContainerSchema.safeParse(input);\nif (!maybeUpdate.success) {\n  // invalid update payload\n}\n\nconst maybeEnvelope = sessionEnvelopeSchema.safeParse(envelopeInput);\nif (!maybeEnvelope.success) {\n  // invalid envelope/event payload\n}\n```\n\n## Build and Distribution Specification\n\n`package.json` contract:\n- `main`: `./dist/index.cjs`\n- `module`: `./dist/index.mjs`\n- `types`: `./dist/index.d.cts`\n- `exports[\".\"]` provides both CJS and ESM entrypoints with type paths.\n\nBuild script:\n- `shx rm -rf dist && tsc --noEmit && pkgroll`\n\nTests:\n- `vitest` against `src/*.test.ts`\n\nPublish gate:\n- `prepublishOnly` runs build + test\n\nPublished files:\n- `dist`\n- `package.json`\n- `README.md`\n\n## Monorepo Build Dependency Behavior\n\nIn this repository, consumer workspaces import `@slopus/happy-wire` through package exports that point at `dist/*`.\n\nThat means on a clean checkout:\n1. Build wire first: `yarn workspace @slopus/happy-wire build`\n2. Then build/typecheck dependents.\n\nAfter publishing to npm, dependents consume prebuilt artifacts from the published tarball.\n\n## Change Policy\n\nWhen modifying wire schemas:\n- Prefer additive changes to keep older consumers compatible.\n- Treat discriminator values (`t`) as protocol-level API and avoid breaking renames.\n- Document semantic changes in this README.\n- Bump package version before downstream releases that depend on new schema behavior.\n\n## Development Commands\n\n```bash\n# from repository root\nyarn workspace @slopus/happy-wire build\nyarn workspace @slopus/happy-wire test\n```\n\n## Release Commands (maintainers)\n\n```bash\n# interactive release target selection from repo root\nyarn release\n\n# direct release invocation\nyarn workspace @slopus/happy-wire release\n```\n\nThis prepares release artifacts using the same `release-it` flow as other publishable libraries in the monorepo.\n","readmeFilename":"README.md","_rev":"1-b79d41ee9c424fed12e95ee90298af76"}