work-ally 0.2.0-alpha.1

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.
Files changed (172) hide show
  1. package/AGENTS.md +110 -0
  2. package/DASHBOARD.md +160 -0
  3. package/PRODUCT.md +113 -0
  4. package/README.md +403 -0
  5. package/ally.sh +171 -0
  6. package/bridge/src/approval-rules.ts +360 -0
  7. package/bridge/src/channel-delivery.ts +207 -0
  8. package/bridge/src/channel-types.ts +22 -0
  9. package/bridge/src/channels/fake/adapter.ts +31 -0
  10. package/bridge/src/channels/feishu/adapter.ts +411 -0
  11. package/bridge/src/channels/feishu/approvals.ts +6 -0
  12. package/bridge/src/channels/feishu/formatter.ts +276 -0
  13. package/bridge/src/channels/feishu/normalize.ts +368 -0
  14. package/bridge/src/codex-config.ts +52 -0
  15. package/bridge/src/config.ts +240 -0
  16. package/bridge/src/fake-runtime-client.ts +505 -0
  17. package/bridge/src/handoff-service.ts +494 -0
  18. package/bridge/src/logger.ts +194 -0
  19. package/bridge/src/memory-digest.ts +186 -0
  20. package/bridge/src/receiver-approval-autonomy.ts +158 -0
  21. package/bridge/src/receiver-control-core.ts +140 -0
  22. package/bridge/src/receiver-control-work-session.ts +218 -0
  23. package/bridge/src/receiver-control.ts +83 -0
  24. package/bridge/src/receiver-delivery.ts +136 -0
  25. package/bridge/src/receiver-helpers.ts +96 -0
  26. package/bridge/src/receiver-human-gate.ts +333 -0
  27. package/bridge/src/receiver-inbound-preflight.ts +162 -0
  28. package/bridge/src/receiver-recovery.ts +236 -0
  29. package/bridge/src/receiver-runtime-callbacks.ts +367 -0
  30. package/bridge/src/receiver-runtime-policy.ts +132 -0
  31. package/bridge/src/receiver-runtime-state.ts +124 -0
  32. package/bridge/src/receiver-support-actions.ts +189 -0
  33. package/bridge/src/receiver-thread-start.ts +57 -0
  34. package/bridge/src/receiver-turn-coordination.ts +94 -0
  35. package/bridge/src/receiver-turn-execution.ts +257 -0
  36. package/bridge/src/receiver-turn-failure.ts +143 -0
  37. package/bridge/src/receiver-turn-result.ts +185 -0
  38. package/bridge/src/receiver-turn-steer.ts +70 -0
  39. package/bridge/src/receiver-work-session.ts +76 -0
  40. package/bridge/src/receiver.ts +329 -0
  41. package/bridge/src/router.ts +62 -0
  42. package/bridge/src/runtime-client-agent-messages.ts +150 -0
  43. package/bridge/src/runtime-client-message-dispatch.ts +176 -0
  44. package/bridge/src/runtime-client-protocol.ts +411 -0
  45. package/bridge/src/runtime-client-request-ops.ts +56 -0
  46. package/bridge/src/runtime-client-run-turn.ts +158 -0
  47. package/bridge/src/runtime-client-thread-ops.ts +270 -0
  48. package/bridge/src/runtime-client-transport.ts +309 -0
  49. package/bridge/src/runtime-client-turn-poll.ts +224 -0
  50. package/bridge/src/runtime-client-turn-read.ts +185 -0
  51. package/bridge/src/runtime-client-turn-state.ts +105 -0
  52. package/bridge/src/runtime-client.ts +344 -0
  53. package/bridge/src/runtime-user-input.ts +403 -0
  54. package/bridge/src/scheduler.ts +239 -0
  55. package/bridge/src/server-handoff-command.ts +364 -0
  56. package/bridge/src/server-main.ts +80 -0
  57. package/bridge/src/server-routine-command.ts +60 -0
  58. package/bridge/src/server-routine-execution.ts +222 -0
  59. package/bridge/src/server-runtime-app-support.ts +107 -0
  60. package/bridge/src/server-runtime-app.ts +238 -0
  61. package/bridge/src/server-thread-sync-command.ts +63 -0
  62. package/bridge/src/server.ts +17 -0
  63. package/bridge/src/session-store-delivery.ts +220 -0
  64. package/bridge/src/session-store-human-gate.ts +380 -0
  65. package/bridge/src/session-store-inbound-acceptance.ts +66 -0
  66. package/bridge/src/session-store-meta.ts +134 -0
  67. package/bridge/src/session-store-turn-ledger.ts +272 -0
  68. package/bridge/src/session-store.ts +380 -0
  69. package/bridge/src/system-notify.ts +220 -0
  70. package/bridge/src/thread-sync.ts +200 -0
  71. package/bridge/src/translator.ts +494 -0
  72. package/bridge/src/types.ts +289 -0
  73. package/bridge/src/utils.ts +104 -0
  74. package/bridge/src/work-session-store.ts +471 -0
  75. package/docs/.gitkeep +0 -0
  76. package/docs/architecture/codex-feishu-bridge-proposal.md +2742 -0
  77. package/docs/completed/FEATURE-feishu-markdown-and-reply-support.md +327 -0
  78. package/docs/completed/README.md +21 -0
  79. package/docs/completed/SPEC-approval-autonomy-and-safe-defaults.md +205 -0
  80. package/docs/completed/SPEC-approval-batch-and-strict-reply-shortcuts.md +153 -0
  81. package/docs/completed/SPEC-conversation-noise-reduction-and-busy-input-gate.md +538 -0
  82. package/docs/completed/SPEC-engineering-sop-skillization.md +190 -0
  83. package/docs/completed/SPEC-faithful-bridge-core-thinning-v2.md +376 -0
  84. package/docs/completed/SPEC-faithful-bridge-core-thinning.md +1071 -0
  85. package/docs/completed/SPEC-group-chat-sender-identity.md +301 -0
  86. package/docs/completed/SPEC-middleware-exception-visibility.md +227 -0
  87. package/docs/completed/SPEC-nightly-memory-digest-visibility.md +121 -0
  88. package/docs/completed/SPEC-project-group-chat-human-centered-conversation-mapping.md +326 -0
  89. package/docs/completed/SPEC-remove-cli-persona-bootstrap.md +201 -0
  90. package/docs/developer-workflow.md +49 -0
  91. package/docs/implementation/SPEC-codex-same-machine-session-handoff-implementation.md +239 -0
  92. package/docs/implementation/test-coverage-map.md +363 -0
  93. package/docs/implementation/work-ally-implementation-guide.md +790 -0
  94. package/docs/issues/README.md +10 -0
  95. package/docs/issues/pending/ANALYSIS-ally-premature-recovery-notice-and-task-state-semantics-2026-03-18.md +295 -0
  96. package/docs/issues/resolved/ANALYSIS-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +466 -0
  97. package/docs/issues/resolved/ANALYSIS-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +261 -0
  98. package/docs/issues/resolved/ANALYSIS-codex-app-server-transport-disconnect-semantics-2026-03-14.md +606 -0
  99. package/docs/issues/resolved/ANALYSIS-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +348 -0
  100. package/docs/issues/resolved/ANALYSIS-runtime-turn-delivery-and-recovery-2026-03-14.md +603 -0
  101. package/docs/issues/resolved/ANALYSIS-self-test-gap-approval-waiting-visible-but-approval-artifact-missing-2026-03-16.md +166 -0
  102. package/docs/issues/resolved/ANALYSIS-self-test-gap-blocking-state-visible-without-user-actionable-artifact-2026-03-16.md +186 -0
  103. package/docs/issues/resolved/ANALYSIS-self-test-gap-premature-terminalization-on-fresh-thread-poll-and-object-error-leak-2026-03-16.md +166 -0
  104. package/docs/issues/resolved/REPORT-ally-runtime-turn-delivery-3b42fb8-2026-03-15.md +373 -0
  105. package/docs/manual-acceptance.md +127 -0
  106. package/docs/ops-runbook.md +44 -0
  107. package/docs/planning/FEATURE-memory-system.md +748 -0
  108. package/docs/planning/SPEC-active-turn-steer-and-context-compaction-visibility.md +269 -0
  109. package/docs/planning/SPEC-approval-rules-inheritance-and-local-validation-lane.md +450 -0
  110. package/docs/planning/SPEC-assistant-persona-bootstrap.md +199 -0
  111. package/docs/planning/SPEC-assistant-rename.md +610 -0
  112. package/docs/planning/SPEC-bridge-app-server-protocol-alignment.md +667 -0
  113. package/docs/planning/SPEC-claude-runtime-host-for-work-ally.md +434 -0
  114. package/docs/planning/SPEC-cli-feishu-codex-session-unification.md +236 -0
  115. package/docs/planning/SPEC-codex-same-machine-session-handoff.md +873 -0
  116. package/docs/planning/SPEC-feishu-reaction-shortcuts.md +282 -0
  117. package/docs/planning/SPEC-local-stable-release-boundary.md +166 -0
  118. package/docs/planning/SPEC-managed-thread-entry-and-surface-mobility.md +862 -0
  119. package/docs/planning/SPEC-minimal-bridge-semantics-and-user-visible-surface.md +362 -0
  120. package/docs/planning/SPEC-npm-alpha-distribution-and-install-first-release.md +222 -0
  121. package/docs/planning/SPEC-remove-websocket-runtime-transport.md +364 -0
  122. package/docs/planning/SPEC-runtime-abstraction-phase-1.md +424 -0
  123. package/docs/planning/SPEC-runtime-connection-and-turn-recovery-semantics.md +274 -0
  124. package/docs/planning/SPEC-session-presence-and-state-visibility.md +397 -0
  125. package/docs/planning/SPEC-skill-first-capability-packaging.md +338 -0
  126. package/docs/planning/SPEC-stable-archive-contract.md +456 -0
  127. package/docs/planning/SPEC-supervised-start-boundary.md +127 -0
  128. package/docs/planning/SPEC-user-barrier-reduction-and-activation.md +832 -0
  129. package/docs/planning/ally-next.md +1278 -0
  130. package/docs/planning/assistant-workbench-spec.md +725 -0
  131. package/docs/planning/product-workbench.md +283 -0
  132. package/docs/product-onboarding.md +227 -0
  133. package/docs/product-spec-standard.md +528 -0
  134. package/docs/troubleshooting.md +45 -0
  135. package/docs/user-quickstart.md +46 -0
  136. package/internal/dispatch.sh +95 -0
  137. package/internal/lib/common.sh +1450 -0
  138. package/internal/modules/assistant/manage.sh +1312 -0
  139. package/internal/modules/bootstrap/setup.sh +144 -0
  140. package/internal/modules/config/init-env.sh +10 -0
  141. package/internal/modules/global/manage.sh +154 -0
  142. package/internal/modules/handoff/manage.sh +54 -0
  143. package/internal/modules/mcp/manage.sh +83 -0
  144. package/internal/modules/ops/logs.sh +76 -0
  145. package/internal/modules/routines/manage.sh +55 -0
  146. package/internal/modules/runtime/assistant-autosave.sh +26 -0
  147. package/internal/modules/runtime/restart.sh +6 -0
  148. package/internal/modules/runtime/start.sh +283 -0
  149. package/internal/modules/runtime/status.sh +194 -0
  150. package/internal/modules/runtime/stop.sh +55 -0
  151. package/internal/modules/runtime/supervisor.sh +216 -0
  152. package/internal/modules/runtime/update.sh +26 -0
  153. package/package.json +41 -0
  154. package/runtime/config/.gitkeep +0 -0
  155. package/runtime/host/.gitkeep +0 -0
  156. package/runtime/host/healthcheck-codex-app-server.ts +22 -0
  157. package/runtime/host/ping-pong-codex-app-server.ts +66 -0
  158. package/runtime/host/probe-codex-app-server.ts +115 -0
  159. package/skills/archive-reader/SKILL.md +9 -0
  160. package/skills/feishu-production-debug/SKILL.md +37 -0
  161. package/skills/feishu-production-debug/references/feishu-debug-order.md +49 -0
  162. package/skills/feishu-production-debug/references/platform-permission-baseline.md +23 -0
  163. package/skills/issue-to-spec-triage/SKILL.md +44 -0
  164. package/skills/issue-to-spec-triage/references/triage-rules.md +66 -0
  165. package/skills/memory-digest/SKILL.md +9 -0
  166. package/skills/post-implementation-closure/SKILL.md +39 -0
  167. package/skills/post-implementation-closure/references/closure-checklist.md +45 -0
  168. package/skills/post-implementation-closure/references/doc-drift-map.md +49 -0
  169. package/skills/product-spec/SKILL.md +244 -0
  170. package/templates/env.example +5 -0
  171. package/templates/routines/nightly-memory-digest.yaml +10 -0
  172. package/templates/workspace/AGENTS.md +26 -0
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ work_ally_ensure_state_dirs
9
+
10
+ cmd_name=$(work_ally_cmd_name)
11
+ ASSISTANT_NAME=""
12
+ ASSISTANT_REMOTE=""
13
+ TARGET_WORKSPACE="${WORK_ALLY_WORKSPACE_ROOT:-}"
14
+
15
+ while [ "$#" -gt 0 ]; do
16
+ case "$1" in
17
+ --assistant)
18
+ [ "$#" -ge 2 ] || work_ally_die "--assistant requires a value"
19
+ ASSISTANT_NAME="$2"
20
+ shift 2
21
+ ;;
22
+ --assistant=*)
23
+ ASSISTANT_NAME="${1#--assistant=}"
24
+ shift
25
+ ;;
26
+ --workspace)
27
+ [ "$#" -ge 2 ] || work_ally_die "--workspace requires a value"
28
+ TARGET_WORKSPACE="$2"
29
+ shift 2
30
+ ;;
31
+ --workspace=*)
32
+ TARGET_WORKSPACE="${1#--workspace=}"
33
+ shift
34
+ ;;
35
+ --remote)
36
+ [ "$#" -ge 2 ] || work_ally_die "--remote requires a value"
37
+ ASSISTANT_REMOTE="$2"
38
+ shift 2
39
+ ;;
40
+ --remote=*)
41
+ ASSISTANT_REMOTE="${1#--remote=}"
42
+ shift
43
+ ;;
44
+ -h|--help)
45
+ cat <<USAGE
46
+ Usage: $cmd_name setup [assistant-name] [--assistant <name>] [--workspace <path>] [--remote <git-url>]
47
+ USAGE
48
+ exit 0
49
+ ;;
50
+ *)
51
+ if [ -z "$ASSISTANT_NAME" ]; then
52
+ ASSISTANT_NAME="$1"
53
+ shift
54
+ else
55
+ work_ally_die "Unknown argument: $1"
56
+ fi
57
+ ;;
58
+ esac
59
+ done
60
+
61
+ [ -n "$TARGET_WORKSPACE" ] || work_ally_die "--workspace is required"
62
+ [ -d "$TARGET_WORKSPACE" ] || work_ally_die "Workspace directory not found: $TARGET_WORKSPACE"
63
+ TARGET_WORKSPACE=$(cd "$TARGET_WORKSPACE" && pwd)
64
+ export WORK_ALLY_WORKSPACE_ROOT="$TARGET_WORKSPACE"
65
+
66
+ work_ally_note "Bootstrapping work-ally runtime shell"
67
+ work_ally_require_cmd node
68
+ work_ally_require_cmd npm
69
+ work_ally_require_cmd codex
70
+ work_ally_install_bridge_dependencies
71
+
72
+ if [ -z "$ASSISTANT_NAME" ] && [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
73
+ ASSISTANT_NAME="$WORK_ALLY_ASSISTANT_NAME"
74
+ fi
75
+ if [ -z "$ASSISTANT_REMOTE" ] && [ -n "${WORK_ALLY_ASSISTANT_GIT_REMOTE:-}" ]; then
76
+ ASSISTANT_REMOTE="$WORK_ALLY_ASSISTANT_GIT_REMOTE"
77
+ fi
78
+
79
+ if [ -n "$ASSISTANT_NAME" ]; then
80
+ existing_workspace=""
81
+ work_ally_validate_assistant_name "$ASSISTANT_NAME"
82
+ if work_ally_registry_has_assistant "$ASSISTANT_NAME"; then
83
+ existing_workspace=$(work_ally_assistant_registered_workspace "$ASSISTANT_NAME" || true)
84
+ if [ -n "$existing_workspace" ] && [ "$existing_workspace" != "$TARGET_WORKSPACE" ]; then
85
+ work_ally_die "Assistant $ASSISTANT_NAME is already bound to $existing_workspace. Create a different assistant for $TARGET_WORKSPACE."
86
+ fi
87
+ fi
88
+
89
+ work_ally_hydrate_assistant_context "$ASSISTANT_NAME"
90
+ "$WORK_ALLY_IMPLEMENTATION_DIR/internal/modules/config/init-env.sh"
91
+ work_ally_load_env
92
+
93
+ manage_args=("$ASSISTANT_NAME" --workspace "$TARGET_WORKSPACE")
94
+ if [ -n "$ASSISTANT_REMOTE" ]; then
95
+ manage_args+=(--git-remote "$ASSISTANT_REMOTE")
96
+ fi
97
+
98
+ if work_ally_registry_has_assistant "$ASSISTANT_NAME"; then
99
+ work_ally_note "Reusing assistant $ASSISTANT_NAME"
100
+ "$WORK_ALLY_IMPLEMENTATION_DIR/internal/modules/assistant/manage.sh" ensure "${manage_args[@]}"
101
+ else
102
+ "$WORK_ALLY_IMPLEMENTATION_DIR/internal/modules/assistant/manage.sh" add "${manage_args[@]}"
103
+ fi
104
+
105
+ work_ally_hydrate_assistant_context "$ASSISTANT_NAME"
106
+ work_ally_env_set WORK_ALLY_ASSISTANT_NAME "$ASSISTANT_NAME"
107
+ if [ -n "$ASSISTANT_REMOTE" ]; then
108
+ work_ally_env_set WORK_ALLY_ASSISTANT_GIT_REMOTE "$ASSISTANT_REMOTE"
109
+ fi
110
+ work_ally_project_registry_set "$TARGET_WORKSPACE" "$ASSISTANT_NAME"
111
+ fi
112
+
113
+ cat <<EOF2
114
+
115
+ Setup complete.
116
+ EOF2
117
+
118
+ if [ -n "$ASSISTANT_NAME" ]; then
119
+ cat <<EOF2
120
+
121
+ Assistant desk is ready:
122
+ - assistant: $ASSISTANT_NAME
123
+ - workspace: $TARGET_WORKSPACE
124
+ - desk: $WORK_ALLY_ASSISTANT_HOME
125
+ - config: $WORK_ALLY_ENV_FILE
126
+
127
+ Next steps:
128
+ 1. Edit $WORK_ALLY_ENV_FILE
129
+ Required for Feishu IM: FEISHU_APP_ID, FEISHU_APP_SECRET
130
+ Optional access control: WORK_ALLY_ALLOWED_USER_IDS (comma-separated)
131
+ 2. Optional: set WORK_ALLY_ASSISTANT_GIT_REMOTE in $WORK_ALLY_ENV_FILE if you want auto-push
132
+ 3. Optional: if you want Feishu docs and Codex has not installed it yet,
133
+ set FEISHU_MCP_SERVER_URL then run: $cmd_name mcp install-feishu --assistant $ASSISTANT_NAME
134
+ 4. Run: $cmd_name start --assistant $ASSISTANT_NAME
135
+ EOF2
136
+ else
137
+ cat <<EOF2
138
+
139
+ Next steps:
140
+ 1. Re-run with an assistant name: $cmd_name setup <name> --workspace <path>
141
+ 2. Edit the assistant config file once it is created
142
+ 3. Run: $cmd_name start --assistant <name>
143
+ EOF2
144
+ fi
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+
9
+ work_ally_ensure_state_dirs
10
+ work_ally_ensure_env_defaults
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+
8
+ WORK_ALLY_HOME="${WORK_ALLY_HOME:-$HOME/.work-ally}"
9
+ WORK_ALLY_ASSISTANTS_DIR="${WORK_ALLY_ASSISTANTS_DIR:-$WORK_ALLY_HOME/assistants}"
10
+ WORK_ALLY_PROJECT_REGISTRY_FILE="${WORK_ALLY_PROJECT_REGISTRY_FILE:-$WORK_ALLY_HOME/projects/registry.yaml}"
11
+ WORK_ALLY_ASSISTANT_REGISTRY_FILE="${WORK_ALLY_ASSISTANT_REGISTRY_FILE:-$WORK_ALLY_ASSISTANTS_DIR/registry.yaml}"
12
+
13
+ usage() {
14
+ local cmd_name
15
+ cmd_name=$(work_ally_cmd_name)
16
+ cat <<USAGE
17
+ Usage: $cmd_name global <command> [args]
18
+
19
+ Commands:
20
+ list Show running assistants across this machine
21
+ stop --assistant <name> Stop the instance for the target assistant
22
+ stop --pid <pid> Stop the instance by bridge pid
23
+ USAGE
24
+ }
25
+
26
+ list_running_instances() {
27
+ local assistants assistant_name runtime_dir pid_file health_file pid
28
+
29
+ [ -f "$WORK_ALLY_ASSISTANT_REGISTRY_FILE" ] || return 0
30
+ assistants=$(awk '/^ [^[:space:]]+:$/ { name=$0; sub(/^ /, "", name); sub(/:$/, "", name); print name }' "$WORK_ALLY_ASSISTANT_REGISTRY_FILE")
31
+ [ -n "$assistants" ] || return 0
32
+
33
+ while IFS= read -r assistant_name; do
34
+ [ -n "$assistant_name" ] || continue
35
+ runtime_dir="$(work_ally_assistant_runtime_dir "$assistant_name")"
36
+ pid_file="$runtime_dir/bridge.pid"
37
+ health_file="$runtime_dir/bridge.health.json"
38
+ pid=$(work_ally_read_pid "$pid_file" || true)
39
+ if [ -z "$pid" ] && [ -f "$health_file" ]; then
40
+ pid=$(sed -nE 's/.*"pid"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p' "$health_file" | head -n 1)
41
+ fi
42
+ if [ -n "$pid" ] && work_ally_is_pid_alive "$pid"; then
43
+ printf '%s\t%s\n' "$pid" "$assistant_name"
44
+ fi
45
+ done <<EOF2
46
+ $assistants
47
+ EOF2
48
+ }
49
+
50
+ read_env_field() {
51
+ local file="$1"
52
+ local key="$2"
53
+ [ -f "$file" ] || return 0
54
+ sed -nE "s/^${key}=(.*)$/\\1/p" "$file" | tail -n 1
55
+ }
56
+
57
+ resolve_assistant_by_pid() {
58
+ local target_pid="$1"
59
+ list_running_instances | awk -F '\t' -v pid="$target_pid" '$1 == pid { print $2; exit }'
60
+ }
61
+
62
+ list_instances() {
63
+ local rows count assistant_name env_file health_file channel app_id health_updated pid workspace
64
+ rows=$(list_running_instances || true)
65
+ if [ -z "$rows" ]; then
66
+ printf 'instances: 0\n'
67
+ return 0
68
+ fi
69
+
70
+ count=$(printf '%s\n' "$rows" | awk 'NF { count += 1 } END { print count + 0 }')
71
+ printf 'instances: %s\n' "$count"
72
+
73
+ while IFS=$'\t' read -r pid assistant_name; do
74
+ [ -n "$pid" ] || continue
75
+ [ -n "$assistant_name" ] || continue
76
+
77
+ workspace=$(work_ally_assistant_registered_workspace "$assistant_name" || true)
78
+ env_file=$(work_ally_assistant_env_file "$assistant_name")
79
+ health_file="$(work_ally_assistant_runtime_dir "$assistant_name")/bridge.health.json"
80
+ channel=$(read_env_field "$env_file" WORK_ALLY_CHANNEL_IMPL)
81
+ app_id=$(read_env_field "$env_file" FEISHU_APP_ID)
82
+ if [ -f "$health_file" ]; then
83
+ health_updated=$(sed -nE 's/.*"updated_at"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/p' "$health_file" 2>/dev/null | head -n 1 || true)
84
+ else
85
+ health_updated=""
86
+ fi
87
+
88
+ printf -- '---\n'
89
+ printf 'bridge pid: %s\n' "$pid"
90
+ printf 'assistant: %s\n' "$assistant_name"
91
+ [ -n "$workspace" ] && printf 'workspace: %s\n' "$workspace"
92
+ printf 'channel: %s\n' "${channel:-unknown}"
93
+ [ -n "$app_id" ] && printf 'app id: %s\n' "$app_id"
94
+ [ -n "$health_updated" ] && printf 'last health update: %s\n' "$health_updated"
95
+ done <<EOF2
96
+ $rows
97
+ EOF2
98
+ }
99
+
100
+ stop_instance() {
101
+ local mode="$1"
102
+ local target="$2"
103
+ local assistant_name=""
104
+
105
+ case "$mode" in
106
+ --assistant)
107
+ assistant_name="$target"
108
+ ;;
109
+ --pid)
110
+ assistant_name=$(resolve_assistant_by_pid "$target")
111
+ ;;
112
+ *)
113
+ work_ally_die "Unknown stop mode: $mode"
114
+ ;;
115
+ esac
116
+
117
+ [ -n "$assistant_name" ] || work_ally_die "No running ally instance matched: $target"
118
+
119
+ WORK_ALLY_HOME="$WORK_ALLY_HOME" \
120
+ WORK_ALLY_ASSISTANTS_DIR="$WORK_ALLY_ASSISTANTS_DIR" \
121
+ WORK_ALLY_ASSISTANT_REGISTRY_FILE="$WORK_ALLY_ASSISTANT_REGISTRY_FILE" \
122
+ WORK_ALLY_PROJECT_REGISTRY_FILE="$WORK_ALLY_PROJECT_REGISTRY_FILE" \
123
+ WORK_ALLY_ASSISTANT_NAME="$assistant_name" \
124
+ WORK_ALLY_INSTALL_ROOT="$WORK_ALLY_IMPLEMENTATION_DIR" \
125
+ WORK_ALLY_IMPLEMENTATION_DIR="$WORK_ALLY_IMPLEMENTATION_DIR" \
126
+ WORK_ALLY_CMD_NAME="$(work_ally_cmd_name)" \
127
+ "$WORK_ALLY_IMPLEMENTATION_DIR/internal/modules/runtime/stop.sh"
128
+ }
129
+
130
+ SUBCMD="${1:-list}"
131
+ shift || true
132
+
133
+ case "$SUBCMD" in
134
+ list)
135
+ list_instances
136
+ ;;
137
+ stop)
138
+ case "${1:-}" in
139
+ --assistant|--pid)
140
+ [ $# -ge 2 ] || work_ally_die "global stop requires a target"
141
+ stop_instance "$1" "$2"
142
+ ;;
143
+ *)
144
+ work_ally_die "Usage: $(work_ally_cmd_name) global stop --assistant <name> | --pid <pid>"
145
+ ;;
146
+ esac
147
+ ;;
148
+ help|-h|--help)
149
+ usage
150
+ ;;
151
+ *)
152
+ work_ally_die "Unknown global command: $SUBCMD"
153
+ ;;
154
+ esac
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ if [ -z "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
9
+ WORK_ALLY_ASSISTANT_NAME=$(work_ally_resolve_assistant_name_from_args "$@" || true)
10
+ fi
11
+ if [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
12
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
13
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
14
+ fi
15
+ work_ally_ensure_state_dirs
16
+ work_ally_load_env
17
+ work_ally_load_assistant_state || true
18
+ work_ally_require_assistant_profile_ready "$WORK_ALLY_ASSISTANT_NAME"
19
+ work_ally_require_cmd codex
20
+
21
+ SUBCMD="${1:-}"
22
+ shift || true
23
+
24
+ case "$SUBCMD" in
25
+ codex|attach|new|continue|threads)
26
+ export WORK_ALLY_ASSISTANT_MODE="${WORK_ALLY_ASSISTANT_MODE:-assistant}"
27
+ export WORK_ALLY_ASSISTANT_NAME
28
+ export WORK_ALLY_ASSISTANT_HOME="${WORK_ALLY_ASSISTANT_HOME:-$(work_ally_assistant_registered_home "$WORK_ALLY_ASSISTANT_NAME")}"
29
+ export WORK_ALLY_ASSISTANT_CODEX_HOME="${WORK_ALLY_ASSISTANT_CODEX_HOME:-$(work_ally_assistant_registered_codex_home "$WORK_ALLY_ASSISTANT_NAME")}"
30
+ exec env \
31
+ CODEX_HOME="$WORK_ALLY_ASSISTANT_CODEX_HOME" \
32
+ WORK_ALLY_ASSISTANT_MODE="$WORK_ALLY_ASSISTANT_MODE" \
33
+ WORK_ALLY_ASSISTANT_NAME="$WORK_ALLY_ASSISTANT_NAME" \
34
+ WORK_ALLY_ASSISTANT_HOME="$WORK_ALLY_ASSISTANT_HOME" \
35
+ WORK_ALLY_ASSISTANT_CODEX_HOME="$WORK_ALLY_ASSISTANT_CODEX_HOME" \
36
+ node "$WORK_ALLY_IMPLEMENTATION_DIR/bridge/src/server.ts" handoff "$SUBCMD" "$@"
37
+ ;;
38
+ thread-sync)
39
+ export WORK_ALLY_ASSISTANT_MODE="${WORK_ALLY_ASSISTANT_MODE:-assistant}"
40
+ export WORK_ALLY_ASSISTANT_NAME
41
+ export WORK_ALLY_ASSISTANT_HOME="${WORK_ALLY_ASSISTANT_HOME:-$(work_ally_assistant_registered_home "$WORK_ALLY_ASSISTANT_NAME")}"
42
+ export WORK_ALLY_ASSISTANT_CODEX_HOME="${WORK_ALLY_ASSISTANT_CODEX_HOME:-$(work_ally_assistant_registered_codex_home "$WORK_ALLY_ASSISTANT_NAME")}"
43
+ exec env \
44
+ CODEX_HOME="$WORK_ALLY_ASSISTANT_CODEX_HOME" \
45
+ WORK_ALLY_ASSISTANT_MODE="$WORK_ALLY_ASSISTANT_MODE" \
46
+ WORK_ALLY_ASSISTANT_NAME="$WORK_ALLY_ASSISTANT_NAME" \
47
+ WORK_ALLY_ASSISTANT_HOME="$WORK_ALLY_ASSISTANT_HOME" \
48
+ WORK_ALLY_ASSISTANT_CODEX_HOME="$WORK_ALLY_ASSISTANT_CODEX_HOME" \
49
+ node "$WORK_ALLY_IMPLEMENTATION_DIR/bridge/src/server.ts" thread-sync "$@"
50
+ ;;
51
+ *)
52
+ work_ally_die "Unknown handoff subcommand: ${SUBCMD:-<missing>}"
53
+ ;;
54
+ esac
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ if [ -z "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
9
+ WORK_ALLY_ASSISTANT_NAME=$(work_ally_resolve_assistant_name_from_args "$@" || true)
10
+ fi
11
+ if [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
12
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
13
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
14
+ fi
15
+ work_ally_ensure_state_dirs
16
+ work_ally_load_env
17
+ work_ally_require_cmd codex
18
+ cmd_name=$(work_ally_cmd_name)
19
+
20
+ NAME=feishu
21
+ SUBCMD="${1:-status}"
22
+ shift || true
23
+
24
+ filtered_args=()
25
+ while [ "$#" -gt 0 ]; do
26
+ case "$1" in
27
+ --assistant)
28
+ [ "$#" -ge 2 ] || work_ally_die "--assistant requires a value"
29
+ shift 2
30
+ ;;
31
+ --assistant=*)
32
+ shift
33
+ ;;
34
+ *)
35
+ filtered_args+=("$1")
36
+ shift
37
+ ;;
38
+ esac
39
+ done
40
+ if [ "${#filtered_args[@]}" -gt 0 ]; then
41
+ set -- "${filtered_args[@]}"
42
+ else
43
+ set --
44
+ fi
45
+
46
+ restart_hint() {
47
+ local bridge_status
48
+ bridge_status=$(work_ally_process_status bridge)
49
+ if [[ "$bridge_status" = running* ]]; then
50
+ work_ally_warn "Codex MCP config is shared by the current user. If runtime is already running, restart with: $cmd_name restart"
51
+ fi
52
+ }
53
+
54
+ case "$SUBCMD" in
55
+ list)
56
+ exec codex mcp list "$@"
57
+ ;;
58
+ status)
59
+ if codex mcp get "$NAME" --json; then
60
+ exit 0
61
+ fi
62
+ work_ally_warn "Feishu MCP is not installed for the current user."
63
+ work_ally_note "Set FEISHU_MCP_SERVER_URL in $WORK_ALLY_ENV_FILE, then run: $cmd_name mcp install-feishu"
64
+ exit 1
65
+ ;;
66
+ install-feishu)
67
+ URL="${FEISHU_MCP_SERVER_URL:-}"
68
+ [ -n "$URL" ] || work_ally_die "FEISHU_MCP_SERVER_URL is required in $WORK_ALLY_ENV_FILE"
69
+ work_ally_note "Installing Feishu MCP into current user's Codex config"
70
+ codex mcp add "$NAME" --url "$URL"
71
+ work_ally_ok "Feishu MCP installed"
72
+ restart_hint
73
+ ;;
74
+ remove-feishu)
75
+ work_ally_note "Removing Feishu MCP from current user's Codex config"
76
+ codex mcp remove "$NAME"
77
+ work_ally_ok "Feishu MCP removed"
78
+ restart_hint
79
+ ;;
80
+ *)
81
+ work_ally_die "Unknown mcp subcommand: $SUBCMD"
82
+ ;;
83
+ esac
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ if [ -z "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
9
+ WORK_ALLY_ASSISTANT_NAME=$(work_ally_resolve_assistant_name_from_args "$@" || true)
10
+ fi
11
+ if [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
12
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
13
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
14
+ fi
15
+ work_ally_ensure_state_dirs
16
+ work_ally_load_env
17
+
18
+ filtered_args=()
19
+ while [ "$#" -gt 0 ]; do
20
+ case "$1" in
21
+ --assistant)
22
+ [ "$#" -ge 2 ] || work_ally_die "--assistant requires a value"
23
+ shift 2
24
+ ;;
25
+ --assistant=*)
26
+ shift
27
+ ;;
28
+ *)
29
+ filtered_args+=("$1")
30
+ shift
31
+ ;;
32
+ esac
33
+ done
34
+ if [ "${#filtered_args[@]}" -gt 0 ]; then
35
+ set -- "${filtered_args[@]}"
36
+ else
37
+ set --
38
+ fi
39
+
40
+ TARGET="${1:-timeline}"
41
+ MODE="${2:-follow}"
42
+ SHIFT_COUNT=2
43
+
44
+ case "$TARGET" in
45
+ timeline|bridge|runtime|supervisor|routine)
46
+ ;;
47
+ follow|print|--print|--tail)
48
+ MODE="$TARGET"
49
+ TARGET="timeline"
50
+ SHIFT_COUNT=1
51
+ ;;
52
+ *)
53
+ work_ally_die "Unknown log target: $TARGET"
54
+ ;;
55
+ esac
56
+
57
+ LOG_FILE=$(work_ally_log_file_for "$TARGET")
58
+ mkdir -p "$WORK_ALLY_LOG_DIR"
59
+ [ -f "$LOG_FILE" ] || touch "$LOG_FILE"
60
+ work_ally_prune_logs
61
+
62
+ case "$MODE" in
63
+ follow)
64
+ tail -f "$LOG_FILE"
65
+ ;;
66
+ print|--print)
67
+ cat "$LOG_FILE"
68
+ ;;
69
+ --tail)
70
+ shift "$SHIFT_COUNT"
71
+ tail -n "${1:-200}" "$LOG_FILE"
72
+ ;;
73
+ *)
74
+ work_ally_die "Unknown logs mode: $MODE"
75
+ ;;
76
+ esac
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ work_ally_ensure_state_dirs
9
+ if [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
10
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
11
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
12
+ fi
13
+
14
+ SUBCMD="${1:-list}"
15
+ shift || true
16
+
17
+ work_ally_load_env
18
+ work_ally_load_assistant_state || true
19
+ cmd_name=$(work_ally_cmd_name)
20
+
21
+ if [ -z "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
22
+ WORK_ALLY_ASSISTANT_NAME=$(work_ally_resolve_assistant_name_from_args "$@")
23
+ fi
24
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
25
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
26
+
27
+ work_ally_require_assistant_profile_ready "$WORK_ALLY_ASSISTANT_NAME"
28
+ export WORK_ALLY_ASSISTANT_MODE="assistant"
29
+ export WORK_ALLY_ASSISTANT_HOME="$(work_ally_assistant_registered_home "$WORK_ALLY_ASSISTANT_NAME")"
30
+ export WORK_ALLY_ASSISTANT_CODEX_HOME="$(work_ally_assistant_registered_codex_home "$WORK_ALLY_ASSISTANT_NAME")"
31
+
32
+ run_bridge_cli() {
33
+ env WORK_ALLY_ASSISTANT_MODE="${WORK_ALLY_ASSISTANT_MODE:-assistant}" WORK_ALLY_ASSISTANT_NAME="$WORK_ALLY_ASSISTANT_NAME" WORK_ALLY_ASSISTANT_HOME="${WORK_ALLY_ASSISTANT_HOME:-}" WORK_ALLY_ASSISTANT_CODEX_HOME="${WORK_ALLY_ASSISTANT_CODEX_HOME:-}" node "$WORK_ALLY_IMPLEMENTATION_DIR/bridge/src/server.ts" routine "$@"
34
+ }
35
+
36
+ case "$SUBCMD" in
37
+ list)
38
+ run_bridge_cli list
39
+ ;;
40
+ run)
41
+ [ $# -ge 1 ] || work_ally_die "Usage: $cmd_name routine run <routine-id>"
42
+ run_bridge_cli run "$@"
43
+ ;;
44
+ enable)
45
+ [ $# -ge 1 ] || work_ally_die "Usage: $cmd_name routine enable <routine-id>"
46
+ run_bridge_cli enable "$@"
47
+ ;;
48
+ disable)
49
+ [ $# -ge 1 ] || work_ally_die "Usage: $cmd_name routine disable <routine-id>"
50
+ run_bridge_cli disable "$@"
51
+ ;;
52
+ *)
53
+ work_ally_die "Unknown routine subcommand: $SUBCMD"
54
+ ;;
55
+ esac
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/../../lib/common.sh"
7
+ work_ally_init_context
8
+ if [ -z "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
9
+ WORK_ALLY_ASSISTANT_NAME=$(work_ally_resolve_assistant_name_from_args "$@" || true)
10
+ fi
11
+ if [ -n "${WORK_ALLY_ASSISTANT_NAME:-}" ]; then
12
+ work_ally_sync_workspace_root_from_assistant "$WORK_ALLY_ASSISTANT_NAME"
13
+ work_ally_hydrate_assistant_context "$WORK_ALLY_ASSISTANT_NAME"
14
+ fi
15
+ work_ally_ensure_state_dirs
16
+ work_ally_load_env
17
+ work_ally_load_assistant_state || true
18
+
19
+ [ -n "${WORK_ALLY_ASSISTANT_HOME:-}" ] || exit 0
20
+ interval=$(work_ally_assistant_autosave_interval)
21
+ work_ally_assistant_git_setup "$WORK_ALLY_ASSISTANT_HOME" "${WORK_ALLY_ASSISTANT_GIT_REMOTE:-}" || true
22
+
23
+ while :; do
24
+ sleep "$interval"
25
+ work_ally_assistant_git_checkpoint "$WORK_ALLY_ASSISTANT_HOME" "autosave" || true
26
+ done
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
5
+ "$SCRIPT_DIR/stop.sh" "$@"
6
+ "$SCRIPT_DIR/start.sh" "$@"