5 Commits
Author SHA1 Message Date
zeekay 8e8ff917b2 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-08-29 13:46:59 -07:00
zeekay 3156793826 fix(sdk): accept ZAP wire v2 (luxfi/zap v1.2.0) + drop-in gaps; engine: CAN-chain describe
The cloud embedded engine links luxfi/zap v1.2.0 via MVS, whose NewBuilder stamps
wire version 2; the TS SDK only accepted version 1 -> 'unsupported version 2'
against cloud's gated :9999. The generic object encoding is byte-identical across
v1/v2 (only the platformvm TxKind schema differs, which this SDK never uses) and
v1.2.0's Parse accepts v1, so: keep emitting v1 (both engines accept it), accept
BOTH 1 and 2 on read. Verified live against cloud v1.786.102.

Also (drop-in compat, from the social migration):
- export TokenProvider from the package root.
- proxyActivities<A>: open the generic so proxyActivities<SomeActivityClass>()
  type-checks; ProxyActivityOptions accepts cancellationType (no-op).
- engine.moreCurrentRun: a CONTINUED_AS_NEW run ranks below any other run of the
  same workflowId, so the completed tail of a continue-as-new chain resolves over
  its closed predecessor on a same-second StartTime (DescribeWorkflow by id).
2026-07-04 22:11:10 -07:00
zeekay 71b3c30d73 feat(sdk): IAM bearer auth over ZAP (auth_token) for the gated frontend
The gated engine (cloud ServeGated :9999) requires an auth_token on every
JSON-body RPC; the TS SDK had no way to send one. Add a TokenProvider that
rides client lifecycle + worker Subscribe as auth_token (mirrors the Go SDK's
Options.Token), injected at the ZAP transport for JSON bodies only — worker
Respond/Heartbeat field-object frames are HMAC-authenticated and untouched.

Threaded through Connection/TasksClient/Worker options. Proven: unit test
(auth_token rides JSON RPCs, absent without a source) + gated e2e vs a real
RequireIdentity tasksd with a local RS256 JWKS (anonymous -> 401; IAM-bearer
client+worker run a durable workflow to COMPLETED with org-scoped namespace).
2026-07-04 21:39:26 -07:00
zeekay a60626ae9e feat(engine): durable social primitives — signals, continueAsNew, startChild, search attrs, conflict policy
The social-orchestrator migration off upstream Temporal onto the embedded
Hanzo Tasks engine needs five workflow primitives its digest/sendEmail/post
workflows depend on. Implemented server-side (event-sourced, replay-safe) plus
the @hanzoai/tasks TS SDK (the worker social runs):

- Signal → running workflow: engine.signalWorkflow now re-dispatches a workflow
  task after appending WORKFLOW_EXECUTION_SIGNALED, so the stateless worker
  replays the extended history and fires the handler (digest/sendEmail are
  entirely signal-driven). TS decider read the wrong history attr key
  ("signal" vs "signalName") — fixed.
- continueAsNew (kind=4): closes the run CONTINUED_AS_NEW + starts a successor
  under the same workflowId carrying input/search-attrs/memo. TS continueAsNew
  emits the command instead of throwing ContinueAsNewNotSupported.
- startChild (kind=5): detached (ABANDON) child, seq-keyed + idempotent; retires
  the 0x006D 501 for the command path. TS startChild/executeChild added.
- Typed search attributes: carried on StartWorkflow/SignalWithStart wire, stored
  on the execution, visibility-queryable (already read by fieldValue). TS adds
  TypedSearchAttributes/defineSearchAttributeKey/SearchAttributeType.
- workflowIdConflictPolicy USE_EXISTING/TERMINATE_EXISTING/FAIL.
- ActivityFailure wraps ApplicationFailure (with .type) so workflow error
  matching (err.cause.type === 'refresh_token') works.

Also fixes a pre-existing wire defect: the server registered
SignalWithStartWorkflow at 0x0069 while every client sends 0x0066 (schema +
Go/TS SDK) — signalWithStart 404'd against the real engine. Swapped with the
HTTP-only GetWorkflowHistory (no ZAP client).

DescribeWorkflow(workflowId, "") now resolves the OPEN run (Temporal's current
execution) so a continueAsNew successor is the one signalled/described.

Tests: engine unit (search attrs, conflict policy, continueAsNew, startChild)
+ TS e2e vs real tasksd (signals-across-continueAsNew, startChild, search attrs
run to COMPLETED). go test -race ./pkg/... green; TS vitest green.
2026-07-04 21:30:09 -07:00
25f19a5a30 feat(sdk): TypeScript SDK (@hanzoai/tasks) — durable execution over ZAP (#7)
Native TS client + worker over the Hanzo Tasks ZAP wire, byte-compatible with pkg/sdk (Go) and luxfi/zap v0.2.0. Drop-in for @temporalio/* + nestjs-temporal-core so the social-orchestrator migration is a dependency swap.

Includes: byte-exact ZAP message codec + TCP node (handshake, reqID correlation, Send-push dispatch); full client (start/signal/signalWithStart/query/describe/cancel/terminate/list, namespaces, health); activity worker (subscribe/dispatch/heartbeat/respond); event-sourced workflow replay decider (proxyActivities, durable activity-backed timers, condition, defineSignal/setHandler); temporal failure envelope serde; @temporalio compat (Connection/Client/NativeConnection/Worker/ApplicationFailure).

Tests: 25 vitest specs green (byte-layout golden, decider unit, full durable loop through a faithful ZAP mock) + a live integration suite that passes against a running tasksd. tsc --noEmit clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-04 13:39:01 -07:00