shennian 0.5.0 → 0.5.2
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 +2 -2
- package/dist/publish-build-manifest.json +165 -125
- package/dist/src/agents/acp/adapter.js +2 -2
- package/dist/src/agents/acp/capability-cache.js +2 -2
- package/dist/src/agents/acp/catalog.js +2 -2
- package/dist/src/agents/acp/manifests.js +2 -2
- package/dist/src/agents/claude.js +8 -6
- package/dist/src/agents/codex.js +2 -2
- package/dist/src/agents/command-spec.js +4 -4
- package/dist/src/agents/cursor.js +1 -1
- package/dist/src/agents/custom-recovery-conformance.js +2 -2
- package/dist/src/agents/gemini.js +1 -1
- package/dist/src/agents/model-registry/discovery.js +3 -3
- package/dist/src/agents/model-registry/service.js +1 -1
- package/dist/src/agents/model-registry.js +1 -1
- package/dist/src/agents/openclaw.js +2 -2
- package/dist/src/agents/opencode.js +1 -1
- package/dist/src/agents/pi-coding-agent.js +3 -4
- package/dist/src/agents/pi-session-ownership.js +2 -2
- package/dist/src/agents/spawn-errors.js +1 -0
- package/dist/src/agents/windows-agent-paths.js +1 -0
- package/dist/src/commands/agent-readiness.js +2 -2
- package/dist/src/commands/daemon-service-spec.js +1 -1
- package/dist/src/commands/daemon.js +6 -6
- package/dist/src/commands/queue.js +1 -0
- package/dist/src/commands/room.js +3 -3
- package/dist/src/config/index.js +2 -2
- package/dist/src/fs/atomic-rename.js +1 -0
- package/dist/src/index.js +3 -3
- package/dist/src/native-fusion/claude-entry-parser.js +7 -0
- package/dist/src/native-fusion/local-repository.js +2 -2
- package/dist/src/native-fusion/native-source-deletions.js +2 -2
- package/dist/src/native-fusion/parsers.js +1 -3
- package/dist/src/native-fusion/state.js +2 -2
- package/dist/src/personal-sync/epoch.js +2 -2
- package/dist/src/personal-sync/identity.js +2 -2
- package/dist/src/relay/client.js +1 -1
- package/dist/src/room/activation-service.js +6 -6
- package/dist/src/room/attachment-cache.js +2 -2
- package/dist/src/room/host-session-observations.js +2 -2
- package/dist/src/room/managed-context.js +1 -1
- package/dist/src/room/managed-room-ipc.js +2 -2
- package/dist/src/room/mirror-sync-service.js +1 -1
- package/dist/src/room/public-attachment-cache.js +2 -2
- package/dist/src/room/room-error-guidance.js +1 -0
- package/dist/src/room/session-registry.js +2 -2
- package/dist/src/security/managed-agent-policy.js +1 -1
- package/dist/src/security/managed-agent-runtime.js +1 -1
- package/dist/src/session/attachment-transfer-store.js +2 -2
- package/dist/src/session/canonical-store.js +5 -5
- package/dist/src/session/deletion-sync-state.js +2 -2
- package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
- package/dist/src/session/handlers/chat-adapter-config.js +1 -1
- package/dist/src/session/handlers/chat-events.js +2 -2
- package/dist/src/session/handlers/chat-recovery.js +1 -1
- package/dist/src/session/handlers/chat.js +1 -1
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/native-cleanup-outbox.js +2 -2
- package/dist/src/session/queue-diagnostics.js +1 -0
- package/dist/src/session/queue-dispatch-failure.js +1 -0
- package/dist/src/session/queue-helpers.js +5 -5
- package/dist/src/session/queue-retry.js +1 -1
- package/dist/src/session/queue-storage.js +2 -2
- package/dist/src/session/queue.js +1 -1
- package/dist/src/session/room-reply-notice.js +1 -0
- package/dist/src/session/run-recovery/journal.js +2 -2
- package/dist/src/session/run-stall.js +1 -0
- package/dist/src/session/store.js +2 -2
- package/dist/src/session/tool-detail-store.js +2 -2
- package/node_modules/@shennian/wire/dist/agent-capabilities.js +1 -1
- package/node_modules/@shennian/wire/dist/agent-workspace.js +1 -144
- package/node_modules/@shennian/wire/dist/envelope.js +1 -1
- package/node_modules/@shennian/wire/dist/events.js +1 -1
- package/node_modules/@shennian/wire/dist/external-message-format.js +3 -70
- package/node_modules/@shennian/wire/dist/frames.js +1 -1
- package/node_modules/@shennian/wire/dist/fs.js +2 -7
- package/node_modules/@shennian/wire/dist/index.js +1 -21
- package/node_modules/@shennian/wire/dist/machine.js +1 -1
- package/node_modules/@shennian/wire/dist/message-payload.js +8 -307
- package/node_modules/@shennian/wire/dist/methods.js +1 -3
- package/node_modules/@shennian/wire/dist/native-session.js +1 -1
- package/node_modules/@shennian/wire/dist/project-fs.js +1 -462
- package/node_modules/@shennian/wire/dist/project-path.js +1 -25
- package/node_modules/@shennian/wire/dist/project.js +1 -3
- package/node_modules/@shennian/wire/dist/relay-connectivity.js +1 -29
- package/node_modules/@shennian/wire/dist/room.js +1 -20
- package/node_modules/@shennian/wire/dist/schedule.js +1 -1
- package/node_modules/@shennian/wire/dist/session-sync.js +1 -123
- package/node_modules/@shennian/wire/dist/session.js +1 -60
- package/node_modules/@shennian/wire/dist/tool-detail.js +1 -9
- package/node_modules/@shennian/wire/dist/voice-chief.js +1 -3
- package/package.json +3 -8
- package/dist/bin/shennian.d.ts +0 -2
- package/dist/src/agent-env.d.ts +0 -44
- package/dist/src/agents/acp/adapter.d.ts +0 -82
- package/dist/src/agents/acp/auth-state.d.ts +0 -3
- package/dist/src/agents/acp/auth.d.ts +0 -7
- package/dist/src/agents/acp/capability-cache.d.ts +0 -14
- package/dist/src/agents/acp/catalog.d.ts +0 -11
- package/dist/src/agents/acp/client-services.d.ts +0 -37
- package/dist/src/agents/acp/discovery.d.ts +0 -10
- package/dist/src/agents/acp/events.d.ts +0 -4
- package/dist/src/agents/acp/manifests.d.ts +0 -63
- package/dist/src/agents/acp/metrics.d.ts +0 -24
- package/dist/src/agents/acp/package-commands.d.ts +0 -4
- package/dist/src/agents/acp/process-client.d.ts +0 -41
- package/dist/src/agents/acp/process-tree.d.ts +0 -2
- package/dist/src/agents/acp/types.d.ts +0 -31
- package/dist/src/agents/acp/watcher.d.ts +0 -22
- package/dist/src/agents/adapter.d.ts +0 -180
- package/dist/src/agents/auth-status.d.ts +0 -4
- package/dist/src/agents/claude-managed-permissions.d.ts +0 -33
- package/dist/src/agents/claude.d.ts +0 -69
- package/dist/src/agents/codex-managed-permissions.d.ts +0 -32
- package/dist/src/agents/codex-managed-room-tools.d.ts +0 -41
- package/dist/src/agents/codex-protocol.d.ts +0 -103
- package/dist/src/agents/codex-runtime.d.ts +0 -91
- package/dist/src/agents/codex-utils.d.ts +0 -29
- package/dist/src/agents/codex.d.ts +0 -59
- package/dist/src/agents/command-spec.d.ts +0 -55
- package/dist/src/agents/config-status.d.ts +0 -18
- package/dist/src/agents/cursor-managed-permissions.d.ts +0 -28
- package/dist/src/agents/cursor.d.ts +0 -44
- package/dist/src/agents/custom-managed-runtime.d.ts +0 -37
- package/dist/src/agents/custom-recovery-conformance.d.ts +0 -2
- package/dist/src/agents/custom.d.ts +0 -62
- package/dist/src/agents/detect.d.ts +0 -23
- package/dist/src/agents/event-terminal-gate.d.ts +0 -16
- package/dist/src/agents/external-channel-instructions.d.ts +0 -4
- package/dist/src/agents/gemini.d.ts +0 -32
- package/dist/src/agents/manager.d.ts +0 -57
- package/dist/src/agents/model-registry/cache.d.ts +0 -4
- package/dist/src/agents/model-registry/discovery.d.ts +0 -4
- package/dist/src/agents/model-registry/opencode-api.d.ts +0 -2
- package/dist/src/agents/model-registry/parsers.d.ts +0 -20
- package/dist/src/agents/model-registry/runner.d.ts +0 -6
- package/dist/src/agents/model-registry/service.d.ts +0 -10
- package/dist/src/agents/model-registry/types.d.ts +0 -39
- package/dist/src/agents/model-registry.d.ts +0 -17
- package/dist/src/agents/native-capabilities.d.ts +0 -10
- package/dist/src/agents/openclaw.d.ts +0 -29
- package/dist/src/agents/opencode-managed-permissions.d.ts +0 -25
- package/dist/src/agents/opencode.d.ts +0 -46
- package/dist/src/agents/pi-coding-agent-managed-permissions.d.ts +0 -7
- package/dist/src/agents/pi-coding-agent.d.ts +0 -63
- package/dist/src/agents/pi-managed-extension.d.ts +0 -12
- package/dist/src/agents/pi-managed-model-broker.d.ts +0 -27
- package/dist/src/agents/pi-managed-model-broker.js +0 -1
- package/dist/src/agents/pi-rpc-client.d.ts +0 -31
- package/dist/src/agents/pi-session-ownership.d.ts +0 -2
- package/dist/src/agents/platform-instructions.d.ts +0 -5
- package/dist/src/agents/runtime-compatibility.d.ts +0 -11
- package/dist/src/agents/workbuddy-managed-permissions.d.ts +0 -37
- package/dist/src/agents/workbuddy.d.ts +0 -63
- package/dist/src/commands/agent-readiness.d.ts +0 -17
- package/dist/src/commands/agent.d.ts +0 -2
- package/dist/src/commands/daemon-instance-lock.d.ts +0 -21
- package/dist/src/commands/daemon-process.d.ts +0 -6
- package/dist/src/commands/daemon-service-spec.d.ts +0 -26
- package/dist/src/commands/daemon-start-wait.d.ts +0 -9
- package/dist/src/commands/daemon-state.d.ts +0 -57
- package/dist/src/commands/daemon-windows.d.ts +0 -33
- package/dist/src/commands/daemon.d.ts +0 -67
- package/dist/src/commands/integration.d.ts +0 -3
- package/dist/src/commands/logout.d.ts +0 -3
- package/dist/src/commands/manager.d.ts +0 -2
- package/dist/src/commands/pair-authorization.d.ts +0 -3
- package/dist/src/commands/pair-browser.d.ts +0 -44
- package/dist/src/commands/pair-qr.d.ts +0 -4
- package/dist/src/commands/pair.d.ts +0 -19
- package/dist/src/commands/room.d.ts +0 -16
- package/dist/src/commands/runtime.d.ts +0 -2
- package/dist/src/commands/schedule.d.ts +0 -2
- package/dist/src/commands/tools.d.ts +0 -2
- package/dist/src/commands/upgrade.d.ts +0 -31
- package/dist/src/commands/worker.d.ts +0 -11
- package/dist/src/config/index.d.ts +0 -58
- package/dist/src/daemon-ipc/agent-readiness.d.ts +0 -15
- package/dist/src/daemon-ipc/client.d.ts +0 -8
- package/dist/src/daemon-ipc/control.d.ts +0 -16
- package/dist/src/daemon-ipc/json.d.ts +0 -3
- package/dist/src/daemon-ipc/paths.d.ts +0 -15
- package/dist/src/daemon-ipc/protocol.d.ts +0 -31
- package/dist/src/daemon-ipc/secret.d.ts +0 -3
- package/dist/src/daemon-ipc/server.d.ts +0 -20
- package/dist/src/daemon-log.d.ts +0 -9
- package/dist/src/env-path.d.ts +0 -15
- package/dist/src/fs/boundary.d.ts +0 -23
- package/dist/src/fs/handler.d.ts +0 -26
- package/dist/src/fs/security.d.ts +0 -2
- package/dist/src/fs/text-decoder.d.ts +0 -10
- package/dist/src/index.d.ts +0 -1
- package/dist/src/log-redaction.d.ts +0 -4
- package/dist/src/log-reporter.d.ts +0 -41
- package/dist/src/manager/prompt.d.ts +0 -2
- package/dist/src/manager/registry.d.ts +0 -184
- package/dist/src/manager/retired-external-channel-compat.d.ts +0 -78
- package/dist/src/manager/runtime.d.ts +0 -90
- package/dist/src/manager/worker-ipc.d.ts +0 -28
- package/dist/src/manager/worker-markdown.d.ts +0 -10
- package/dist/src/native-fusion/codex-files.d.ts +0 -10
- package/dist/src/native-fusion/codex-message-parser.d.ts +0 -9
- package/dist/src/native-fusion/codex-parser.d.ts +0 -8
- package/dist/src/native-fusion/codex-user-input.d.ts +0 -11
- package/dist/src/native-fusion/config.d.ts +0 -1
- package/dist/src/native-fusion/file-identity.d.ts +0 -9
- package/dist/src/native-fusion/file-watcher.d.ts +0 -26
- package/dist/src/native-fusion/local-repository.d.ts +0 -90
- package/dist/src/native-fusion/native-source-deletions.d.ts +0 -47
- package/dist/src/native-fusion/opencode-parser.d.ts +0 -29
- package/dist/src/native-fusion/parser-common.d.ts +0 -35
- package/dist/src/native-fusion/parsers.d.ts +0 -13
- package/dist/src/native-fusion/service.d.ts +0 -64
- package/dist/src/native-fusion/session-header.d.ts +0 -13
- package/dist/src/native-fusion/session-native-sources.d.ts +0 -24
- package/dist/src/native-fusion/source-visibility-audit.d.ts +0 -16
- package/dist/src/native-fusion/source-visibility.d.ts +0 -25
- package/dist/src/native-fusion/state.d.ts +0 -4
- package/dist/src/native-fusion/types.d.ts +0 -82
- package/dist/src/personal-sync/epoch.d.ts +0 -17
- package/dist/src/personal-sync/identity.d.ts +0 -1
- package/dist/src/personal-sync/machine-authority.d.ts +0 -12
- package/dist/src/personal-sync/metrics.d.ts +0 -25
- package/dist/src/personal-sync/paths.d.ts +0 -5
- package/dist/src/region.d.ts +0 -15
- package/dist/src/relay/client.d.ts +0 -81
- package/dist/src/room/activation-audit.d.ts +0 -15
- package/dist/src/room/activation-policy.d.ts +0 -8
- package/dist/src/room/activation-service.d.ts +0 -77
- package/dist/src/room/attachment-cache.d.ts +0 -44
- package/dist/src/room/attachment-upload.d.ts +0 -20
- package/dist/src/room/device-authorization-client.d.ts +0 -91
- package/dist/src/room/host-session-observations.d.ts +0 -54
- package/dist/src/room/invite-bootstrap.d.ts +0 -49
- package/dist/src/room/invite-qr.d.ts +0 -6
- package/dist/src/room/live-delivery.d.ts +0 -5
- package/dist/src/room/managed-context.d.ts +0 -49
- package/dist/src/room/managed-prompt-composer.d.ts +0 -47
- package/dist/src/room/managed-room-binding.d.ts +0 -69
- package/dist/src/room/managed-room-ipc.d.ts +0 -65
- package/dist/src/room/mirror-sync-service.d.ts +0 -49
- package/dist/src/room/public-attachment-cache.d.ts +0 -34
- package/dist/src/room/public-room-client.d.ts +0 -37
- package/dist/src/room/registration-authority.d.ts +0 -4
- package/dist/src/room/room-action-client-types.d.ts +0 -137
- package/dist/src/room/room-action-client.d.ts +0 -116
- package/dist/src/room/room-binding-client.d.ts +0 -62
- package/dist/src/room/session-registry.d.ts +0 -158
- package/dist/src/runtime-distribution.d.ts +0 -7
- package/dist/src/schedules/personal-context.d.ts +0 -2
- package/dist/src/schedules/server-client.d.ts +0 -19
- package/dist/src/security/managed-agent-credential-paths.d.ts +0 -6
- package/dist/src/security/managed-agent-executable.d.ts +0 -19
- package/dist/src/security/managed-agent-policy.d.ts +0 -66
- package/dist/src/security/managed-agent-runtime.d.ts +0 -44
- package/dist/src/session/archive-zip.d.ts +0 -10
- package/dist/src/session/attachment-reference.d.ts +0 -2
- package/dist/src/session/attachment-transfer-store.d.ts +0 -45
- package/dist/src/session/canonical-store.d.ts +0 -104
- package/dist/src/session/deletion-sync-state.d.ts +0 -20
- package/dist/src/session/deletion-sync-validation.d.ts +0 -2
- package/dist/src/session/deletion-synchronizer.d.ts +0 -9
- package/dist/src/session/handlers/agent-capabilities.d.ts +0 -3
- package/dist/src/session/handlers/agent-config.d.ts +0 -7
- package/dist/src/session/handlers/agent-control.d.ts +0 -4
- package/dist/src/session/handlers/agent-workspace-validation.d.ts +0 -28
- package/dist/src/session/handlers/agents.d.ts +0 -11
- package/dist/src/session/handlers/chat-adapter-config.d.ts +0 -11
- package/dist/src/session/handlers/chat-context.d.ts +0 -31
- package/dist/src/session/handlers/chat-events.d.ts +0 -5
- package/dist/src/session/handlers/chat-recovery.d.ts +0 -4
- package/dist/src/session/handlers/chat-session-lifecycle.d.ts +0 -9
- package/dist/src/session/handlers/chat.d.ts +0 -6
- package/dist/src/session/handlers/control.d.ts +0 -5
- package/dist/src/session/handlers/fs.d.ts +0 -14
- package/dist/src/session/handlers/message-status.d.ts +0 -3
- package/dist/src/session/handlers/pi-validation-session.d.ts +0 -7
- package/dist/src/session/handlers/pi-validation-session.js +0 -1
- package/dist/src/session/handlers/project-fs.d.ts +0 -11
- package/dist/src/session/handlers/remote-access.d.ts +0 -4
- package/dist/src/session/handlers/room-managed.d.ts +0 -6
- package/dist/src/session/handlers/session-refresh.d.ts +0 -3
- package/dist/src/session/handlers/title.d.ts +0 -3
- package/dist/src/session/handlers/tool-detail.d.ts +0 -3
- package/dist/src/session/handlers/voice-window.d.ts +0 -3
- package/dist/src/session/history-subscriptions.d.ts +0 -29
- package/dist/src/session/index-publisher.d.ts +0 -3
- package/dist/src/session/manager-event-authority.d.ts +0 -3
- package/dist/src/session/manager.d.ts +0 -95
- package/dist/src/session/native-cleanup-outbox.d.ts +0 -64
- package/dist/src/session/native-session-lifecycle.d.ts +0 -56
- package/dist/src/session/project-fs-store.d.ts +0 -43
- package/dist/src/session/projection.d.ts +0 -3
- package/dist/src/session/queue-control.d.ts +0 -27
- package/dist/src/session/queue-helpers.d.ts +0 -20
- package/dist/src/session/queue-message.d.ts +0 -35
- package/dist/src/session/queue-retry.d.ts +0 -11
- package/dist/src/session/queue-storage.d.ts +0 -8
- package/dist/src/session/queue-types.d.ts +0 -31
- package/dist/src/session/queue.d.ts +0 -73
- package/dist/src/session/queued-chat-dispatch.d.ts +0 -12
- package/dist/src/session/run-recovery/barrier.d.ts +0 -12
- package/dist/src/session/run-recovery/coordinator.d.ts +0 -32
- package/dist/src/session/run-recovery/journal.d.ts +0 -30
- package/dist/src/session/run-recovery/schema.d.ts +0 -48
- package/dist/src/session/store.d.ts +0 -128
- package/dist/src/session/tool-detail-store.d.ts +0 -17
- package/dist/src/session/turn-trigger.d.ts +0 -43
- package/dist/src/session/types.d.ts +0 -93
- package/dist/src/tools/markdown-to-pdf.d.ts +0 -42
- package/dist/src/upgrade/channel.d.ts +0 -5
- package/dist/src/upgrade/distribution.d.ts +0 -21
- package/dist/src/upgrade/engine.d.ts +0 -104
- package/dist/src/upgrade/scheduler.d.ts +0 -60
- package/dist/src/upgrade/updater-bootstrap.d.ts +0 -12
- package/dist/src/upgrade/updater-launcher.d.ts +0 -37
- package/dist/src/upgrade/updater-protocol.d.ts +0 -40
- package/dist/src/upgrade/updater-service-entry.d.ts +0 -7
- package/dist/src/upgrade/updater-worker.d.ts +0 -57
- package/dist/src/windows-shell.d.ts +0 -6
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts +0 -16
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts +0 -133
- package/node_modules/@shennian/wire/dist/envelope.d.ts +0 -7
- package/node_modules/@shennian/wire/dist/events.d.ts +0 -125
- package/node_modules/@shennian/wire/dist/external-message-format.d.ts +0 -37
- package/node_modules/@shennian/wire/dist/frames.d.ts +0 -33
- package/node_modules/@shennian/wire/dist/fs.d.ts +0 -107
- package/node_modules/@shennian/wire/dist/index.d.ts +0 -21
- package/node_modules/@shennian/wire/dist/machine.d.ts +0 -160
- package/node_modules/@shennian/wire/dist/message-payload.d.ts +0 -71
- package/node_modules/@shennian/wire/dist/methods.d.ts +0 -5
- package/node_modules/@shennian/wire/dist/native-session.d.ts +0 -20
- package/node_modules/@shennian/wire/dist/project-fs.d.ts +0 -146
- package/node_modules/@shennian/wire/dist/project-path.d.ts +0 -4
- package/node_modules/@shennian/wire/dist/project.d.ts +0 -16
- package/node_modules/@shennian/wire/dist/relay-connectivity.d.ts +0 -30
- package/node_modules/@shennian/wire/dist/room.d.ts +0 -190
- package/node_modules/@shennian/wire/dist/schedule.d.ts +0 -37
- package/node_modules/@shennian/wire/dist/session-sync.d.ts +0 -406
- package/node_modules/@shennian/wire/dist/session.d.ts +0 -465
- package/node_modules/@shennian/wire/dist/tool-detail.d.ts +0 -38
- package/node_modules/@shennian/wire/dist/voice-chief.d.ts +0 -116
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createInterface as g}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as h,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{buildAgentProcessEnv as
|
|
1
|
+
import{createInterface as g}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as h,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{spawnEnoentError as C}from"./spawn-errors.js";import{buildAgentProcessEnv as y,buildManagedAgentProcessEnv as O,buildManagedNativeFullProcessEnv as D}from"../agent-env.js";import{buildInlineChannelPreamble as I}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as S,isManagedAgentNativeFull as P}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as w}from"../security/managed-agent-runtime.js";import{compileOpenCodeManagedPermissions as _,createOpenCodeManagedConfigDirectory as A,disposeOpenCodeManagedConfigDirectory as v,OPENCODE_MANAGED_RUNTIME_SECURITY as N}from"./opencode-managed-permissions.js";w("opencode",N);function k(n){if(!n)return;const e=n.input,t=n.output;if(!(typeof e!="number"&&typeof t!="number"))return{inputTokens:typeof e=="number"?e:0,outputTokens:typeof t=="number"?t:0}}function u(n){if(n==null)return"";if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return String(n)}}function c(n){if(!n)return"opencode request failed";if(typeof n=="string")return n;if(typeof n!="object")return String(n);const e=n;return typeof e.message=="string"?e.message:typeof e.name=="string"?e.name:"data"in e?c(e.data):u(n)||"opencode request failed"}class x extends h{type="opencode";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";runUsage;externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,o){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,o&&(this.agentSessionId=o),this.resetRunState()}async send(e,t,o,i,s,d){if(d?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=l(),this.resetRunState();const a=["run","--format","json","--dir",this.workDir??process.cwd()];this.agentSessionId&&a.push("--session",this.agentSessionId),t&&a.push("--model",t);const r=`${I(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,s)}${e}`;await this.spawnAndParse(a,r)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=l(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:e}),this.emitFinalIfOpen({state:"final",agentSessionId:e})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open",this.runUsage=void 0}async spawnAndParse(e,t){const o=m("opencode");if(!o){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const i=await this.prepareManagedLaunch();let s;try{s=E(o,[e[0],...i.args,...e.slice(1)],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:i.env})}catch(r){throw await this.disposeManagedConfig(i.configDir),r}this.process=s,this.managedConfigDir=i.configDir,g({input:s.stdout}).on("line",r=>{this.handleProcessLine(s,r)});let a="";s.stderr?.on("data",r=>{a+=r.toString()}),s.on("close",(r,p)=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),this.terminalState==="open"&&this.completeRunAfterProcessExit(r,p,a.trim()))}),s.on("error",r=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),r.code==="ENOENT"?this.emit("error",C(this.workDir,'Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",r))}),s.stdin.on("error",r=>{this.process===s&&this.emitErrorIfOpen({state:"error",message:r.message})}),s.stdin.end(t)}async prepareManagedLaunch(){const e=this.managedAgentPolicy;if(!e)return{args:["--auto"],env:y({NO_COLOR:"1",...this.extraEnv}),configDir:null};if(P(e))return{args:["--auto"],env:D({NO_COLOR:"1",...this.extraEnv}),configDir:null};const t=_(S(e),e.adapterPolicy.workDir),o=await A(t),i=O({agentType:"opencode",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return i.OPENCODE_CONFIG=o.configPath,i.OPENCODE_CONFIG_DIR=o.directory,i.OPENCODE_CONFIG_CONTENT=JSON.stringify(t.config),i.OPENCODE_DISABLE_PROJECT_CONFIG="true",i.OPENCODE_DISABLE_CLAUDE_CODE="1",i.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT="1",i.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS="1",{args:t.args,env:i,configDir:o.directory}}async disposeManagedConfig(e){e&&(this.managedConfigDir===e&&(this.managedConfigDir=null),await v(e).catch(()=>{}))}handleStreamEvent(e){e.sessionID&&e.sessionID!==this.agentSessionId&&(this.agentSessionId=e.sessionID,this.emitEvent({state:"start",agentSessionId:e.sessionID}));const t=e.part;if(e.type==="text"&&t?.text){this.emitEvent({state:"delta",text:t.text});return}if(e.type==="reasoning"&&t?.text){this.emitEvent({state:"delta",text:t.text,thinking:!0});return}if(e.type==="tool_use"&&t?.type==="tool"){t.state?.status==="completed"||t.state?.status==="error"?this.emitEvent({state:"tool-result",name:t.tool??"tool",result:t.state.status==="error"?t.state.error??"tool failed":u(t.state?.output)}):this.emitEvent({state:"tool-call",name:t.tool??"tool",args:t.state?.input??{}});return}if(e.type==="error"){this.emitErrorIfOpen({state:"error",message:c(e.error)});return}e.type==="step_finish"&&this.recordStepUsage(k(t?.tokens))}handleProcessLine(e,t){if(!(this.process!==e||!t.trim()))try{this.handleStreamEvent(JSON.parse(t))}catch{this.emitEvent({state:"delta",text:t})}}recordStepUsage(e){e&&(this.runUsage={inputTokens:(this.runUsage?.inputTokens??0)+e.inputTokens,outputTokens:(this.runUsage?.outputTokens??0)+e.outputTokens})}completeRunAfterProcessExit(e=0,t=null,o=""){if(e!==0||t!==null){this.emitErrorIfOpen({state:"error",message:o||(t?`opencode exited with signal ${t}`:`opencode exited with code ${String(e)}`)});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.runUsage})}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}async killProcess(){const e=this.process;if(!e){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}),await this.disposeManagedConfig(this.managedConfigDir)}}f("opencode",()=>new x);export{x as OpenCodeAdapter};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
[truncated]`}function
|
|
3
|
-
`)}`}function E(n,t){const s=[];for(const e of n??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let i=e.previewData?.trim()??"";const a=i.indexOf(",");if(i.startsWith("data:")&&a>=0&&(i=i.slice(a+1)),!i&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const l=h.statSync(e.path);l.isFile()&&l.size<=10*1024*1024&&(i=h.readFileSync(e.path).toString("base64"))}catch{i=""}i&&s.push({type:"image",data:i,mimeType:e.mimeType})}return s}class W extends A{type="pi-coding-agent";get supportsActiveInput(){return!0}async injectActiveInput(t){const s=await this.readState();if(!this.rpc||!this.runId||!s.isStreaming&&!s.isCompacting)throw new Error("pi_active_turn_unavailable");const e={message:_(t.text,t.attachments,this.workDir,this.externalChannel,this.shennianSessionId,null)},i=E(t.attachments,!this.managedAgentPolicy);i.length&&!this.modelBroker&&(e.images=i),await this.rpc.request("steer",e)}get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;modelBroker=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,i){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const a=f("runtime","pi-coding-agent",g(t));this.persistNativeSession=i?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:u.join(a,`validation-${w()}`),this.sessionDir=this.validationRoot?u.join(this.validationRoot,"sessions"):u.join(a,"sessions"),h.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,i,a,l){await this.ensureProcess(a);const c=this.requireRpc(),p=await this.readState(),o=!!(p.isStreaming||p.isCompacting);(!o||!this.runId)&&(this.runId=w(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const d=K(s);if(d.modelId&&!o&&(p.model?.id!==d.modelId||d.provider&&p.model?.provider!==d.provider)){if(!d.provider)throw new Error("Pi model selection must include provider/modelId");await c.request("set_model",{provider:d.provider,modelId:d.modelId})}e&&!o&&await c.request("set_thinking_level",{level:e});const r=o?l?.source==="room_activation"?"follow_up":"steer":"prompt",m={message:_(t,i,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=E(i,!this.managedAgentPolicy);S.length&&!this.modelBroker&&(m.images=S),this.modelBroker?.setTurnActive(!0);try{await c.request(r,m)}catch(v){throw this.modelBroker?.setTurnActive(!1),v}}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc)return;const s=x("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];this.agentSessionId&&e.push("--session",this.agentSessionId);const i=await this.prepareHostedModel();if(i&&e.push("--provider","shennian-dashscope","--model","deepseek-v4-flash-0731"),this.managedAgentPolicy&&!P(this.managedAgentPolicy)){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const r=this.managedTools(),m=F({outputPath:u.join(f("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",m),r.length?e.push("--tools",r.join(",")):e.push("--no-tools")}const a=D(this.workDir,this.externalChannel,this.shennianSessionId,t),l=this.validationRoot??f("runtime","pi-coding-agent",g(this.shennianSessionId));h.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=u.join(l,"instructions.md"),h.writeFileSync(this.promptFile,a,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const c={NO_COLOR:"1",...i?{PI_CODING_AGENT_DIR:i.configDir}:{}},p=this.managedAgentPolicy&&!P(this.managedAgentPolicy)?N({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:c}):this.managedAgentPolicy?b({...c,...this.extraEnv}):T({...c,...this.extraEnv});let o;try{o=R(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:p})}catch(r){throw await this.stopModelBroker(),r}this.process=o,this.stderr="",o.stderr?.on("data",r=>{const m=typeof r=="string"?r:r.toString("utf8");this.stderr=y(`${this.stderr}${m}`,$)});const d=new B(o);this.rpc=d,d.on("event",r=>this.handleRpcEvent(r)),d.on("protocolError",r=>this.emitError(r.message)),o.once("close",r=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(r===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${r??"unknown"}${this.stderr?`: ${this.stderr}`:""}`),this.stopModelBroker())}),o.once("error",r=>{this.process===o&&this.emitError(r.message)});try{const r=await this.readState();if(!r.sessionId)throw new Error("Pi RPC did not return a session ID");if(r.isStreaming||r.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&r.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!r.sessionFile||!this.ownsSessionFile(r.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=r.sessionId,this.persistNativeSession&&U(r.sessionId,this.sessionDir)}catch(r){throw await this.stopProcess(),r}}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,i=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||i||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=u.resolve(this.sessionDir),e=u.resolve(t),i=u.relative(s,e);return i!==""&&!i.startsWith("..")&&!u.isAbsolute(i)}async readState(){const t=await this.requireRpc().request("get_state");return H(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=I(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:X(t.result)||Z(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=I(e.usage)??this.lastUsage,e.stopReason==="error"&&(this.modelBroker?.setTurnActive(!1),this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed"))}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.modelBroker?.setTurnActive(!1),this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"error",message:L(t)})}async prepareHostedModel(){const t=M(),s=t.machineToken?.trim();if(!s)return null;const e=new q({serverUrl:t.serverUrl?.trim()||"https://shennian.net",machineToken:s,sessionId:this.shennianSessionId}),i=await e.start(),a=this.validationRoot?u.join(this.validationRoot,"agent-config"):f("runtime","pi-coding-agent",g(this.shennianSessionId),"agent-config");h.mkdirSync(a,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(a,448);const l=u.join(a,"models.json"),c={providers:{"shennian-dashscope":{baseUrl:i.baseUrl,api:"openai-completions",apiKey:i.apiKey,authHeader:!0,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!0},models:[{id:"deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",reasoning:!0,input:["text"],thinkingLevelMap:{off:null,minimal:null,low:"low",medium:null,high:"high",xhigh:null,max:"max"}}]}}};return h.writeFileSync(l,`${JSON.stringify(c,null,2)}
|
|
4
|
-
`,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(l,384),this.modelBroker=e,{configDir:a}}async stopModelBroker(){const t=this.modelBroker;this.modelBroker=null,await t?.stop().catch(()=>{})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t?(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const i=()=>{e||(e=!0,s())};t.once("close",i),setTimeout(()=>{t.kill("SIGKILL"),i()},z).unref()}),await this.stopModelBroker()):await this.stopModelBroker(),this.validationRoot&&(h.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}k("pi-coding-agent",()=>new W);export{W as PiCodingAgentAdapter};
|
|
1
|
+
import d from"node:fs";import h from"node:path";import{randomUUID as P}from"node:crypto";import{AgentAdapter as A,registerAgent as x}from"./adapter.js";import{resolveBuiltinCommand as v,spawnAgentCommand as R}from"./command-spec.js";import{buildAgentProcessEnv as N,buildManagedAgentProcessEnv as C,buildManagedNativeFullProcessEnv as T}from"../agent-env.js";import{resolveShennianPath as m}from"../config/index.js";import{buildInlineChannelPreamble as b,buildPlatformInstructions as k}from"./platform-instructions.js";import{isManagedAgentNativeFull as _}from"../security/managed-agent-policy.js";import{PiRpcClient as D}from"./pi-rpc-client.js";import{registerManagedAgentRuntimeSecurity as M}from"../security/managed-agent-runtime.js";import{PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY as O}from"./pi-coding-agent-managed-permissions.js";import{writePiManagedExtension as q}from"./pi-managed-extension.js";import{recordPiSessionOwnership as j}from"./pi-session-ownership.js";M("pi-coding-agent",O);const F=32*1024,$=256*1024,U=3e3;function g(n){return n.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,180)||"session"}function B(n){return n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?n.data:{}}function G(n){if(typeof n=="string")return n;if(!n||typeof n!="object")return"";const t=n.content;return Array.isArray(t)?t.map(s=>{if(!s||typeof s!="object")return"";const e=s;return e.type==="text"&&typeof e.text=="string"?e.text:""}).join(""):""}function f(n,t=$){return n.length<=t?n:`${n.slice(0,t)}
|
|
2
|
+
[truncated]`}function z(n){return f(n,2e3).replace(/Bearer\s+[A-Za-z0-9._~-]+/gi,"Bearer [redacted]").replace(/\b(?:pimc|mrc)_[A-Za-z0-9_-]{20,}\b/g,"[redacted-capability]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g,"[redacted-key]")}function H(n){try{return f(JSON.stringify(n))}catch{return"[unserializable]"}}function E(n){if(!n||typeof n!="object")return;const t=n;if(!(typeof t.input!="number"&&typeof t.output!="number"))return{inputTokens:typeof t.input=="number"?t.input:0,outputTokens:typeof t.output=="number"?t.output:0}}function X(n){const t=n?.trim();if(!t)return{};const s=t.indexOf("/");return s<=0||s===t.length-1?{modelId:t}:{provider:t.slice(0,s),modelId:t.slice(s+1)}}function w(n,t,s,e,r,l){const c=b(s,e,r,l),u=t?.filter(a=>a.kind!=="image")??[];if(!u.length)return`${c}${n}`;const o=u.map(a=>`[${a.name}](<${a.path}>)`);return`${c}${[n,"",...o].join(`
|
|
3
|
+
`)}`}function I(n,t){const s=[];for(const e of n??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let r=e.previewData?.trim()??"";const l=r.indexOf(",");if(r.startsWith("data:")&&l>=0&&(r=r.slice(l+1)),!r&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const c=d.statSync(e.path);c.isFile()&&c.size<=10*1024*1024&&(r=d.readFileSync(e.path).toString("base64"))}catch{r=""}r&&s.push({type:"image",data:r,mimeType:e.mimeType})}return s}class Z extends A{type="pi-coding-agent";get supportsActiveInput(){return!0}async injectActiveInput(t){const s=await this.readState();if(!this.rpc||!this.runId||!s.isStreaming&&!s.isCompacting)throw new Error("pi_active_turn_unavailable");const e={message:w(t.text,t.attachments,this.workDir,this.externalChannel,this.shennianSessionId,null)},r=I(t.attachments,!this.managedAgentPolicy);r.length&&(e.images=r),await this.rpc.request("steer",e)}get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};spawnedRoomContext=null;managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,r){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const l=m("runtime","pi-coding-agent",g(t));this.persistNativeSession=r?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:h.join(l,`validation-${P()}`),this.sessionDir=this.validationRoot?h.join(this.validationRoot,"sessions"):h.join(l,"sessions"),d.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&d.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,r,l,c){await this.ensureProcess(l);const u=this.requireRpc(),o=await this.readState(),a=!!(o.isStreaming||o.isCompacting);(!a||!this.runId)&&(this.runId=P(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const i=X(s);if(i.modelId&&!a&&(o.model?.id!==i.modelId||i.provider&&o.model?.provider!==i.provider)){if(!i.provider)throw new Error("Pi model selection must include provider/modelId");await u.request("set_model",{provider:i.provider,modelId:i.modelId})}e&&!a&&await u.request("set_thinking_level",{level:e});const p=a?c?.source==="room_activation"?"follow_up":"steer":"prompt",y={message:w(t,r,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=I(r,!this.managedAgentPolicy);S.length&&(y.images=S),await u.request(p,y)}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc){if(!await this.roomContextStale())return;await this.stopProcess()}const s=v("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];if(this.agentSessionId&&e.push("--session",this.agentSessionId),this.managedAgentPolicy&&!_(this.managedAgentPolicy)){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const i=this.managedTools(),p=q({outputPath:h.join(m("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",p),i.length?e.push("--tools",i.join(",")):e.push("--no-tools")}const r=k(this.workDir,this.externalChannel,this.shennianSessionId,t),l=this.validationRoot??m("runtime","pi-coding-agent",g(this.shennianSessionId));d.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=h.join(l,"instructions.md"),d.writeFileSync(this.promptFile,r,{encoding:"utf8",mode:384}),process.platform!=="win32"&&d.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const c={NO_COLOR:"1"},u=this.managedAgentPolicy&&!_(this.managedAgentPolicy)?C({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:c}):this.managedAgentPolicy?T({...c,...this.extraEnv}):N({...c,...this.extraEnv}),o=R(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:u});this.process=o,this.spawnedRoomContext=this.currentRoomContext(),this.stderr="",o.stderr?.on("data",i=>{const p=typeof i=="string"?i:i.toString("utf8");this.stderr=f(`${this.stderr}${p}`,F)});const a=new D(o);this.rpc=a,a.on("event",i=>this.handleRpcEvent(i)),a.on("protocolError",i=>this.emitError(i.message)),o.once("close",i=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(i===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${i??"unknown"}${this.stderr?`: ${this.stderr}`:""}`))}),o.once("error",i=>{this.process===o&&this.emitError(i.message)});try{const i=await this.readState();if(!i.sessionId)throw new Error("Pi RPC did not return a session ID");if(i.isStreaming||i.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&i.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!i.sessionFile||!this.ownsSessionFile(i.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=i.sessionId,this.persistNativeSession&&j(i.sessionId,this.sessionDir)}catch(i){throw await this.stopProcess(),i}}currentRoomContext(){return this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT??null}async roomContextStale(){if(this.currentRoomContext()===this.spawnedRoomContext)return!1;const t=await this.readState().catch(()=>null);return!t?.isStreaming&&!t?.isCompacting}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,r=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||r||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=h.resolve(this.sessionDir),e=h.resolve(t),r=h.relative(s,e);return r!==""&&!r.startsWith("..")&&!h.isAbsolute(r)}async readState(){const t=await this.requireRpc().request("get_state");return B(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=E(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:G(t.result)||H(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=E(e.usage)??this.lastUsage,e.stopReason==="error"&&this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed")}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.emitTerminal({state:"error",message:z(t)})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t&&(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const r=()=>{e||(e=!0,s())};t.once("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},U).unref()})),this.validationRoot&&(d.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}x("pi-coding-agent",()=>new Z);export{Z as PiCodingAgentAdapter};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createHash as p}from"node:crypto";import
|
|
2
|
-
`,{encoding:"utf8",mode:384}),
|
|
1
|
+
import{createHash as p}from"node:crypto";import n from"node:fs";import{renameSyncWithRetry as f}from"../fs/atomic-rename.js";import o from"node:path";import{resolveShennianPath as c}from"../config/index.js";function a(){return c("runtime","pi-coding-agent","session-owners")}function d(r){const t=p("sha256").update(r).digest("hex");return o.join(a(),`${t}.json`)}function u(r){const t=o.resolve(c("runtime","pi-coding-agent")),e=o.resolve(r),i=o.relative(t,e);return i!==""&&!i.startsWith("..")&&!o.isAbsolute(i)&&o.basename(e)==="sessions"}function S(r,t){if(!r||!u(t))throw new Error("pi_session_ownership_invalid");const e=a();n.mkdirSync(e,{recursive:!0,mode:448});const i=d(r),s=`${i}.${process.pid}.tmp`,m={version:1,agentSessionId:r,sessionDir:o.resolve(t)};n.writeFileSync(s,`${JSON.stringify(m)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),f(s,i),process.platform!=="win32"&&n.chmodSync(i,384)}function _(r){if(!r||r.length>255||/[\0\r\n]/.test(r))return"invalid_identity";const t=d(r);let e;try{e=JSON.parse(n.readFileSync(t,"utf8"))}catch(i){return i.code==="ENOENT"?"already_absent":"invalid_identity"}return e.version!==1||e.agentSessionId!==r||!u(e.sessionDir)?"invalid_identity":(n.rmSync(e.sessionDir,{recursive:!0,force:!0}),n.rmSync(t,{force:!0}),"deleted")}export{_ as deleteOwnedPiSession,S as recordPiSessionOwnership};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import o from"node:fs";function e(r,n){return r&&!o.existsSync(r)?new Error(`agent_workdir_not_found: \u5DE5\u4F5C\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${r}`):new Error(n)}export{e as spawnEnoentError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawnSync as c}from"node:child_process";import s from"node:fs";import p from"node:os";import n from"node:path";import{buildWindowsSystemEnv as d,resolveWindowsPowerShellPath as m}from"../windows-shell.js";let r;function P(){r=void 0}function a(){if(r)return r;r={path:"",codexRoots:[]};const i=["$ErrorActionPreference = 'Stop'","[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)","$paths = @([Environment]::GetEnvironmentVariable('Path', 'Machine'), [Environment]::GetEnvironmentVariable('Path', 'User'))","$roots = @()","try { $roots = @(Get-AppxPackage -Name '*Codex*' -ErrorAction Stop | Where-Object { $_.Name -eq 'OpenAI.Codex' } | Sort-Object InstallLocation | Select-Object -ExpandProperty InstallLocation) } catch {}","@{ path = ($paths -join ';'); codexRoots = @($roots) } | ConvertTo-Json -Compress"].join("; ");try{const t=c(m(),["-NoProfile","-NonInteractive","-Command",i],{env:{...process.env,...d()},encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:3e3,maxBuffer:65536,windowsHide:!0});if(t.status!==0||typeof t.stdout!="string")return r;const e=JSON.parse(t.stdout.replace(/^\uFEFF/,""));r={path:typeof e.path=="string"?e.path:"",codexRoots:Array.isArray(e.codexRoots)?e.codexRoots.filter(o=>typeof o=="string"&&n.win32.isAbsolute(o)):[]}}catch{}return r}function y(){const t=[...(process.env.PATH??process.env.Path??"").split(";"),...a().path.split(";")],e=new Set;return t.map(o=>o.trim().replace(/^"(.*)"$/,"$1")).filter(o=>!o||e.has(o.toLowerCase())?!1:(e.add(o.toLowerCase()),!0)).join(";")}function l(i){const t=n.win32.join(i,"OpenAI","Codex","bin");try{return s.readdirSync(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>n.win32.join(t,e.name)).map(e=>({dir:e,modified:s.statSync(e).mtimeMs})).sort((e,o)=>o.modified-e.modified).map(({dir:e})=>n.win32.join(e,"codex.exe"))}catch{return[]}}function C(i=p.homedir()){const t=process.env.LOCALAPPDATA||n.win32.join(i,"AppData","Local"),e=[...a().codexRoots,n.win32.join(t,"Programs","Codex"),n.win32.join(t,"Codex")];return[...l(t),...e.flatMap(o=>[n.win32.join(o,"app","resources","codex.exe"),n.win32.join(o,"resources","codex.exe")])]}export{a as readWindowsInstallationPaths,P as resetWindowsInstallationPaths,C as windowsCodexDesktopCandidates,y as windowsLookupPath};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{callDaemonIpc as
|
|
2
|
-
`),n.ok||(process.exitCode=1)};
|
|
1
|
+
import{callDaemonIpc as s}from"../daemon-ipc/client.js";import{DaemonIpcError as i}from"../daemon-ipc/protocol.js";const d={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The result is unknown. Check the target machine and wait for the current check to finish; do not repeatedly send tests.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available.",agent_validation_workdir_invalid:"Use an existing absolute project directory on this computer that the user allows Shennian to use.",agent_validation_workdir_not_found:"The working directory does not exist on this computer. Ask the user for an existing absolute project directory (it may have been moved, deleted or is on an unmounted drive); do not create it for them.",agent_validation_workdir_not_directory:"The working directory path is a file, not a folder. Ask the user for the project folder.",agent_validation_workdir_unavailable:"The working directory exists but this user cannot access it. Check its permissions on this computer or choose another directory.",agent_validation_start_failed:"The AI could not start. Run the tool once on this computer to see its own error, fix its installation or configuration, then retry.",agent_validation_response_timeout:"The AI started but gave no hello reply within 60 seconds. Check its provider sign-in, selected model and network, then retry once; do not repeatedly send tests.",agent_validation_response_mismatch:"The AI replied but not with hello. Check the selected model; a reply that ignores simple instructions usually means a wrong or misconfigured model.",agent_validation_response_failed:"The AI started but failed while replying. Check its provider sign-in, selected model, quota and network, then retry once."},r={agent_validation_runtime_unavailable:"start",agent_validation_workdir_invalid:"start",agent_validation_workdir_not_found:"start",agent_validation_workdir_not_directory:"start",agent_validation_workdir_unavailable:"start",agent_validation_start_failed:"start",agent_validation_runtime_auth_required:"auth",agent_validation_model_unavailable:"model",agent_validation_quota_exceeded:"quota",agent_validation_network_failed:"network",agent_validation_response_timeout:"reply",agent_validation_response_mismatch:"reply",agent_validation_response_failed:"reply"},l="A successful check only proves one standard-mode hello reply; it does not prove the AI can send messages in a Room.",c={authState:'unknown means Shennian has no login probe for this AI; it is not "not logged in".',defaultModelId:"null means no model is marked default; it does not mean no model is available. The AI picks its own model when none is passed."};async function u(t,a,o=s){try{const e=await o({method:t,params:a,timeoutMs:9e4});if(t==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new i("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return t==="agent.discover"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,notes:c}}:t==="agent.check"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,note:l}}:{ok:!0,command:t,result:e}}catch(e){const n=e instanceof i?e.code:"agent_check_failed";return{ok:!1,command:t,error:n,...r[n]?{stage:r[n]}:{},nextAction:d[n]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function m(t){const a=async(o,e)=>{const n=await u(o,e);process.stdout.write(`${JSON.stringify(n)}
|
|
2
|
+
`),n.ok||(process.exitCode=1)};t.command("discover").description("Read the daemon AI snapshot; use --refresh only to rerun local provider and model discovery").option("--agent <type>","Return only one discovered Agent type").option("--compact","Return capability summary without the full model list").option("--refresh","Rerun discovery; with --agent, probe only that Agent").option("--json","Print JSON (default)").action(o=>a("agent.discover",{...o.agent?{agentType:o.agent}:{},compact:o.compact===!0,refresh:o.refresh===!0})),t.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((o,e)=>a("agent.check",{agentType:o,workDir:e.workdir,modelId:e.model??null}))}export{u as executeAgentReadinessCommand,m as registerAgentReadinessCommands};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import o from"node:fs";import a from"node:path";import s from"node:os";import{resolveShennianPath as i}from"../config/index.js";import{buildAugmentedPath as A}from"../env-path.js";import{getPlatform as m,SHENNIAN_DIR as P}from"./daemon-state.js";const E=new Set(["PATH","SHENNIAN_CODEX_PATH","HOME","USERPROFILE","HOMEDRIVE","HOMEPATH","USERNAME","USERDOMAIN","COMPUTERNAME","USER","LOGNAME","SHELL","TMPDIR","LANG","LC_ALL","LC_CTYPE","SSH_AUTH_SOCK","XDG_CONFIG_HOME","XDG_DATA_HOME","TEMP","TMP","APPDATA","LOCALAPPDATA","SHENNIAN_DESKTOP_SERVER_URL","SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HOME","SHENNIAN_ACCOUNT_NAMESPACE_ID","SHENNIAN_NATIVE_FUSION_DISABLED","SHENNIAN_WECHAT_DELIVERABILITY_TRACE"]);function N(e){return E.has(e)}function t(e){const r=e.replace(/\\/g,"/").toLowerCase(),n=s.tmpdir().replace(/\\/g,"/").toLowerCase();return r.includes("/_npx/")||r.includes("/npm-cache/_npx/")||r.includes("/pnpm/dlx/")||r.startsWith(n.endsWith("/")?n:`${n}/`)}function M(e){return o.existsSync(e.scriptPath)&&(process.env.SHENNIAN_E2E_ISOLATED_DAEMON==="1"||!t(e.scriptPath))?{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}:e.shennianCommandPath&&!t(e.shennianCommandPath)?{command:e.shennianCommandPath,args:["run-service"],mode:"global-shim"}:e.npxPath?{command:e.npxPath,args:["--yes","shennian","run-service"],mode:"npx"}:{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}}function I(){const e={};for(const r of E)process.env[r]&&(e[r]=process.env[r]);if(e.HOME??=s.homedir(),e.PATH=A({pathValue:e.PATH,env:e}),e.USER??=s.userInfo().username,m()==="win32"){const r=process.env.TEMP||process.env.TMP||s.tmpdir(),n=s.homedir();e.USERPROFILE??=n;const c=a.win32.parse(n);e.HOMEDRIVE??=c.root.replace(/[\\/]$/,"")||process.env.HOMEDRIVE||"",e.HOMEPATH??=n.slice((e.HOMEDRIVE||"").length)||process.env.HOMEPATH||"",e.USERNAME??=process.env.USERNAME||s.userInfo().username,e.COMPUTERNAME??=process.env.COMPUTERNAME||"",e.TMPDIR??=r,e.TEMP??=r,e.TMP??=r}else e.TMPDIR??="/tmp";return e}function d(){o.mkdirSync(P,{recursive:!0});const e={};for(const[r,n]of Object.entries(process.env))n!==void 0&&N(r)&&(e[r]=n);(process.env.PATH??process.env.Path)&&(e.PATH=process.env.PATH??process.env.Path),o.writeFileSync(i("env.json"),JSON.stringify(e,null,2))}export{I as captureEnvForService,t as isEphemeralCliPath,N as isSafeSnapshotEnvKey,M as resolveServiceLaunchSpec,d as saveEnvSnapshot};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import a from"chalk";import{readCliDistribution as ae}from"../runtime-distribution.js";import s from"node:fs";import l from"node:path";import g from"node:os";import{execSync as c,spawn as
|
|
2
|
-
`)}function J(e){const n=e?.trim();if(!n)return;const t=
|
|
1
|
+
import a from"chalk";import{readCliDistribution as ae}from"../runtime-distribution.js";import s from"node:fs";import{renameSyncWithRetry as ce}from"../fs/atomic-rename.js";import l from"node:path";import g from"node:os";import{execSync as c,spawn as ue}from"node:child_process";import{randomUUID as le}from"node:crypto";import{fileURLToPath as de}from"node:url";import{loadConfig as pe,resolveShennianPath as v,saveConfig as me}from"../config/index.js";import{buildWindowsLauncherCommand as fe,buildWindowsScheduledTaskXml as Se,buildWindowsStartupVbs as ge,escapeXml as I,isWindowsCmdScript as he,quoteCmdArg as W,quoteSystemdArg as ye,registerWindowsScheduledTask as we,suspendWindowsScheduledTask as ve}from"./daemon-windows.js";import{isDaemonReadyStatus as ke,waitForDaemonReadyStatus as A}from"./daemon-start-wait.js";import{getCurrentVersion as O}from"../upgrade/engine.js";import{buildWindowsLauncherCommand as yn,buildWindowsScheduledTaskCommands as wn,buildWindowsScheduledTaskSuspendCommands as vn,buildWindowsScheduledTaskXml as kn,buildWindowsStartupVbs as Dn,suspendWindowsScheduledTask as bn}from"./daemon-windows.js";import{inferDaemonLauncherFromCommand as $n,isShennianRunServiceCommand as In}from"./daemon-process.js";import{SHENNIAN_DIR as U,PID_FILE as E,LOG_FILE as d,REMOTE_ACCESS_DISABLED_FILE as B,readPidRecord as R,clearDaemonLauncher as De,shouldDiscoverGlobalDaemonProcesses as be,getPlatform as f,isRunning as k,waitForPidExitSync as F,isRemoteAccessDisabled as Pe,clearRemoteAccessDisabled as $e,recordStartedDaemon as Ie,findRunningDaemonProcessIds as Ae,shouldInstallPlatformService as x,getDaemonStatus as u}from"./daemon-state.js";import{isEphemeralCliPath as Ee,resolveServiceLaunchSpec as Re,captureEnvForService as H,saveEnvSnapshot as xe}from"./daemon-service-spec.js";import{isRemoteAccessDisabled as En,clearRemoteAccessDisabled as Rn,getCurrentProcessDaemonLauncher as xn,createDaemonInstanceId as Ln,writeDaemonPid as _n,clearDaemonPidIfOwner as jn,writeDaemonLauncher as Nn,clearDaemonLauncher as Tn,recordStartedDaemon as Cn,findRunningDaemonProcessIds as Wn,isIsolatedDaemonE2eInstance as On,shouldDiscoverGlobalDaemonProcesses as Un,shouldInstallPlatformService as Bn,getDaemonStatus as Fn}from"./daemon-state.js";import{isSafeSnapshotEnvKey as Mn,isEphemeralCliPath as Gn,resolveServiceLaunchSpec as Vn,captureEnvForService as Jn,saveEnvSnapshot as Kn}from"./daemon-service-spec.js";const Le=l.dirname(de(import.meta.url)),M=l.resolve(Le,"../../bin/shennian.js"),G=process.execPath;function V(e,n){const t=l.dirname(e),r=`${e}.${process.pid}.${le()}.tmp`;s.mkdirSync(t,{recursive:!0});let o=null;try{o=s.openSync(r,"w",384),s.writeSync(o,n,void 0,"utf8"),s.fsyncSync(o),s.closeSync(o),o=null,ce(r,e);try{const i=s.openSync(t,"r");try{s.fsyncSync(i)}finally{s.closeSync(i)}}catch{}}finally{o!==null&&s.closeSync(o);try{s.unlinkSync(r)}catch{}}}function _e(e={}){const n=e.disabledAt??new Date().toISOString(),t=e.markerFile??B,r=e.platform??f(),o=e.servicePresent??(x()&&N(r)),i=e.execCommand??(m=>{c(m,{stdio:"pipe",windowsHide:!0})});if(V(t,n),!o)return{disabledAt:n,autoStartDisabled:!0};try{return i(r==="darwin"?`launchctl disable "${_()}"`:r==="linux"?"systemctl --user disable shennian":`schtasks /change /tn "${w}" /disable`),{disabledAt:n,autoStartDisabled:!0}}catch(m){return{disabledAt:n,autoStartDisabled:!1,autoStartError:m instanceof Error?m.message:String(m)}}}function je(e={}){const n=e.platform??f();if(!(e.servicePresent??(x()&&N(n))))return{serviceStopped:!0};const r=e.execCommand??(o=>{c(o,{stdio:"pipe",windowsHide:!0})});try{return r(n==="darwin"?`launchctl bootout "${_()}"`:n==="linux"?"systemctl --user stop shennian":`schtasks /end /tn "${w}"`),{serviceStopped:!0}}catch(o){return{serviceStopped:!1,error:o instanceof Error?o.message:String(o)}}}function p(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
2
|
+
`)}function J(e){const n=e?.trim();if(!n)return;const t=pe();t.serverUrl=n,me(t)}function K(e){return e?.trim()||process.env.SHENNIAN_DESKTOP_SERVER_URL?.trim()||void 0}const L="com.shennian.agent",S=l.join(g.homedir(),"Library/LaunchAgents",`${L}.plist`),q=v("Shennian.app"),Ne=l.join(g.homedir(),"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),D=v("autostart.cmd"),b=v("autostart.vbs"),P=v("autostart.xml"),Te=l.join(Ne,"ShennianAgent.vbs");function X(e){const n=f()==="win32"?`where ${e}`:`command -v ${e}`;try{return c(n,{stdio:["ignore","pipe","pipe"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(o=>o.trim()).find(Boolean)??null}catch{return null}}function Ce(){const e=f()==="win32"?"npx.cmd":"npx",n=l.join(l.dirname(G),e);return s.existsSync(n)?n:X("npx")}function h(){return Re({nodeExec:G,scriptPath:M,shennianCommandPath:X("shennian"),npxPath:Ce()})}function Y(){try{c(`schtasks /delete /tn "${w}" /f`,{stdio:"pipe",windowsHide:!0})}catch{}}function z(){try{s.unlinkSync(Te)}catch{}}function We(){const e=process.env.USERDOMAIN?.trim(),n=process.env.COMPUTERNAME?.trim(),t=process.env.USERNAME?.trim()||g.userInfo().username;return e&&e.toUpperCase()!=="WORKGROUP"?`${e}\\${t}`:n?`${n}\\${t}`:t}function Oe(e){if(f()==="win32"&&he(e.command)){const n=[e.command,...e.args].map(W).join(" ");return{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",`"${n}"`],windowsVerbatimArguments:!0}}return{command:e.command,args:e.args}}function Ue(e,n,t=process.env){return{detached:!0,stdio:["ignore",n,n],env:t,windowsHide:!0,...e.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}}}function Be(){const e=h();s.writeFileSync(D,fe(e,d)),s.writeFileSync(b,ge(D)),z(),Y();const n=Se({userId:We(),command:l.join(process.env.SystemRoot||"C:\\Windows","System32","wscript.exe"),arguments:[W(b)]});return s.writeFileSync(P,`\uFEFF${n}`,"utf16le"),we({taskName:w,xmlPath:P},t=>{c(t,{stdio:"pipe",windowsHide:!0})})}function Fe(){ve(w,e=>{c(e,{stdio:"pipe",windowsHide:!0})})}function He(e={}){const n=H(),t=e.launch??h(),r=Object.entries(n).map(([i,m])=>` <key>${I(i)}</key>
|
|
3
3
|
<string>${I(m)}</string>`).join(`
|
|
4
4
|
`),o=[t.command,...t.args].map(i=>` <string>${I(i)}</string>`).join(`
|
|
5
5
|
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -27,8 +27,8 @@ ${r}
|
|
|
27
27
|
<key>StandardErrorPath</key>
|
|
28
28
|
<string>${d}</string>
|
|
29
29
|
</dict>
|
|
30
|
-
</plist>`}function Q(e=q){s.rmSync(e,{recursive:!0,force:!0})}function
|
|
31
|
-
`),r=[n.command,...n.args].map(
|
|
30
|
+
</plist>`}function Q(e=q){s.rmSync(e,{recursive:!0,force:!0})}function Me(e=f()){return e!=="darwin"?null:"macOS may show \u201CNode.js Foundation\u201D under Allow in the Background. This is the Node.js runtime used by Shennian Client."}const y=l.join(g.homedir(),".config/systemd/user/shennian.service");function Ge(){const e=H(),n=h(),t=Object.entries(e).map(([o,i])=>`Environment=${o}=${i}`).join(`
|
|
31
|
+
`),r=[n.command,...n.args].map(ye).join(" ");return`[Unit]
|
|
32
32
|
Description=Shennian Agent Daemon
|
|
33
33
|
After=network.target
|
|
34
34
|
|
|
@@ -41,6 +41,6 @@ StandardOutput=append:${d}
|
|
|
41
41
|
StandardError=append:${d}
|
|
42
42
|
|
|
43
43
|
[Install]
|
|
44
|
-
WantedBy=default.target`}const w="ShennianAgent";function
|
|
44
|
+
WantedBy=default.target`}const w="ShennianAgent";function Ve(e){c(e,{stdio:"pipe",windowsHide:!0})}function Z(){const e=process.getuid?.();if(typeof e=="number")return e;const n=g.userInfo();return typeof n.uid=="number"?n.uid:n.username}function _(e=Z()){return`gui/${e}/${L}`}function Je(e=Ve){const n=`gui/${Z()}`,t=_();try{return e(`launchctl enable "${t}"`),e(`launchctl bootout "${t}" 2>/dev/null || true`),e(`launchctl bootstrap "${n}" "${S}"`),e(`launchctl kickstart -k "${t}"`),e(`launchctl print "${t}"`),!0}catch{try{return e(`launchctl enable "${t}"`),e(`launchctl unload "${S}" 2>/dev/null || true`),e(`launchctl load -w "${S}"`),e(`launchctl kickstart -k "${t}"`),e(`launchctl print "${t}"`),!0}catch{return!1}}}function ee(e={}){s.mkdirSync(U,{recursive:!0});const n=u({cleanupStale:!0}),t=$(n);if(t)throw new Error(t);if(n.pid!==null&&n.running&&!j(n)){e.quiet||console.log(a.green(`\u2713 Background service already running (PID ${n.pid})`));return}ne(n);const r=s.openSync(d,"a"),o=Oe(h()),i=ue(o.command,o.args,Ue(o,r));i.unref(),s.closeSync(r),Ie(i.pid),e.quiet||(console.log(a.green(`\u2713 Background service started (PID ${i.pid})`)),console.log(a.gray(` Logs: ${d}`)))}function j(e,n=R(),t=O()){return e.pid===null||!e.running||e.launcher!=="global-cli"?!1:e.adopted===!0||n?.version!==t}function $(e){return e.pid===null||!e.running||e.launcher==="global-cli"?null:`unsupported_daemon_source:${e.launcher}`}function N(e=f()){switch(e){case"darwin":return s.existsSync(S)&&!s.existsSync(q);case"linux":return s.existsSync(y);case"win32":return s.existsSync(D)&&s.existsSync(b)&&s.existsSync(P)}}function Ke(e,n,t,r=R(),o=O()){return!n.api?.trim()&&e.pid!==null&&e.running&&e.launcher==="global-cli"&&!e.stale&&!e.remoteAccessDisabled&&t&&!j(e,r,o)}function ne(e=u({cleanupStale:!0})){if(!j(e)||e.pid===null)return;let n;try{process.kill(e.pid,"SIGTERM"),F(e.pid,5e3)||(process.kill(e.pid,"SIGKILL"),F(e.pid,2e3))}catch(t){n=t}if(k(e.pid)){const t=n instanceof Error?n.message:"daemon_stop_timeout";throw new Error(`daemon_replacement_failed: ${t}`)}try{R()?.pid===e.pid&&s.unlinkSync(E)}catch{}}function te(e={}){if(s.mkdirSync(U,{recursive:!0}),!x())return!1;const n=f();switch(h().mode==="direct"&&Ee(M)&&console.warn(a.yellow("\u26A0 Warning: Current CLI path is temporary (npx). Auto-start may not work after reboot.\n Run `npm install -g shennian@latest` for reliable auto-start.")),n){case"darwin":{const r=l.dirname(S);s.mkdirSync(r,{recursive:!0}),Q(),s.writeFileSync(S,He());const o=Je(),i=Me(n);return!e.quiet&&i&&console.log(a.gray(`\u2139 ${i}`)),o}case"linux":{const r=l.dirname(y);s.mkdirSync(r,{recursive:!0}),s.writeFileSync(y,Ge());try{c("systemctl --user daemon-reload && systemctl --user enable shennian",{stdio:"pipe",windowsHide:!0})}catch{return!1}try{c(`loginctl enable-linger ${g.userInfo().username}`,{stdio:"pipe",windowsHide:!0})}catch{}try{return c("systemctl --user restart shennian",{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}case"win32":return Be()}}function qe(){const n=u({cleanupStale:!0}).pid;if(n===null)return{};if(!k(n)){try{s.unlinkSync(E)}catch{}return{stalePid:n}}try{return process.kill(n,"SIGTERM"),{stoppedPid:n}}catch(t){return{error:t instanceof Error?t.message:String(t)}}}async function re(e=5e3){const n=qe();if(!n.stoppedPid)return n;if(!await C(n.stoppedPid,e))try{if(process.kill(n.stoppedPid,"SIGKILL"),!await C(n.stoppedPid,2e3))return{...n,error:"daemon_stop_timeout"}}catch(r){return{...n,error:r instanceof Error?r.message:String(r)}}try{s.unlinkSync(E)}catch{}if(De(),be()){for(const r of Ae())if(r!==n.stoppedPid)try{process.kill(r,"SIGTERM"),await C(r,2e3)}catch{}}return n}function Xe(e={}){const n=Pe();try{const t=u({cleanupStale:!0}),r=$(t);if(r)throw new Error(r);J(K(e.api)),$e(),ne(t),te({quiet:e.json})||ee({quiet:e.json});const i=t.running?t.instanceId:void 0,m=A(()=>u({cleanupStale:!0}),{excludedInstanceId:i});if(!ke(m,i))throw new Error("daemon_start_failed");e.json?p(m):console.log(a.green("\u2713 Background service started"))}catch(t){n&&V(B,new Date().toISOString()),process.exitCode=1;const r=t instanceof Error?t.message:String(t);e.json?p({...u(),error:r}):console.error(a.red(`Background service did not start: ${r}`))}}async function Ye(e={}){const n=_e(),t=je(),r=await re(),o=u({cleanupStale:!0}),i=r.error??n.autoStartError??t.error??(o.running?"daemon_stop_failed":o.remoteAccessDisabled?void 0:"remote_access_pause_failed");if(i&&(process.exitCode=1),e.json){p(i?{...o,error:i}:o);return}i?console.error(a.red(`\u2717 Failed to stop completely: ${i}`)):console.log(a.green("\u2713 Background service stopped"))}function oe(e){const n=u({cleanupStale:!0});if(Ke(n,e,N())){e.json?p(n):console.log(a.green(`\u2713 Background service already running (PID ${n.pid})`));return}xe(),Xe(e)}async function T(e={}){const n=u({cleanupStale:!0}),t=$(n);if(t){process.exitCode=1,e.json?p({...n,error:t}):console.error(a.red(`Background service was not stopped: ${t}`));return}await Ye(e)}async function C(e,n=5e3){const t=Date.now();for(;Date.now()-t<n;){if(!k(e))return!0;await new Promise(r=>setTimeout(r,100))}return!k(e)}async function ze(e={}){const n=u({cleanupStale:!0}),t=$(n);if(t){process.exitCode=1,e.json?p({...n,error:t}):console.error(a.red(`Background service was not restarted: ${t}`));return}if(n.remoteAccessDisabled){e.json?p({...n,error:"remote_access_disabled_use_shennian_start"}):console.error(a.yellow("Remote access is paused. Run `shennian start` on this computer to resume."));return}J(K(e.api));const r=f();r==="win32"&&Fe();const o=await re();if(o.error){e.json?p({...u(),error:o.error}):console.error(a.red(`\u2717 Failed to stop: ${o.error}`));return}if(o.stoppedPid!==void 0?e.json||console.log(a.green(`\u2713 Background service stopped (PID ${o.stoppedPid})`)):o.stalePid!==void 0?e.json||console.log(a.yellow(`\u26A0 Service process no longer exists, cleaned up stale PID ${o.stalePid}`)):e.json||console.log(a.gray("\u25CF Background service not running, starting it now")),(r==="linux"||r==="win32")&&te()){e.json&&p(A(()=>u({cleanupStale:!0})));return}ee({quiet:e.json}),e.json&&p(A(()=>u({cleanupStale:!0})))}function se(e={}){const n={...u(),client:ae()};if(e.json){p(n);return}if(n.pid===null){console.log(a.gray("\u25CF Background service not running"));return}n.running?(console.log(a.green(`\u25CF Background service running (PID ${n.pid})`)),console.log(a.gray(` Logs: ${d}`))):console.log(a.yellow(`\u25CF Background service stopped (PID ${n.pid} is stale)`))}function ie(e){if(!s.existsSync(d)){console.log(a.gray("No logs yet"));return}try{const n=c(g.platform()==="win32"?`powershell Get-Content -Tail ${e.lines} "${d}"`:`tail -n ${e.lines} "${d}"`,{encoding:"utf-8",windowsHide:!0});process.stdout.write(n)}catch{const n=s.readFileSync(d,"utf-8").split(`
|
|
45
45
|
`).slice(-e.lines);console.log(n.join(`
|
|
46
|
-
`))}}async function
|
|
46
|
+
`))}}async function Qe(){switch(await T(),f()){case"darwin":{if(s.existsSync(S)){try{c(`launchctl unload -w "${S}"`,{stdio:"pipe",windowsHide:!0})}catch{}s.unlinkSync(S)}Q(),console.log(a.green("\u2713 Auto-start uninstalled (launchd)"));break}case"linux":{try{c("systemctl --user disable --now shennian",{stdio:"pipe",windowsHide:!0})}catch{}if(s.existsSync(y)){s.unlinkSync(y);try{c("systemctl --user daemon-reload",{stdio:"pipe",windowsHide:!0})}catch{}}console.log(a.green("\u2713 Auto-start uninstalled (systemd)"));break}case"win32":{Y();try{s.unlinkSync(D)}catch{}try{s.unlinkSync(b)}catch{}try{s.unlinkSync(P)}catch{}z(),console.log(a.green("\u2713 Auto-start uninstalled (Task Scheduler)"));break}}}function Sn(e){e.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>oe(r)),e.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(r=>T(r)),e.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>se(r)),e.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>ie({lines:parseInt(r.lines,10)}));const n=e.command("daemon",{hidden:!0}).description("Deprecated: use top-level start/stop/status/logs"),t=(r,o)=>{o||console.error(a.yellow(`\u26A0 Deprecated command. Use \`shennian ${r}\` instead.`))};n.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("start",r.json),oe(r)}),n.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(async r=>{t("stop",r.json),await T(r)}),n.command("restart").description("Restart the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("stop && shennian start",r.json),ze(r)}),n.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>{t("status",r.json),se(r)}),n.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>{t("logs"),ie({lines:parseInt(r.lines,10)})}),n.command("uninstall").description("Uninstall auto-start service").action(Qe)}export{Ue as buildDaemonSpawnOptions,He as buildMacLaunchdPlist,Ge as buildSystemdUnit,yn as buildWindowsLauncherCommand,wn as buildWindowsScheduledTaskCommands,vn as buildWindowsScheduledTaskSuspendCommands,kn as buildWindowsScheduledTaskXml,Dn as buildWindowsStartupVbs,Ke as canReuseRunningDaemonForStart,Jn as captureEnvForService,Tn as clearDaemonLauncher,jn as clearDaemonPidIfOwner,Rn as clearRemoteAccessDisabled,Ln as createDaemonInstanceId,Wn as findRunningDaemonProcessIds,xn as getCurrentProcessDaemonLauncher,Fn as getDaemonStatus,_ as getLaunchdServiceTarget,Me as getMacBackgroundItemNotice,$ as getUnsupportedDaemonSourceError,$n as inferDaemonLauncherFromCommand,te as installService,N as isAutoStartServicePresent,Gn as isEphemeralCliPath,On as isIsolatedDaemonE2eInstance,En as isRemoteAccessDisabled,Mn as isSafeSnapshotEnvKey,In as isShennianRunServiceCommand,_e as prepareRemoteAccessPause,Cn as recordStartedDaemon,Sn as registerDaemonCommand,Je as reloadLaunchdAgent,Q as removeLegacyMacBackgroundApp,Vn as resolveServiceLaunchSpec,Kn as saveEnvSnapshot,Un as shouldDiscoverGlobalDaemonProcesses,Bn as shouldInstallPlatformService,j as shouldReplaceRunningDaemon,ee as startDaemonProcess,je as stopPreparedRemoteAccessService,bn as suspendWindowsScheduledTask,Nn as writeDaemonLauncher,_n as writeDaemonPid};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{buildQueueDiagnostics as o}from"../session/queue-diagnostics.js";import{readQueue as n}from"../session/queue-storage.js";function r(t){t.command("queue").description("Inspect messages waiting to be delivered to local AI tools").command("status").description("Show which messages are waiting and why (read-only, never prints message text)").option("--json","Print JSON (default)").action(()=>{try{const e=o(n());console.log(JSON.stringify({ok:!0,command:"queue.status",result:{...e,notes:{delivery:"waiting = not attempted yet; retrying = failed but retried automatically; blocked = kept until the cause (see block.whatToDo) is fixed; handed_to_codex_desktop = queued inside Codex Desktop.",workDirStatus:"Anything other than ok means the message cannot be delivered until that directory is back."}}},null,2))}catch(e){console.log(JSON.stringify({ok:!1,command:"queue.status",error:"queue_unreadable",message:e instanceof Error?e.message:String(e),nextAction:"Check that the current user owns the Shennian data directory and run shennian status --json. Do not delete the queue file."},null,2)),process.exitCode=1}})}export{r as registerQueueCommand};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import b from"node:crypto";import U from"node:fs";import
|
|
2
|
-
`)}catch(a){if(a instanceof
|
|
3
|
-
`),e.fail()}export{
|
|
1
|
+
import b from"node:crypto";import U from"node:fs";import R from"node:path";import{PublicAttachmentCache as j}from"../room/public-attachment-cache.js";import{PublicRoomClient as k,PublicRoomClientError as S}from"../room/public-room-client.js";import{callDaemonIpc as D}from"../daemon-ipc/client.js";import{DaemonIpcError as q}from"../daemon-ipc/protocol.js";import{MANAGED_ROOM_IPC_ROOT_ENV as N,resolveManagedRoomIpcPaths as P}from"../daemon-ipc/paths.js";import{MANAGED_ROOM_CONTEXT_ENV as L}from"../room/managed-context.js";import{createRoomInviteQr as $}from"../room/invite-qr.js";import{externalRoomNextAction as I,managedRoomNextAction as C}from"../room/room-error-guidance.js";const T={write:e=>{process.stdout.write(e)},fail:()=>{process.exitCode=1}};function oe(e,t={}){const o=t.client??new k,a=t.cache??new j({client:o}),s=t.io??T,u=t.createInviteQr??$,c=e.command("room").description("Use one explicitly referenced Shennian Room");c.command("schedule").description("Manage scheduled work in the current managed conversation").requiredOption("--operation <operation>","list/create/update/pause/resume/delete").option("--id <id>").option("--version <version>").option("--operation-id <operationId>").option("--time-description <timeDescription>").option("--timezone <timezone>").option("--prompt <prompt>").action(async r=>p("room.schedule",s,async()=>{const n=h();return n||i("managed_room_context_required","Scheduling is only available in managed Room context.",I()),v(n,"schedule",{...r,version:r.version?Number(r.version):void 0})})),c.command("create").description("Create a Room as the paired user").requiredOption("--name <name>","Room name").action(async r=>p("room.create",s,async()=>{w("create");const n=r.name.trim();(!n||n.length>80)&&i("invalid_room_name","Room name must contain 1 to 80 characters.");const m=await o.create(n),d=_(m.room,"invalid_room_response");typeof d.inviteUrl!="string"&&i("invalid_room_response","Shennian returned an invalid Room invitation.");const f=await u(d.inviteUrl).catch(()=>({imagePath:null,mimeType:"image/png",payload:d.inviteUrl}));return{...m,sharing:{inviteUrl:d.inviteUrl,inviteQr:f}}})),c.command("join <invite-url>").description("Join or request access through an official Room invitation").option("--message <message>","Introduction and reason required when owner approval is enabled").action(async(r,n)=>p("room.join",s,async()=>{w("join");const m=A(r,"invite"),d=n.message?.trim();return d&&d.length>500&&i("join_message_too_long","Join request message must be at most 500 characters."),o.join(m.roomId,m.inviteToken,d)})),c.command("open <room-url>").description("Open one Room where the paired user is already a member").action(async r=>p("room.open",s,async()=>{w("open");const n=A(r,"stable");return o.open(n.roomId)})),c.command("status [room-ref]").description("Show the managed Room, or one explicitly referenced Room").action(async r=>p("room.status",s,()=>{const n=h();return n?(r&&i("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(n,"status",{})):o.status(x(r))})),c.command("read [room-ref]").description("Read recent, older, or newer messages from one Room").option("--before <sequence>","Read messages before this sequence").option("--after <sequence>","Read messages after this sequence").option("--limit <count>","Maximum messages, 1 to 50","50").action(async(r,n)=>{await p("room.read",s,async()=>{n.before&&n.after&&i("ambiguous_sequence_cursor","--before and --after are mutually exclusive."),n.before&&!z(n.before)&&i("invalid_sequence","--before sequence is invalid."),n.after&&!z(n.after)&&i("invalid_sequence","--after sequence is invalid.");const m=Number(n.limit);(!Number.isInteger(m)||m<1||m>50)&&i("invalid_limit","--limit must be between 1 and 50.");const d=h();if(d)return r&&i("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(d,"read",{...n.before?{before:n.before}:{},...n.after?{after:n.after}:{},limit:m});const f=x(r),y=await o.read(f,{before:n.before,after:n.after,limit:m});return Q(y,f,a)})}),c.command("send [room-ref]").description("Send text and up to 10 files as the paired user").option("--text <text>","Message text").option("--file <path>","Local file path; repeat for multiple files",E,[]).action(async(r,n)=>{await p("room.send",s,async()=>{const m=n.text?.trim()??"";!m&&n.file.length===0&&i("room_message_empty","Provide --text or at least one --file."),n.file.length>10&&i("room_attachments_too_many","A message can contain at most 10 files.");const d=h();if(d)return r&&i("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(d,"send",{clientMessageId:`managed:${b.randomUUID()}`,text:m,files:n.file});const f=x(r),y=[];for(const O of n.file)y.push(await F(o,f,O));return o.send(f,{clientMessageId:`cli:${b.randomUUID()}`,...m?{text:m}:{},...y.length>0?{attachmentIds:y}:{}})})}),c.command("pause").description("Pause the current managed Agent in its bound Room").requiredOption("--reason <reason>","Short reason shown to all Room members").action(async r=>p("room.pause",s,()=>{const n=h();return n||i("managed_room_context_required","Pause is only available in managed Room context.",I()),v(n,"pause",{reason:r.reason})})),c.command("attachment").description("Download Room attachments through Shennian").command("get [room-ref] [attachment-id]").description("Download and verify one Room attachment").action(async(r,n)=>{await p("room.attachment.get",s,async()=>{const m=h(),d=m?r:n;return(!d||!/^ratt_[A-Za-z0-9_-]{1,191}$/.test(d))&&i("invalid_attachment_ref","attachment-id is invalid."),m?v(m,"attachment.get",{attachmentId:d}):a.materialize(x(r),d)})}),c.command("leave <room-ref>").description("Leave one explicitly referenced Room").action(async r=>p("room.leave",s,()=>(w("leave"),o.leave(M(r))))),c.command("list",{hidden:!0}).action(()=>g(s,"command_removed","Room listing is not available to Agents.",null)),c.command("search",{hidden:!0}).allowUnknownOption(!0).action(()=>g(s,"command_removed","Room search is not available to Agents.",null)),c.command("agent",{hidden:!0}).allowUnknownOption(!0).action(()=>g(s,"command_removed","Managed Agents are created in the Shennian mobile App.",null))}async function p(e,t,o){try{const a=await o();t.write(`${JSON.stringify({ok:!0,command:e,result:a})}
|
|
2
|
+
`)}catch(a){if(a instanceof S){g(t,a.code,a.message,a.nextAction);return}if(a instanceof q){g(t,a.code,a.message,C(a.code));return}g(t,"room_command_failed","Shennian Room command failed.",null)}}function h(){return process.env[L]?.trim()||null}async function v(e,t,o){const a=process.env[N]?.trim();if(!a||!R.isAbsolute(a))throw new q("managed_room_context_unavailable","Managed Room IPC context is unavailable.");return D({method:"managed-room.execute",params:{context:e,action:t,...o},paths:P(a),timeoutMs:t==="send"||t==="attachment.get"?18e4:15e3})}function w(e){h()&&i("managed_room_action_forbidden",`${e} is not available in managed Room context.`)}function x(e){return e||i("room_ref_required","Use an official Room URL returned by Shennian.",I()),M(e)}function M(e){return A(e,"stable").roomId}function A(e,t){let o;const a=t==="invite"?"invalid_invite_url":"invalid_room_ref",s=t==="invite"?"Use an official Shennian Room invitation URL.":"Use an official Room URL returned by Shennian.";try{o=new URL(e)}catch{i(a,s)}const u=o.pathname.match(/^\/spaces\/([A-Za-z0-9_-]{1,191})$/),c=o.searchParams.get("invite");return(o.protocol!=="https:"||o.hostname!=="app.shennian.net"||o.port||o.username||o.password||o.hash||!u||o.searchParams.has("access")||[...o.searchParams.keys()].some(l=>l!=="invite")||t==="stable"&&c!=null||t==="invite"&&(c==null||!/^[A-Za-z0-9_-]{32,256}$/.test(c)))&&i(a,s),{roomId:u[1],...c?{inviteToken:c}:{}}}function z(e){return/^(0|[1-9]\d{0,19})$/.test(e)}function E(e,t){return[...t,e]}async function F(e,t,o){const a=R.resolve(o);let s;try{s=await U.promises.lstat(a)}catch{i("file_not_found",`File does not exist: ${o}`)}(!s.isFile()||s.isSymbolicLink())&&i("invalid_file",`Not a regular file: ${o}`),(s.size<1||s.size>100*1024*1024)&&i("invalid_file_size","Each file must be between 1 byte and 100 MB.");const u=await U.promises.readFile(a),c=b.createHash("sha256").update(u).digest("hex"),l=J(a),r=await e.initializeAttachment(t,{clientUploadId:`cli:${b.randomUUID()}`,name:R.basename(a),mediaKind:l.startsWith("image/")?"image":l.startsWith("audio/")?"audio":"file",mimeType:l,byteSize:s.size,sha256:c}),n=_(r.attachment,"invalid_attachment_response"),m=_(r.upload,"invalid_attachment_response");(typeof n.id!="string"||typeof m.url!="string"||m.method!=="PUT")&&i("invalid_attachment_response","Shennian returned an invalid attachment response.");const d=_(m.headers,"invalid_attachment_response");return Object.values(d).some(f=>typeof f!="string")&&i("invalid_attachment_response","Shennian returned invalid upload headers."),H(m.url),await e.upload(m.url,d,u),await e.completeAttachment(t,n.id),n.id}function J(e){const t=R.extname(e).toLowerCase();return{".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".heic":"image/heic",".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".mp4":"video/mp4",".mov":"video/quicktime",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".zip":"application/zip",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t]??"application/octet-stream"}function Q(e,t,o){return Array.isArray(e.messages)||i("invalid_server_response","Shennian returned invalid messages."),{messages:e.messages.map(a=>{const s=_(a,"invalid_server_response"),u=Array.isArray(s.attachments)?s.attachments:[];return{...s,attachments:u.map(c=>{const l=_(c,"invalid_server_response");return(typeof l.attachmentId!="string"||typeof l.name!="string"||typeof l.mimeType!="string"||typeof l.byteSize!="string"||typeof l.sha256!="string")&&i("invalid_server_response","Shennian returned invalid attachment metadata."),{...l,...o.lookup(t,l)}})}})}}function _(e,t){return(!e||typeof e!="object"||Array.isArray(e))&&i(t,"Invalid structured response."),e}function H(e){let t;try{t=new URL(e)}catch{i("invalid_attachment_response","Invalid upload URL.")}const o=t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1");(t.protocol!=="https:"&&!o||t.username||t.password||t.hash)&&i("invalid_attachment_response","Invalid upload URL.")}function i(e,t,o=null){throw new S(e,t,o)}function g(e,t,o,a){e.write(`${JSON.stringify({ok:!1,error:t,message:o,nextAction:a})}
|
|
3
|
+
`),e.fail()}export{oe as registerRoomCommand};
|
package/dist/src/config/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"node:fs";import i from"node:path";import
|
|
2
|
-
`;if(e.mkdirSync(o,{recursive:!0,mode:448}),process.platform!=="win32"&&e.chmodSync(o,448),process.platform==="win32"){e.writeFileSync(r,
|
|
1
|
+
import e from"node:fs";import{renameSyncWithRetry as u}from"../fs/atomic-rename.js";import i from"node:path";import p from"node:os";import a from"node:crypto";function c(){const n=process.env.SHENNIAN_HOME?.trim();return n?i.resolve(n):d()?i.join(p.tmpdir(),"shennian-vitest-runtime",`${process.pid}-${process.env.VITEST_WORKER_ID??"main"}`):i.join(p.homedir(),".shennian")}function s(...n){return i.join(c(),...n)}function f(){return s("config.json")}const x=f();function E(n){return n===void 0||n==="patch"?"patch":"none"}function N(){try{const n=f();if(!e.existsSync(n))return{};const o=JSON.parse(h(e.readFileSync(n,"utf-8")));return o.serverUrl?.includes("shennian.ai")&&(o.serverUrl="https://shennian.net"),o}catch{return{}}}function I(n){const o=c(),r=f(),m=`${JSON.stringify(n,null,2)}
|
|
2
|
+
`;if(e.mkdirSync(o,{recursive:!0,mode:448}),process.platform!=="win32"&&e.chmodSync(o,448),process.platform==="win32"){e.writeFileSync(r,m,{encoding:"utf8",mode:384});return}const t=`${r}.tmp-${process.pid}-${a.randomBytes(6).toString("hex")}`;try{e.writeFileSync(t,m,{encoding:"utf8",mode:384,flag:"wx"}),e.chmodSync(t,384),u(t,r),e.chmodSync(r,384)}finally{try{e.unlinkSync(t)}catch{}}}function w(){e.mkdirSync(c(),{recursive:!0,mode:448}),e.mkdirSync(s("sessions"),{recursive:!0,mode:448}),process.platform!=="win32"&&(e.chmodSync(c(),448),e.chmodSync(s("sessions"),448))}function d(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}function h(n){return n.charCodeAt(0)===65279?n.slice(1):n}export{x as configPath,w as ensureDir,f as getConfigPath,c as getShennianDir,N as loadConfig,E as normalizeAutoUpgradePolicy,s as resolveShennianPath,I as saveConfig};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import S from"node:fs";const s=new Set(["EPERM","EBUSY","EACCES"]),E=[10,20,40,80,160,320,640];function i(t){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}function p(t,a,e={}){const f=e.platform??process.platform;for(let r=0;;r+=1)try{S.renameSync(t,a);return}catch(n){const o=n.code,c=E[r];if(f!=="win32"||!o||!s.has(o)||c===void 0)throw n;(e.sleep??i)(c)}}export{p as renameSyncWithRetry};
|
package/dist/src/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{registerScheduleCommand as Se}from"./commands/schedule.js";import{resolvePersonalScheduleContext as ye}from"./schedules/personal-context.js";import{executeServerSchedule as oe,deliverServerSchedule as we}from"./schedules/server-client.js";import{Command as Ce}from"commander";import
|
|
2
|
-
`),process.exitCode=1}function Jo(a){const s=[`trigger=${a.trigger??"unknown"}`,`phase=${a.phase}`,`code=${a.code??"unknown"}`,`attempt=${a.reconnectAttempt}`];return a.reason&&s.push(`reason=${a.reason}`),a.error&&s.push(`error=${a.error}`),s.join(" ")}const i=new Ce;i.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(z),i.enablePositionalOptions(),Je(i),Ke(i),Se(i),i.option("--api <url>","Server URL override").option("--name <name>","Machine name",be.hostname()).action(async a=>{const s=p(),g=a.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??void 0;await Me(g,a.name)}),i.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async a=>{const s=G("env.json");try{const e=JSON.parse(F.readFileSync(s,"utf-8"));for(const[n,o]of Object.entries(e))process.env[n]||(process.env[n]=o);le()}catch{}Te(ne(process.env,p()));const g=uo();ae()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(g),process.exit(0));const c=xe(),y=so({lockPath:Go,instanceId:c});y.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(y.ownerPid?` (PID ${y.ownerPid})`:"")+", skipping duplicate start"),clearInterval(g),process.exit(0));try{const e=Wo();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),y.release(),process.exit(0)}catch{}}catch{}const K=Ve(process.env,fe)?[]:$e(process.pid);K.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${K[0]}), skipping duplicate start`),y.release(),process.exit(0)),se(process.pid,c,{version:z}),ce(process.pid,void 0,c),process.on("exit",()=>{te(process.pid,c),re(c)}),process.on("exit",y.release);let O=null;try{O=to()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const D=await eo();if(D){O||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{ro({fromVersion:z,targetVersion:D.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:D.jobId},{readiness:O}),console.error(`[upgrade] New version crashed ${D.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{jo()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const m=p(),u=a.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??m.serverUrl??W.cn.url,h=de(),l=await io({serverUrl:u,authToken:m.machineToken??m.accessToken}),w=l.map(e=>e.type),V=N(l),f=new Co,U=new Ro,C=new No(f),I=new bo(u),ve=new xo({actionClient:I}),Ie=new $o({actionClient:I});let S=null,r;const q=Oo({authority:C,actionClient:I,attachmentCache:ve,attachmentUploader:Ie,observations:U,getMachineCredentials:()=>({machineToken:p().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),scheduleExecutor:(e,n,o)=>oe({serverUrl:u,machineToken:p().machineToken,sessionId:e,action:n,args:o}),onPaused:({registryKey:e,sessionId:n})=>{const t=f.getByRegistryKey(e)?.binding;t&&f.setBinding({registryKey:e,bindingId:t.bindingId,roomId:t.roomId,agentIdentityId:t.agentIdentityId,agentMembershipId:t.agentMembershipId,status:"paused",activationMode:"paused"}),C.revokeSession(e),r?.discardPendingManagedRoomMessages(n)}});let L=null,j=null,H=null;const b=await me({paths:fo(),handlers:{...vo({daemonVersion:h,protocolVersion:wo,getStatus:()=>ie(),getAgents:()=>l,completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),startUpgrade:async e=>{if(!L)throw new Error("upgrade_unavailable");return L(e)},prepareExternalUpgrade:e=>{if(!j)throw new Error("external_upgrade_unavailable");return j(e)},cancelExternalUpgrade:()=>{if(!H)throw new Error("external_upgrade_unavailable");return H()}}),...Io({getStatus:()=>ie(),getSnapshot:()=>N(l).map(e=>{const n=l.find(o=>o.type===e.type);return{...e,runtimePlatform:n?.runtimePlatform,runtimeIsWsl:n?.runtimeIsWsl}}),discover:async e=>{if(!r)throw new Error("daemon_starting");const n=await So(!0,e);if(e){const t=l.filter(A=>A.type!==e);l.splice(0,l.length,...t,...n.detectedAgents)}else l.splice(0,l.length,...n.detectedAgents);const o=N(l);return d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:l.map(t=>t.type),agents:o}}),n.agents.map(t=>{const A=n.detectedAgents.find(B=>B.type===t.type);return{...t,runtimePlatform:A?.runtimePlatform,runtimeIsWsl:A?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return yo(e,{ignoreNativeSession:(n,o)=>R?.ignoreNativeSource(n,o)})}})}});let k;try{k=await me({paths:ho(),handlers:{"managed-room.execute":e=>q(e),"schedule.personal":async e=>{const n=e,o=ye(n?.context);if(f.getByNianSessionId(o)?.binding)throw new Error("schedule_personal_context_required");return await oe({serverUrl:u,machineToken:p().machineToken,sessionId:o,action:n.operation,args:n})}}})}catch(e){throw await b.close(),e}let Y=!1;const M=()=>{Y||(Y=!0,Promise.allSettled([b.close(),k.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",M),process.once("SIGTERM",M),!m.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([b.close(),k.close()]),process.exitCode=1;return}process.removeListener("SIGINT",M),process.removeListener("SIGTERM",M);const Q=`${zo(u)}/relay/machine`,_=m.machineToken;if(!_)return;try{await Lo({serverUrl:u,machineToken:_,machineId:m.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([b.close(),k.close()]),process.exit(1)}m.machineId&&lo(u,m.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${Q}... (v${h}) agents: ${w.join(",")}`),T({level:"info",wsEvent:"daemon.start",metadata:{version:h,agents:w}});let R=null,P=null,x=0,v=oo();const Z=Ae(m.autoUpgrade),d=new Ee({serverUrl:Q,machineToken:_,cliVersion:h,agentList:w,autoUpgradePolicy:Z,sessionSyncProtocolVersion:pe,sessionSyncCapabilities:ge,daemonInstallationId:Vo(),dataEpoch:ue,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),T({level:"info",wsEvent:"daemon.connected"}),V.some(o=>o.models.length>0)&&d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:V}}),co(l,{serverUrl:m.serverUrl??u,authToken:m.machineToken??m.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(V)&&d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:o}})}).catch(()=>{}),v&&d.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:v.from,to:v.to,...v.jobId?{jobId:v.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),$.start(),P?.start();const e=++x,n=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),v){const o=v;v=null,o.jobId&&ao(o.jobId,o.to),Xe(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),mo({kind:"upgrade",result:o.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),d.sendEvent({type:"event",event:"upgrade",payload:{state:o.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:o.from,to:o.to,...o.jobId?{jobId:o.jobId}:{}}}),o.operation!=="rollback"&&d.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:o.from,to:o.to}})}e===x&&d.getState()==="connected"&&R?.handleConnected()}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===x&&d.getState()==="connected"){if(o instanceof Bo)return;const t=o instanceof Ho?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{n()},t).unref?.()}}};n()},onDisconnected:e=>{x+=1,r?.revokeProjectFsHandles(),P?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${Jo(e)}`),T({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||r?.revokeProjectFsHandles()},onReq:e=>{if(console.log(`[${new Date().toISOString()}] [req] ${e.method}`),T({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),e.method==="room.message.deliver"){Ao(d,P,e);return}r.handleReq(e)}});R=po()?new go(d):null,P=new Po({registry:f,observations:U,actionClient:I,getMachineCredentials:()=>({machineToken:p().machineToken}),isSessionDeleted:e=>new Eo().hasSession(e),onMessages:async(e,n,o,t)=>{await S?.processMessages(e,n,o,t)},onBindingPaused:e=>{C.revokeSession(e.registryKey),e.lifecycleState==="closed"?r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")}):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const $=new no({currentVersion:h,machineId:m.machineId??"unknown-machine",serverUrl:m.serverUrl??u,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:pe,dataEpoch:ue,advertisedCapabilities:ge,updaterProtocolVersion:1,startUpgrade:async(e,n)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(d,"auto-upgrade",e,{currentVersion:h,prepareForUpgrade:t=>r.prepareForUpgrade(t),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:n?void 0:()=>r.getUpgradeIdleState().idle})}});$.setPolicy(Z),r=new qe(d,R,h,$,new ko({registry:f,observations:U,bindingClient:I,getMachineCredentials:()=>{const e=p();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${c}`}),{prepare:()=>Ne(),isDisabled:()=>ae(),shutdownAfterResponse:()=>{setTimeout(()=>{Oe(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>C.revokeToken(e),q,null,Ye(_),()=>N(l)),L=async e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof n.targetVersion=="string"?n.targetVersion:void 0,t=n.confirmedMajor===!0;return await Ge(d,`local-upgrade-${Date.now()}`,o,{currentVersion:h,confirmedMajor:t,prepareForUpgrade:B=>r.prepareForUpgrade(B),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},j=e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=`desktop-${(typeof n.targetVersion=="string"?n.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:t,...r.prepareForUpgrade(t)}},H=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),S=new Uo({registry:f,observations:U,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const n=p().machineToken?.trim(),o=e.binding;if(!n||!o)throw new Error("managed_room_context_unavailable");const t=await I.status({machineToken:n,roomId:o.roomId,bindingId:o.bindingId});if(!Do(f,e)||!To(e,t))throw new Error("managed_room_binding_unavailable");return{roomName:t.room.name,memberCount:t.room.memberCount,members:t.room.members,agentsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent}:{},agentSystemPromptsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,n,o)=>{const t=p().machineToken;if(!t)throw new Error("machine_not_authorized");return C.issue({registryKey:e,machineCredential:t,activationCauseMessageId:n,allowedActions:o})},audit:new _o,resolveManagedAgentPolicy:e=>Mo({...e,runtime:l.find(n=>n.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>we({serverUrl:u,machineToken:p().machineToken,req:e,client:d,queue:r.getScheduleQueue(),registry:f}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(f.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await I.status({machineToken:p().machineToken,roomId:e.roomId,bindingId:e.bindingId});return o.status==="active"&&o.room.status==="active"?"ready":"ended"},r.setManagedRoomTurnPreparer(e=>S.prepareConversationTurn(e)),r.setManagedAgentDirectTurnPreparer((e,n)=>S.prepareDirectConversationTurn(e,n)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?S.prepareDirectConversationTurn(e.sessionId,{allowedRoomActions:[]}):e.source==="manager_event"?S.prepareDirectConversationTurn(e.sessionId,{allowedRoomActions:[],managerEvent:!0}):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:S.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),F.mkdirSync(fe,{recursive:!0}),se(process.pid,c,{version:h}),ce(process.pid,void 0,c),d.connect(),process.stdin.resume();let X=!1;const ee=async()=>{if(!X){X=!0,console.log(E.gray(`
|
|
3
|
-
Disconnecting...`)),T({level:"info",wsEvent:"daemon.stop"}),clearInterval(g);try{await r.cleanup()
|
|
1
|
+
import{registerScheduleCommand as Se}from"./commands/schedule.js";import{resolvePersonalScheduleContext as ye}from"./schedules/personal-context.js";import{executeServerSchedule as oe,deliverServerSchedule as we}from"./schedules/server-client.js";import{Command as Ce}from"commander";import A from"chalk";import Re from"node:os";import F from"node:fs";import{loadConfig as p,saveConfig as be,getConfigPath as ke,getShennianDir as Pe,resolveShennianPath as G,normalizeAutoUpgradePolicy as Ee}from"./config/index.js";import{CliRelayClient as Ae}from"./relay/client.js";import{collectKnownLogSecrets as ne,installCliLogRedaction as Te,sanitizeCliLogValue as De}from"./log-redaction.js";import{registerPairCommand as Ue,runSmartStart as _e}from"./commands/pair.js";import{registerLogoutCommand as Me}from"./commands/logout.js";import{clearDaemonPidIfOwner as te,createDaemonInstanceId as Ne,clearDaemonLauncher as re,findRunningDaemonProcessIds as xe,isRemoteAccessDisabled as ae,prepareRemoteAccessPause as Oe,stopPreparedRemoteAccessService as $e,isIsolatedDaemonE2eInstance as Ve,getDaemonStatus as ie,registerDaemonCommand as Le,writeDaemonPid as se,writeDaemonLauncher as ce}from"./commands/daemon.js";import{registerRuntimeCommand as je}from"./commands/runtime.js";import{registerAgentCommand as He}from"./commands/agent.js";import{registerManagerCommand as Be}from"./commands/manager.js";import{registerWorkerCommand as Fe}from"./commands/worker.js";import{handleUpgradeStart as Ge,registerUpgradeCommand as We}from"./commands/upgrade.js";import{registerToolsCommand as ze}from"./commands/tools.js";import{registerQueueCommand as Je}from"./commands/queue.js";import{registerIntegrationCommand as Ke}from"./commands/integration.js";import{registerRoomCommand as qe}from"./commands/room.js";import{SessionManager as Qe}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as Ye}from"./session/handlers/project-fs.js";import{SERVERS as W,regionToUrl as Ze,urlToRegion as Xe}from"./region.js";import{clearUpgradeAttempt as eo,getCurrentVersion as de,handleStartupCrashCheck as oo,readUpgradeAttempt as no}from"./upgrade/engine.js";import{AutoUpgradeScheduler as to}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as ro}from"./upgrade/updater-bootstrap.js";import{launchUpdater as ao,markUpdaterHealthy as io}from"./upgrade/updater-launcher.js";import{detectAgents as so}from"./agents/detect.js";import{augmentProcessPath as le}from"./env-path.js";import{acquireDaemonInstanceLock as co}from"./commands/daemon-instance-lock.js";le();const z=de();import{getCachedAgentInfos as O,resolveAgentInfos as lo}from"./agents/model-registry.js";import{initCliLogReporter as mo,reportLog as T,reportUpgradeAggregateMetric as po}from"./log-reporter.js";import{isNativeFusionEnabled as go}from"./native-fusion/config.js";import{NativeSessionFusionService as uo}from"./native-fusion/service.js";import{startDaemonLogRetention as fo}from"./daemon-log.js";import{startDaemonIpcServer as me}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as ho,resolveManagedRoomIpcPaths as vo}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as Io}from"./daemon-ipc/control.js";import{createAgentReadinessHandlers as So}from"./daemon-ipc/agent-readiness.js";import{scanMachineAgents as yo}from"./session/handlers/agents.js";import{validateAgentWorkspaceConfiguration as wo}from"./session/handlers/agent-workspace-validation.js";import{DAEMON_IPC_VERSION as Co}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as Ro}from"./room/session-registry.js";import{HttpRoomBindingClient as bo}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as ko}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Po}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Eo}from"./room/mirror-sync-service.js";import{handleLiveRoomDelivery as Ao}from"./room/live-delivery.js";import{NativeSourceDeletionStore as To}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as Do,isCurrentRegistration as Uo}from"./room/registration-authority.js";import{RoomActivationService as _o,resolveManagedAgentPolicy as Mo}from"./room/activation-service.js";import{RoomActivationAudit as No}from"./room/activation-audit.js";import{RoomAttachmentCache as xo}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Oo}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as $o}from"./room/managed-context.js";import{createManagedRoomExecutor as Vo}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as pe,SESSION_SYNC_ADVERTISED_CAPABILITIES as ge}from"@shennian/wire";import{getDaemonInstallationId as Lo}from"./session/store.js";import{OWNER_DIRECT_TURN_OPTIONS as jo}from"./session/queue-helpers.js";import{synchronizeMachinePersonalAuthority as Ho}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as ue,ensurePersonalDataEpoch as Bo}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as Fo,DeletionSyncTerminalError as Go}from"./session/deletion-sync-state.js";const fe=Pe(),Wo=G("daemon.pid"),zo=G("daemon.instance.lock");function Jo(){try{const a=F.readFileSync(Wo,"utf-8").trim();if(a.startsWith("{")){const g=JSON.parse(a),c=Number(g.pid);return Number.isInteger(c)&&c>0?c:null}const s=parseInt(a,10);return Number.isInteger(s)&&s>0?s:null}catch{return null}}function Ko(a){return a.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function J(){process.stdout.write(`${JSON.stringify({ok:!1,error:"integration_command_retired",message:"Room MCP and Hooks were retired. Use the Shennian Skill and CLI.",nextAction:{type:"open_install_guide",url:"https://shennian.net/install.md"}})}
|
|
2
|
+
`),process.exitCode=1}function qo(a){const s=[`trigger=${a.trigger??"unknown"}`,`phase=${a.phase}`,`code=${a.code??"unknown"}`,`attempt=${a.reconnectAttempt}`];return a.reason&&s.push(`reason=${a.reason}`),a.error&&s.push(`error=${a.error}`),s.join(" ")}const i=new Ce;i.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(z),i.enablePositionalOptions(),Ke(i),qe(i),Se(i),i.option("--api <url>","Server URL override").option("--name <name>","Machine name",Re.hostname()).action(async a=>{const s=p(),g=a.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??void 0;await _e(g,a.name)}),i.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async a=>{const s=G("env.json");try{const e=JSON.parse(F.readFileSync(s,"utf-8"));for(const[n,o]of Object.entries(e))process.env[n]||(process.env[n]=o);le()}catch{}Te(ne(process.env,p()));const g=fo();ae()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(g),process.exit(0));const c=Ne(),w=co({lockPath:zo,instanceId:c});w.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(w.ownerPid?` (PID ${w.ownerPid})`:"")+", skipping duplicate start"),clearInterval(g),process.exit(0));try{const e=Jo();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),w.release(),process.exit(0)}catch{}}catch{}const K=Ve(process.env,fe)?[]:xe(process.pid);K.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${K[0]}), skipping duplicate start`),w.release(),process.exit(0)),se(process.pid,c,{version:z}),ce(process.pid,void 0,c),process.on("exit",()=>{te(process.pid,c),re(c)}),process.on("exit",w.release);let $=null;try{$=ro()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const D=await oo();if(D){$||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{ao({fromVersion:z,targetVersion:D.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:D.jobId},{readiness:$}),console.error(`[upgrade] New version crashed ${D.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{Bo()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const m=p(),u=a.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??m.serverUrl??W.cn.url,h=de(),l=await so({serverUrl:u,authToken:m.machineToken??m.accessToken}),C=l.map(e=>e.type),V=O(l),f=new Ro,U=new Po,R=new $o(f),S=new bo(u),ve=new xo({actionClient:S}),Ie=new Oo({actionClient:S});let y=null,r;const q=Vo({authority:R,actionClient:S,attachmentCache:ve,attachmentUploader:Ie,observations:U,getMachineCredentials:()=>({machineToken:p().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),onSendOutcome:e=>r.noteManagedRoomSendOutcome(e),scheduleExecutor:(e,n,o)=>oe({serverUrl:u,machineToken:p().machineToken,sessionId:e,action:n,args:o}),onPaused:({registryKey:e,sessionId:n})=>{const t=f.getByRegistryKey(e)?.binding;t&&f.setBinding({registryKey:e,bindingId:t.bindingId,roomId:t.roomId,agentIdentityId:t.agentIdentityId,agentMembershipId:t.agentMembershipId,status:"paused",activationMode:"paused"}),R.revokeSession(e),r?.discardPendingManagedRoomMessages(n)}});let L=null,j=null,H=null;const b=await me({paths:ho(),handlers:{...Io({daemonVersion:h,protocolVersion:Co,getStatus:()=>ie(),getAgents:()=>l,completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),startUpgrade:async e=>{if(!L)throw new Error("upgrade_unavailable");return L(e)},prepareExternalUpgrade:e=>{if(!j)throw new Error("external_upgrade_unavailable");return j(e)},cancelExternalUpgrade:()=>{if(!H)throw new Error("external_upgrade_unavailable");return H()}}),...So({getStatus:()=>ie(),getSnapshot:()=>O(l).map(e=>{const n=l.find(o=>o.type===e.type);return{...e,runtimePlatform:n?.runtimePlatform,runtimeIsWsl:n?.runtimeIsWsl}}),discover:async e=>{if(!r)throw new Error("daemon_starting");const n=await yo(!0,e);if(e){const t=l.filter(I=>I.type!==e);l.splice(0,l.length,...t,...n.detectedAgents)}else l.splice(0,l.length,...n.detectedAgents);const o=O(l);return d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:l.map(t=>t.type),agents:o}}),n.agents.map(t=>{const I=n.detectedAgents.find(B=>B.type===t.type);return{...t,runtimePlatform:I?.runtimePlatform,runtimeIsWsl:I?.runtimeIsWsl}})},validate:async e=>{if(!r)throw new Error("daemon_starting");return wo(e,{ignoreNativeSession:(n,o)=>P?.ignoreNativeSource(n,o)})}})}});let k;try{k=await me({paths:vo(),handlers:{"managed-room.execute":e=>q(e),"schedule.personal":async e=>{const n=e,o=ye(n?.context);if(f.getByNianSessionId(o)?.binding)throw new Error("schedule_personal_context_required");return await oe({serverUrl:u,machineToken:p().machineToken,sessionId:o,action:n.operation,args:n})}}})}catch(e){throw await b.close(),e}let Q=!1;const _=()=>{Q||(Q=!0,Promise.allSettled([b.close(),k.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",_),process.once("SIGTERM",_),!m.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([b.close(),k.close()]),process.exitCode=1;return}process.removeListener("SIGINT",_),process.removeListener("SIGTERM",_);const Y=`${Ko(u)}/relay/machine`,M=m.machineToken;if(!M)return;try{await Ho({serverUrl:u,machineToken:M,machineId:m.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([b.close(),k.close()]),process.exit(1)}m.machineId&&mo(u,m.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${Y}... (v${h}) agents: ${C.join(",")}`),T({level:"info",wsEvent:"daemon.start",metadata:{version:h,agents:C}});let P=null,E=null,N=0,v=no();const Z=Ee(m.autoUpgrade),d=new Ae({serverUrl:Y,machineToken:M,cliVersion:h,agentList:C,autoUpgradePolicy:Z,sessionSyncProtocolVersion:pe,sessionSyncCapabilities:ge,daemonInstallationId:Lo(),dataEpoch:ue,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),T({level:"info",wsEvent:"daemon.connected"}),V.some(o=>o.models.length>0)&&d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:C,agents:V}}),lo(l,{serverUrl:m.serverUrl??u,authToken:m.machineToken??m.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(V)&&d.sendEvent({type:"event",event:"machine.agents",payload:{agentList:C,agents:o}})}).catch(()=>{}),v&&d.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:v.from,to:v.to,...v.jobId?{jobId:v.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),x.start(),E?.start();const e=++N,n=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),v){const o=v;v=null,o.jobId&&io(o.jobId,o.to),eo(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),po({kind:"upgrade",result:o.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),d.sendEvent({type:"event",event:"upgrade",payload:{state:o.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:o.from,to:o.to,...o.jobId?{jobId:o.jobId}:{}}}),o.operation!=="rollback"&&d.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:o.from,to:o.to}})}e===N&&d.getState()==="connected"&&P?.handleConnected()}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===N&&d.getState()==="connected"){if(o instanceof Go)return;const t=o instanceof Fo?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{n()},t).unref?.()}}};n()},onDisconnected:e=>{N+=1,r?.revokeProjectFsHandles(),E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${qo(e)}`),T({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||r?.revokeProjectFsHandles()},onReq:e=>{if(console.log(`[${new Date().toISOString()}] [req] ${e.method}`),T({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),e.method==="room.message.deliver"){Ao(d,E,e);return}r.handleReq(e)}});P=go()?new uo(d):null,E=new Eo({registry:f,observations:U,actionClient:S,getMachineCredentials:()=>({machineToken:p().machineToken}),isSessionDeleted:e=>new To().hasSession(e),onMessages:async(e,n,o,t)=>{await y?.processMessages(e,n,o,t)},onBindingPaused:e=>{R.revokeSession(e.registryKey),e.lifecycleState==="closed"?r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")}):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const x=new to({currentVersion:h,machineId:m.machineId??"unknown-machine",serverUrl:m.serverUrl??u,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:pe,dataEpoch:ue,advertisedCapabilities:ge,updaterProtocolVersion:1,startUpgrade:async(e,n)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(d,"auto-upgrade",e,{currentVersion:h,prepareForUpgrade:t=>r.prepareForUpgrade(t),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:n?void 0:()=>r.getUpgradeIdleState().idle})}});x.setPolicy(Z),r=new Qe(d,P,h,x,new ko({registry:f,observations:U,bindingClient:S,getMachineCredentials:()=>{const e=p();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${c}`}),{prepare:()=>Oe(),isDisabled:()=>ae(),shutdownAfterResponse:()=>{setTimeout(()=>{$e(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>R.revokeToken(e),q,null,Ye(M),()=>O(l)),L=async e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof n.targetVersion=="string"?n.targetVersion:void 0,t=n.confirmedMajor===!0;return await Ge(d,`local-upgrade-${Date.now()}`,o,{currentVersion:h,confirmedMajor:t,prepareForUpgrade:B=>r.prepareForUpgrade(B),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},j=e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},t=`desktop-${(typeof n.targetVersion=="string"?n.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:t,...r.prepareForUpgrade(t)}},H=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),y=new _o({registry:f,observations:U,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const n=p().machineToken?.trim(),o=e.binding;if(!n||!o)throw new Error("managed_room_context_unavailable");const t=await S.status({machineToken:n,roomId:o.roomId,bindingId:o.bindingId});if(!Uo(f,e)||!Do(e,t))throw new Error("managed_room_binding_unavailable");return{roomName:t.room.name,memberCount:t.room.memberCount,members:t.room.members,agentsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent}:{},agentSystemPromptsByIdentityId:t.agent?{[t.agentIdentityId]:t.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,n,o,t)=>{const I=p().machineToken;if(!I)throw new Error("machine_not_authorized");return R.issue({registryKey:e,machineCredential:I,activationCauseMessageId:n,allowedActions:o,propagateWorkerRoomOrigin:t})},audit:new No,resolveManagedAgentPolicy:e=>Mo({...e,runtime:l.find(n=>n.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>we({serverUrl:u,machineToken:p().machineToken,req:e,client:d,queue:r.getScheduleQueue(),registry:f}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(f.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await S.status({machineToken:p().machineToken,roomId:e.roomId,bindingId:e.bindingId});return o.status==="active"&&o.room.status==="active"?"ready":"ended"},r.setManagedRoomTurnPreparer(e=>y.prepareConversationTurn(e)),r.setManagedAgentDirectTurnPreparer((e,n)=>y.prepareDirectConversationTurn(e,n)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?y.prepareDirectConversationTurn(e.sessionId,jo):e.source==="manager_event"?y.prepareDirectConversationTurn(e.sessionId,{allowedRoomActions:[],managerEvent:!0}):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:y.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),F.mkdirSync(fe,{recursive:!0}),se(process.pid,c,{version:h}),ce(process.pid,void 0,c),d.connect(),process.stdin.resume();let X=!1;const ee=async()=>{if(!X){X=!0,console.log(A.gray(`
|
|
3
|
+
Disconnecting...`)),T({level:"info",wsEvent:"daemon.stop"}),clearInterval(g);try{await r.cleanup(),x.stop(),P?.stop(),E?.stop(),d.disconnect(),await Promise.allSettled([b.close(),k.close()]),te(process.pid,c),re(c)}finally{process.exit(0)}}};process.on("SIGINT",()=>{ee()}),process.on("SIGTERM",()=>{ee()})}),i.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>J()),i.command("room-session-hook",{hidden:!0}).description("(internal) Authorize the official Room tool for one trusted Agent Session").argument("<runtime>","Trusted runtime adapter").allowUnknownOption(!0).action(()=>J()),i.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>J());const he=i.command("config").description("View or modify configuration");he.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${ke()}`);const a=p(),s=De(a,ne(process.env,a));if(a.serverUrl){const g=Xe(a.serverUrl);console.log(`Region: ${g} (${W[g].label})`)}console.log(JSON.stringify(s,null,2))}),he.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((a,s)=>{const g=p();if(a==="server"){s!=="cn"&&s!=="global"&&(console.error(A.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const c=s;g.serverUrl=Ze(c),be(g),console.log(A.green(`\u2713 Server set to ${W[c].label}`)),console.log(A.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(A.red(`\u2717 Unknown config key: ${a}. Supported: server`)),process.exit(1)}),Ue(i),Me(i),Le(i),je(i),He(i),Be(i),Fe(i),We(i),ze(i),Je(i),i.parse();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{createHash as y}from"node:crypto";import p from"node:fs";import{renameSyncWithRetry as T}from"../fs/atomic-rename.js";import E from"node:path";import{buildUserMessagePayload as $}from"@shennian/wire";import{resolveShennianPath as A}from"../config/index.js";import{buildToolPayload as g,makeCursor as C,makeEventKey as I,normalizeText as h}from"./parser-common.js";const _=64*1024,x={"image/png":{ext:"png",kind:"image"},"image/jpeg":{ext:"jpg",kind:"image"},"image/webp":{ext:"webp",kind:"image"},"image/gif":{ext:"gif",kind:"image"},"application/pdf":{ext:"pdf",kind:"file"}},K=["local-command-caveat","local-command-stdout","local-command-stderr","bash-stdout","bash-stderr","task-notification","system-reminder"];function q(t,e,n){return t.isSidechain===!0?[]:t.type==="user"?M(t,e,n):t.type==="assistant"?k(t,e,n):t.type==="attachment"?b(t,e,n):[]}function M(t,e,n){if(t.isMeta===!0||t.isCompactSummary===!0)return[];const o=d(t.message)?.content,i=[];if(Array.isArray(o))for(const a of o){const s=d(a);if(s?.type==="tool_result"){const l=U(s,e,n);l&&i.push(l)}}const r=v(o,e,n,"user");return r&&i.push(r),i}function b(t,e,n){const o=d(t.attachment);if(o?.type!=="queued_command")return[];const i=d(o.origin);if(!(i?i.kind==="human":o.commandMode==="prompt"))return[];const a=v(o.prompt,e,n,"queued_user");return a?[a]:[]}function v(t,e,n,o){const i=[],r=[],a=Array.isArray(t)?t:[t];for(const l of a){if(typeof l=="string"){i.push(l);continue}const u=d(l);if(u){if(u.type==="text"&&typeof u.text=="string")i.push(u.text);else if(u.type==="image"||u.type==="document"){const c=D(u,e.sourceSessionKey);c&&r.push(c)}}}const s=h(i.map(w).filter(Boolean).join(`
|
|
2
|
+
|
|
3
|
+
`));return!s&&r.length===0?null:(!n.value&&s&&(n.value=s.slice(0,80)),{...f(e,o,n,"user"),payload:r.length?$(s,r):s})}function k(t,e,n){const o=d(t.message),i=typeof o?.model=="string"?o.model:null,r=typeof o?.content=="string"?[{type:"text",text:o.content}]:Array.isArray(o?.content)?o.content:[],a=[];let s=[],l=0;const u=()=>{const c=h(s.join(`
|
|
4
|
+
|
|
5
|
+
`));if(s=[],!c)return;const m=l===0?"assistant":`assistant:${l}`;l+=1,a.push({...f(e,m,n,"agent"),payload:c,modelId:i})};for(const c of r){const m=d(c);m&&((m.type==="text"||m.type===void 0)&&typeof m.text=="string"?s.push(m.text):m.type==="tool_use"&&(u(),a.push(R(m,e,n,i))))}return u(),a}function R(t,e,n,o){const i=typeof t.id=="string"&&t.id.trim()?t.id.trim():"",r=typeof t.name=="string"&&t.name?t.name:"tool",a=f(e,`tool_use:${i||"anonymous"}`,n,"agent"),s=S(e.sourceSessionKey,i,a.sourceEventKey);return{...a,payload:g({name:r,toolCallId:s.toolCallId,detailRevision:1,status:"running"}),modelId:o,...s.canonicalMessageKey?{canonicalMessageKey:s.canonicalMessageKey,canonicalMutation:"append"}:{},localToolDetail:{toolCallId:s.toolCallId,detailRevision:1,name:r,...t.input!==void 0?{args:t.input}:{},status:"running"}}}function U(t,e,n){const o=typeof t.tool_use_id=="string"?t.tool_use_id.trim():"";if(!o)return null;const i=t.is_error===!0?"failed":"completed",r="tool_result",a=f(e,`tool_result:${o}`,n,"agent"),s=S(e.sourceSessionKey,o,a.sourceEventKey);return{...a,payload:g({name:r,toolCallId:s.toolCallId,detailRevision:2,status:i}),canonicalMessageKey:s.canonicalMessageKey,canonicalMutation:"upsert",localToolDetail:{toolCallId:s.toolCallId,detailRevision:2,name:r,result:j(t.content),status:i}}}function S(t,e,n){if(!e)return{toolCallId:`native:${n}`};const o=y("sha256").update(`${t}\0${e}`).digest("hex").slice(0,32);return{toolCallId:`native:tool:${o}`,canonicalMessageKey:`tool:${o}`}}function j(t){let e;return typeof t=="string"?e=t:Array.isArray(t)?e=t.map(n=>{if(typeof n=="string")return n;const o=d(n);return o?typeof o.text=="string"?o.text:o.type==="image"?"[image]":"":""}).filter(Boolean).join(`
|
|
6
|
+
`):e="",e.length>_?`${e.slice(0,_)}
|
|
7
|
+
\u2026[truncated]`:e}function w(t){const e=t.trim();if(!e||e.startsWith("[Request interrupted by user"))return"";for(const n of K)if(e.startsWith(`<${n}>`)||e.startsWith(`<${n} `))return"";if(e.startsWith("<command-name>")||e.startsWith("<command-message>")){const n=e.match(/<command-name>([\s\S]*?)<\/command-name>/)?.[1]?.trim()??"";if(!n)return"";const o=e.match(/<command-args>([\s\S]*?)<\/command-args>/)?.[1]?.trim()??"";return o?`${n} ${o}`:n}return t}function D(t,e){const n=d(t.source);if(n?.type!=="base64")return null;const o=typeof n.media_type=="string"?n.media_type.toLowerCase():"",i=typeof n.data=="string"?n.data:"",r=x[o];if(!r||!i)return null;const a=Buffer.from(i,"base64");if(a.length===0)return null;const s=y("sha256").update(a).digest("hex"),l=A("native-attachments","claude",e.replace(/[^A-Za-z0-9._-]/g,"_")),u=E.join(l,`${s}.${r.ext}`);if(!p.existsSync(u)){p.mkdirSync(l,{recursive:!0,mode:448});const c=`${u}.tmp-${process.pid}`;p.writeFileSync(c,a,{mode:384}),T(c,u)}return{path:u,name:`${r.kind==="image"?"image":"document"}-${s.slice(0,8)}.${r.ext}`,mimeType:o,kind:r.kind,byteSize:a.length,sha256:s}}function f(t,e,n,o){return{agentType:"claude",sourceMode:"claude_transcript_import",sourceSessionKey:t.sourceSessionKey,sourceEventKey:I(t.filePath,t.lineOffset,e),cursor:C(t.filePath,t.lineOffset),role:o,ts:t.ts,payload:"",title:n.value,titleSource:"first_user_fallback",workDir:t.workDir}}function d(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:null}export{q as parseClaudeEntry};
|